Hi,
newbie here, I am making my first little synth: osc, env, filter.
Now I added the DelayLine and it crackles.
Most probably the cpu is cooking.
How could I optimize this?
I already successfully implemented the mux, and the oled, but the oled also dragged the performance down (no sound).
Maybe the adc could be read more slowly, but I don´t know how.
Here is the code:
#include “daisysp.h”
#include <stdio.h>
#include <string.h>
#include “daisy_seed.h”
#include “dev/oled_ssd130x.h”
#include “dev/mpr121.h”
#define MAX_DELAY static_cast<size_t>(48000 * 0.75f)
using namespace daisysp;
using namespace daisy;
using MyOledDisplay = OledDisplay;
dsy_gpio ledR_1_pin, ledG_1_pin, ledB_1_pin;
uint16_t currTouched;
uint16_t lastTouched;
// Define the frequencies for the two octaves surrounding middle C
double scale[12] = {
// Octave below middle C
{130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94},
// Middle C and the octave above
{261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88},
// Octave above middle C
{523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77}};
DaisySeed hw;
MyOledDisplay display;
Mpr121I2C mpr121;
static Oscillator osc;
static Svf filt;
static Metro clock;
static Adsr env;
bool gate;
float envout;
float finalF;
float trig;
// Declare a DelayLine of MAX_DELAY number of floats.
static DelayLine<float, MAX_DELAY> del;
static void AudioCallback(AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size)
{
// Declare a DelayLine of MAX_DELAY number of floats.
float delout;
float feedback;
float sig;
float sigout;
for(size_t i = 0; i < size; i += 2)
{
del.SetDelay(hw.adc.GetMuxFloat(10, 1) * 20000 );
float fb = (hw.adc.GetMuxFloat(10, 2) * .99);
// Use envelope to control the amplitude of the oscillator.
envout = env.Process(trig);
osc.SetAmp(envout);
filt.Process(sig);
// Read from delay line
delout = del.Read();
// Calculate output and feedback
sig = osc.Process();
sigout = delout + filt.Low();
feedback = (delout * fb) + filt.Low();
// Write to the delay
del.Write(feedback);
// left out
out[i] = sigout;
// right out
out[i + 1] = sigout;
}
}
int main(void)
{
// initialize seed hardware and oscillator daisysp module
float sample_rate;
hw.Configure();
hw.Init(true);
hw.SetAudioBlockSize(32);
sample_rate = hw.AudioSampleRate();
osc.Init(sample_rate);
//init metro object
clock.Init(2, sample_rate);
//Set envelope parameters
env.Init(sample_rate);
env.SetTime(ADSR_SEG_ATTACK, .1);
env.SetTime(ADSR_SEG_DECAY, .5);
env.SetTime(ADSR_SEG_RELEASE, .5);
env.SetSustainLevel(0);
// Set parameters for oscillator
osc.SetWaveform(osc.WAVE_POLYBLEP_SAW);
osc.SetFreq(440);
osc.SetAmp(0.5);
// Initialize Filter, and set parameters.
filt.Init(sample_rate);
filt.SetFreq(500.0);
filt.SetRes(0.85);
filt.SetDrive(0.8);
del.Init();
// R 1 on pin 27
ledR_1_pin.pin = hw.GetPin(12);
ledR_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
ledR_1_pin.pull = DSY_GPIO_NOPULL;
dsy_gpio_init(&ledR_1_pin);
dsy_gpio_write(&ledR_1_pin, false);
// G 1 on pin 26
ledG_1_pin.pin = hw.GetPin(13);
ledG_1_pin.pull = DSY_GPIO_NOPULL;
ledG_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
dsy_gpio_init(&ledG_1_pin);
dsy_gpio_write(&ledG_1_pin, false);
// B 1 on pin 25
ledB_1_pin.pin = hw.GetPin(14);
ledB_1_pin.mode = DSY_GPIO_MODE_OUTPUT_PP;
ledB_1_pin.pull = DSY_GPIO_NOPULL;
dsy_gpio_init(&ledB_1_pin);
dsy_gpio_write(&ledB_1_pin, false);
/** Initialize the ADC with our configuration */
//hw.adc.Init(&adc_cfg, 1);
//Configure pin 21 as an ADC input. This is where we'll read the knob.
// Create an array of two AdcChannelConfig objects
const int num_adc_channels = 11;
AdcChannelConfig my_adc_config[num_adc_channels];
// Initialize the first one connected to A0
my_adc_config[0].InitSingle(hw.GetPin(21));
my_adc_config[1].InitSingle(hw.GetPin(20));
my_adc_config[2].InitSingle(hw.GetPin(19));
my_adc_config[3].InitSingle(hw.GetPin(18));
my_adc_config[4].InitSingle(hw.GetPin(17));
my_adc_config[5].InitSingle(hw.GetPin(16));
my_adc_config[6].InitSingle(hw.GetPin(15));
my_adc_config[7].InitSingle(hw.GetPin(22));
my_adc_config[8].InitSingle(hw.GetPin(23));
my_adc_config[9].InitSingle(hw.GetPin(24));
my_adc_config[10].InitMux(seed::A10, 8, seed::D0, seed::D1, seed::D2);
//Initialize the adc with the config we just made
hw.adc.Init(my_adc_config, num_adc_channels);
//Start reading values
hw.adc.Start();
// start callback
hw.StartAudio(AudioCallback);
// touch works
// Initialize MPR121 with I2C configuration
Mpr121I2C::Config mprConfig;
mprConfig.transport_config.periph = I2CHandle::Config::Peripheral::I2C_1;
mprConfig.transport_config.speed = I2CHandle::Config::Speed::I2C_400KHZ;
mprConfig.transport_config.scl = Pin(PORTB,8); // Replace with your SCL pin
mprConfig.transport_config.sda = Pin(PORTB,9); // Replace with your SDA pin
// Set additional MPR121 configuration if needed
mprConfig.touch_threshold = 12;
mprConfig.release_threshold = 6;
if(mpr121.Init(mprConfig) != Mpr121I2C::OK)
{
// Handle initialization error
while(1)
{
// Error handling code (blinking LED, etc.)
}
}
// Setup to print
hw.StartLog();
// oled
// Configure the Display
/*MyOledDisplay::Config disp_cfg;
disp_cfg.driver_config.transport_config.i2c_address = 0x3C;
disp_cfg.driver_config.transport_config.i2c_config.periph = I2CHandle::Config::Peripheral::I2C_1;
disp_cfg.driver_config.transport_config.i2c_config.speed = I2CHandle::Config::Speed::I2C_100KHZ;
disp_cfg.driver_config.transport_config.i2c_config.mode = I2CHandle::Config::Mode::I2C_MASTER;
disp_cfg.driver_config.transport_config.i2c_config.pin_config.scl = {DSY_GPIOB, 8};
disp_cfg.driver_config.transport_config.i2c_config.pin_config.sda = {DSY_GPIOB, 9};
// And Initialize
display.Init(disp_cfg);
float finalFO = 440;
int te = 1;
bool we = false;
//oled end
*/
// Touch Stuff
//bool test = false;
int step = 0;
int cnt = 0;
while(1) {
float baseF=hw.adc.GetFloat(0)*200;
// Read touch status
currTouched = mpr121.Touched();
// Process the touch status as needed
for(int i = 0; i < 12; i++)
{
if((currTouched & (1 << i)) && !(lastTouched& (1 << i)))
{
// Channel i is touched, print the channel number
hw.PrintLine("Channel %d touched", i);
osc.SetFreq(scale[0][i] + baseF);
trig = 1;
hw.SetLed(true);
dsy_gpio_write(&ledR_1_pin, true );
dsy_gpio_write(&ledG_1_pin, true );
dsy_gpio_write(&ledB_1_pin, true );
}
if(!(currTouched & (1 << i)) && (lastTouched& (1 << i)))
{
// Channel i is released, print the channel number
hw.PrintLine("Channel %d released", i);
trig = 0;
hw.SetLed(false);
//
dsy_gpio_write(&ledR_1_pin, false );
dsy_gpio_write(&ledG_1_pin, false );
dsy_gpio_write(&ledB_1_pin, false );
}
}
lastTouched = currTouched;
if (clock.Process()){
if(cnt == 0) {
gate = 1;
if (step == 2){
step=0;
}
else{
step++;
}
} else if(cnt == 3) {
gate = 0;
}
if (cnt < 4) {
cnt++;
} else {
cnt = 0;
}
}
/*if (step==0){
finalF = baseF + hw.adc.GetFloat(3);
}
else if (step==1){
finalF = baseF + hw.adc.GetFloat(4);
}
else if (step==2){
finalF = baseF + hw.adc.GetFloat(5);
}*/
if(finalF > 1.0) {
finalF = 1.0;
}
//OlED Stuff
/*if (finalF != finalFO) {
//display.Fill(false);
//display.SetCursor(10, 10);
//display.DrawRect(4, 4, 124, 60, true, false);
//display.WriteString(strbuff, Font_11x18, true);
//display.SetCursor(10, 32);
//display.WriteString("test2", Font_11x18, true);
//display.Update();
//oled
}*/
/*if (cnt==0) {
display.SetCursor(10, 10);
if (we == true) {
display.WriteString("1test", Font_11x18, true);
we = false;
} else {
display.WriteString("2test", Font_11x18, true);
we = true;
}
display.Update();
}
finalFO = finalF;*/
//osc.SetFreq(finalF * 1200 + 45);
float peak = hw.adc.GetFloat(9) * envout;
float Cut = hw.adc.GetFloat(1);
filt.SetFreq((Cut * Cut + peak) * 4500 + 45);
filt.SetRes(hw.adc.GetFloat(2) * 1.1f);
osc.SetWaveform(hw.adc.GetMuxFloat(10, 0)*4+4);
clock.SetFreq(4 * (hw.adc.GetFloat(6) * 1.9f + .1f));
//Set envelope parameters
env.SetTime(ADSR_SEG_ATTACK, hw.adc.GetFloat(7));
float dec = hw.adc.GetFloat(8);
env.SetTime(ADSR_SEG_DECAY, dec * dec);
env.SetTime(ADSR_SEG_RELEASE, dec * dec);
env.SetSustainLevel(trig);
}
}