I’d like to make an attempt at implementing a FFT pitch shift effect (as opposed to the SOLA implementation used in the current DaisySP library).
I came across this FFT pitch shifter implementation from Zynaptiq that I think could work on Daisy if I could use more the more efficient FFT functions available via arm_math.h (i.e. arm_cfft_radix4_f32()) to adapt it.
Is there any ETA on when the CMSIS libarary will be implemented for Daisy? It seems like the idea has been reviewed to some extent - as the current iteration of the pitchshifter in DaisySP includes arm_math.h, but doesn’t seem to compile if I force it to use arm_sin_f32() - I just get the “arm_math.h” is “undefined” error.
It also looks like libdaisy includes CMSIS and arm_math.h in the driver path:
…DaisyExamples\libDaisy\Drivers\CMSIS\DSP\Include\
It’s just not part of the current build. Is this something that’s on the roadmap for Daisy in the near future?
But it’s source is already included in libDaisy. They probably haven’t added those files to C_SRC variable, so it doesn’t get built. But you should be able to solve this in your project.
Also, CMSIS based FFT was usable on STM32F4 for running FFT and RFFT on a stereo channel. I’d expect it to manage even 4 channels in Daisy.
I initially thought it would be just as easy as including:
/Drivers/CMSIS/DSP/Include
into the Make files for libDaisy and libDaisy core with the #define variable for cortex-m7 MCU (“ARM_MATH_CM7”) - but after a lot of tinkering - it seems that there is something I’m missing.
I can rebuild the libraries without errors and I even get it to stop throwing the “arm_math.h” is “undefined” error…but in it’s place I get “undefined reference to ‘arm_sin_f32’” (or whichever arm_math.h function I use).
Has anyone successfully rebuilt the libraries including the CMSIS DSP headers and gotten something to successfully compile using one of the arm_math.h functions? If so, can you point me to where I may have gone wrong?
It seems that I’ve found a work-around in the meantime.
I stumbled on this stack overflow question and while the poster’s specific issue is about a
stm32f4 device, his issue is the same.
The proposed workaround is to grab the applicable *.c source files from:
…/DaisyExamples/libDaisy/Drivers/CMSIS/DSP/Source/…
and include them in the project directory and the Make file like: # Sources CPP_SOURCES = ex_pitchshifter.cpp C_SOURCES = arm_sin_f32.c arm_common_tables.c
I am able to get the pitchshifter example to compile this way and it runs on the hardware using using the arm_math.h functions exactly as it runs without them.
I imagine there is a better way to define where all of the CMSIS source files are, so I don’t have to include them one-by-one, but the make file already includes: # Library Locations LIBDAISY_DIR ?= ../../../libdaisy
[edit] This is not the answer.
So, I’m guessing that: CMSIS_DIR ?= ../../../libDaisy/Drivers/CMSIS/DSP/Source/
Isn’t the answer (though, I might give this a go now - just to check).
Long term, would love to just be able to use the functions without the workaround - let me know if anyone has a better solution.
I’ve been trying to get FFTS working as well. Using the additions to the makefile that @fredyeah suggested, it’s linking the .c files. However, it seems one of the files required for arm_rfft_fast_f32 is arm_bitreversal2.S.
Since this is an assembly file, the makefile doesn’t seem to have a rule for passing it to the compiler. I’ve tried several things, but I can’t seem to get it to work. Does anyone know how to set up the makefile to get this to work? This is the first time I’ve ever used makefiles and I’m finding it a bit confusing.
Or if anyone knows of any open source projects using FFTs on the Daisy, that would help immensely. I’ve not been able to find any code using FFTs to use as a model.
I haven’t done it with wildcarding, but there are three variables that need to be edited/set to work add the CMSIS files.
I was only using a few things when I was experimenting so the C_SOURCES list is fairly short.
However, as many files as needed can be added manually. It should also be able to be set with a wildcard similar to above.
This can sneak by until you hit the compiler error:
arm-none-eabi-cpp is the ‘C preprocessor’ - it handles expansion of macros like #if, #ifdef, #include, etc. It’s not just for C, also useful for c++, assembler and anything else that needs this type of macro expansion.
The point is that .S files might have macros that need preprocessing, and .s files don’t. doesn’t include a rule for transforming a .S file to a .o file.
There are various ways to get this to build, but I haven’t figured out a good one which doesn’t involve hacking DaisyExamples/libDaisy/core/Makefile .
how can I prune my code, which is just doing an FFT->iFFT and nothing else ?
#include "daisy_seed.h"
#include "daisysp.h"
#include "arm_math.h"
// Use the daisy namespace to prevent having to type
// daisy:: before all libdaisy functions
using namespace daisy;
using namespace daisysp;
// Declare a DaisySeed object called hardware
DaisySeed hardware;
Oscillator osc;
AdEnv env;
arm_rfft_fast_instance_f32* fftInstance;
float32_t *fftBuffer;
void AudioCallback(AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size)
{
float osc_out;
//Fill the block with samples
for(size_t i = 0; i < size; i += 2)
{
osc_out = osc.Process();
//Set the left and right outputs
out[i] = osc_out;
// out[i + 1] = osc_out;
out[i+1] = in[i+1];
arm_rfft_fast_f32(fftInstance,(float32_t*)&in[0],fftBuffer,0);
arm_rfft_fast_f32(fftInstance,fftBuffer,(float32_t*)&out[0],1);
}
}
int main(void)
{
// Declare a variable to store the state we want to set for the LED.
bool led_state;
led_state = true;
// Configure and Initialize the Daisy Seed
// These are separate to allow reconfiguration of any of the internal
// components before initialization.
hardware.Configure();
hardware.Init();
hardware.SetAudioBlockSize(4);
//How many samples we'll output per second
float samplerate = hardware.AudioSampleRate();
fftInstance = new arm_rfft_fast_instance_f32;
arm_status status = arm_rfft_fast_init_f32(fftInstance, hardware.AudioBlockSize());
fftBuffer = new float32_t[hardware.AudioBlockSize()];
//Set up oscillator
osc.Init(samplerate);
osc.SetWaveform(osc.WAVE_SIN);
osc.SetAmp(1.f);
osc.SetFreq(440);
hardware.StartAudio(AudioCallback);
// Loop forever
for(;;)
{
// Set the onboard LED
hardware.SetLed(led_state);
// Toggle the LED state for the next time around.
led_state = !led_state;
// Wait 500ms
System::Delay(500);
}
}
The cause of that error is the result of objects being too big to fit in the data section. You can try moving some of the stuff to SDRAM.
Our guess is that the fftInstance is the really big thing that should be moved.
So, arm_rfft_fast_instance_f32 DSY_SDRAM_BSS fftInstance; to move that object to the SDRAM.
Also, new is not typically used in embedded in our experience and will require some refactoring to use the SDRAM. Therefore, everywhere you reference it needs to be changed to &fftInstance.
I’m still struggling to fit this on my patch.init(), anyone had sucess here? In this minimal example (that doesn’t make sense, just trying to compile), both fft instance and buffer are on SDRAM_BSS but still no joy - any ideas?
/Applications/ArmGNUToolchain/12.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld: build/spectral.elf section `.text' will not fit in region `FLASH'
/Applications/ArmGNUToolchain/12.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld: region `FLASH' overflowed by 68868 bytes
/Applications/ArmGNUToolchain/12.3.rel1/arm-none-eabi/bin/../lib/gcc/arm-none-eabi/12.3.1/../../../../arm-none-eabi/bin/ld: warning: build/spectral.elf has a LOAD segment with RWX permissions
Memory region Used Size Region Size %age Used
FLASH: 199940 B 128 KB 152.54%
DTCMRAM: 0 GB 128 KB 0.00%
SRAM: 13864 B 512 KB 2.64%
RAM_D2: 16896 B 288 KB 5.73%