FFT / iFFT?

Took me awhile to understand how C++ build systems work, but the gist is the “ordinary” way to create a C++ executable is to write some code in source.cpp, point your terminal to the directory where your source file lives, and run g++ source.cpp. That command g++ invokes the GNU C++ compiler, which eats source.cpp and by default spits out an executable file called a.out. If you want to modify some parameters of the compilation – for example, you want the name of the executable to be different, or you want to include other files that live in a different folder – you might instead run:

g++ source.cpp -o myexecutable -I /some/other/dir/

There are a ton of options (or “flags”) you can pass to the compiler, which will modify where it looks for files, what it does with those files, what kinds of optimizations it performs on your code, etc. As your project becomes more complex you often have to use lots and lots of flags. A Makefile is a human-readable way of preparing those flags – it’s a bit like a scripting language that sets up and performs the compilation. Makefiles can include other Makefiles, branch according to conditions, define and modify variables, etc.

The Makefile in the example above gives a name to the output executable, lists the C++ source files, indicates the location of the DaisySP and libDaisy directories, sets the C++ standard used by the compiler (GNU C++17) and optimization level, and then includes the template Makefile supplied by Electrosmith in libDaisy/core/Makefile, where all the actual compilation commands live.

1 Like

A Makefile is so much more than a convenient way to put together compiler options.

Thanks for explaining this so thoroughly. As I understand it, this is something like what Arduino handles for the user?

Here’s the follow up question: do I have to (bite off a big learning curve and) advance from using Arduino if I want to be able to use libDaisy, or is there an Arduino way to do it?

I already have a busy career as a mechanical engineer, so I’m not really trying to learn too much for this one small project.

Yeah, exactly – the Arduino IDE gives you a GUI for downloading libraries, and then behind the scenes generates all the build code to compile / link your application to those libraries.

Since the Arduino language is a simplified version of C++, moving from Arduino / DaisyDuino to C++ / libDaisy shouldn’t actually be too difficult. I’d highly encourage looking through the projects in DaisyExamples. You’ll find most of the makefiles are identical (other than some straightforward modifications); the example projects also follow a template analogous to the Arduino sketch format, where there’s some initialization, the audio callback gets started, and then there’s some main loop that deals with processing non-audio information.

Happy to help if you get stuck!

1 Like

Much appreciated, I’ll put on my big person pants and give it a go.

I think it’s important to understand that ‘the Arduino language’ IS C++. Underneath the Arduino IDE, the code is compiled by a C++ compiler. The syntax and semantics are C++, the language isn’t simplified. It’s the build process that’s simplified, Arduino IDE creates some new conventions, and hides a lot of details.

https://www.idogendel.com/en/archives/19#comment-2809

thanks for the very interesting repo, loved the idea of a stripped-down version.

I am having some troubles getting any output though. The code compiles and flashes to daisy just fine, but there is no output at all. I am feeding it a mono line level signal in audio in pin 2 and outputting to audio out pin 2.

Would you have any suggestion?

Thanks!

Nicolas

Do you really mean you’re trying to get audio in and out on the same pin, or is that a typo?

Not exactly :slight_smile:

I was getting signal in from the AUDIO INPUT PIN 2 and signal out from the AUDIO OUTPUT PIN 2. But in any case the problem was that it does not read from the second input channel (to which I was connected), I just tried to connect to the first input channel and it works now. Is it meant to be mono?

Sorry if the issue was silly, I know how to use daisy well only with pd/max… still learning!

Yes, mono. Input on 1, output is duplicated on both output channels.

As programmed, the effect runs in mono. If you wanted it to be stereo (to process the two input channels separately) you’d need a second STFT object, which would double the memory and processing load of the program.

Thanks so much, this example has been great to get up and running with on my patch.init()! I’m starting to look at taking FFTs of longer samples (3-6sec, depending on sample rate), and have looked at the following options:

STFT

There are clearly limitations for SRAM that mean you can’t easily allocate buffers for longer than ~1/2 second. (additionally, ShyFFT stops working on buffers larger than 2^16). So I tried just moving the example @alo.bu shared (modified for patch.init()) from SRAM to SDRAM, but I am getting pretty garbled results out. I interpret this as maybe read/write speeds aren’t sufficients for the STFT processing? Or am I doing something silly? Example below just does passthough “processing” in fourier space, and works with SRAM but has issues with SDRAM.

FFT

I’ve also written code to just take a larger buffer put it on SDRAM using DSY_SDRAM_BSS, and Fourier Transform that. This works with the ShyFFT code (up to the 2^16 buffer limit mentioned) but understandably the audio thread locks up for a 1/10th of a sec or so doing such a large FFT. Is there some way to distribute the FFT processing over the several blocks, as it’s way too “bursty” at the moment? My initial thinking to look at STFT above was for just this (to avoid the burstiness).

tldlr; how should I approach taking regular/repeated FFTs on buffer sizes that appear to be too long for SRAM?

Any help greatly appreciated!

Glad the example has been helpful! I also tried moving the buffers to SDRAM when I was building this and got crashes / garbled results - I think it’s a read / write speed issue that hangs the audio thread.

A better version of this class would run the FFT / frequency domain callback / iFFT outside the audio thread so that the spectral processing can take place while the overlapping buffers are being windowed / filled (which is fairly inexpensive).

This would require a bit of modification of the Fourier class, which currently calls the FFT / callback / iFFT (forward, middle and back) whenever a buffer fills up. Instead, the class should flip a flag, which would get handled by the main loop, to call those methods. I might have a chance to play around with it later today.

1 Like