Recently I discovered Arduino Audio Tools that is a super cool library that unify the audio into arduino Streams. Basically buffers that can execute write and read.
Also it implements the drivers for I2S and Faust, that is exactly what I use. And works like a charm. Here is an example of a broken autotune, that doesnt work perfectly:
#define USE_MEMORY_MANAGER
#include <Arduino.h>
#include "AudioTools.h"
#include "AudioControlSGTL5000.h"
#include "AudioTools/AudioLibs/AudioRealFFT.h"
#include "AudioTools/AudioLibs/AudioFaust.h"
#include "Pitcher.h"
// I2S_INPUT -> SPLITTER -> FFT
// -> PitchShift -> I2S_OUTPUT
#define I2S_BCLK 3 // Bit clock
#define I2S_LRC 6 // Word select / LR clock
#define I2S_DOUT 4 // Data out
#define I2S_DIN 5 // Data in (not used here)
#define I2S_MCLK 0 // Master clock (optional)
#define SAMPLE_RATE 44100
#define BIT_DEPTH 16
AudioControlSGTL5000 audio;
// Create i2S stream as audio sink and source
I2SStream i2s_stream;
MultiOutput splitter;
AudioRealFFT fft; // or AudioKissFFT
FaustStream<mydsp> faust(i2s_stream);
StreamCopy copier(splitter, i2s_stream); // (To, From)
// Audio info: sample rate, channels, bit depth
AudioInfo info(SAMPLE_RATE, 2, BIT_DEPTH);
// display fft result
void fftResult(AudioFFTBase &fft){
float diff;
auto result = fft.result();
if (result.magnitude>100){
Serial.print(result.frequency);
Serial.print(" ");
Serial.print(result.magnitude);
Serial.print(" => ");
Serial.print(result.frequencyAsNote(diff));
Serial.print( " diff: ");
Serial.println(diff);
faust.setLabelValue("shift_semitones", - diff / 10);
}
}
void setup() {
Serial.begin(115200);
// I2S config
auto cfg_i2s_in = i2s_stream.defaultConfig(RXTX_MODE);
cfg_i2s_in.sample_rate = SAMPLE_RATE;
cfg_i2s_in.bits_per_sample = BIT_DEPTH;
cfg_i2s_in.channels = 2;
cfg_i2s_in.pin_bck = I2S_BCLK;
cfg_i2s_in.pin_ws = I2S_LRC;
cfg_i2s_in.pin_data = I2S_DOUT;
cfg_i2s_in.pin_data_rx = I2S_DIN;
cfg_i2s_in.pin_mck = I2S_MCLK;
cfg_i2s_in.use_apll = true;
i2s_stream.begin(cfg_i2s_in);
// Setup Faust
auto faust_cfg = faust.defaultConfig();
faust.begin(faust_cfg);
faust.setLabelValue("shift_semitones", 1);
// setup multi output
splitter.add(faust);
splitter.add(fft);
if(!audio.enable()){
Serial.println("Something wrong happened");
}
audio.volume(0.5);
// Setup FFT
auto tcfg = fft.defaultConfig();
tcfg.length = 8192;
tcfg.channels = 2;
tcfg.sample_rate = SAMPLE_RATE;
tcfg.bits_per_sample = BIT_DEPTH;
tcfg.callback = &fftResult;
fft.begin(tcfg);
}
void loop() {
// Generate and write audio frames to I2S
copier.copy();
}
Fixing the script
The error is strange. Seems that fft gives strange readings when applying modifications to the Faust. It seams that the output affects the input, buuuuut checking the code, there is no possibility of this.
- Most probably there are not enought resources to perform a FFT while modifying values of Faust
- Or…. I am callying modifyin Faust while being in a callback, which can affect the FFT
- Soooo…. The solution would be to divide the logic in two cores, and one modify the other