Dan Allegre / 401_reverb

Dependencies:   mbed

Committer:
dallegre
Date:
Sat Jul 30 23:57:45 2016 +0000
Revision:
8:ef4dca8695d1
Parent:
7:c84086dce9ac
Child:
9:f42863126573
got it just about fast enough to run at 22khz.  see if you can make it more efficient or speed up the processor by configuration.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dallegre 0:c12e968e5b60 1 //delay dsp for stm32f401re nucleo board with openmusiclabs audio codec shield. Need to jumpter the i2c pins from the
dallegre 0:c12e968e5b60 2 //top right arduino headers on the nucleo board to the bottom left 2 pins on the codec shield. Bottom left i2c pins are
dallegre 0:c12e968e5b60 3 //not mbed enabled on the nucleo boards.
dallegre 0:c12e968e5b60 4 //Also need to install a 11.2896MHz crystal on nucleo board and connect the appropriate jumpers as explained in the nucleo
dallegre 0:c12e968e5b60 5 //user manual. Two 20pf capacitors are used with the crystal. The series resistors going from the crystal to the stm32 chip
dallegre 0:c12e968e5b60 6 //are just shorts.
dallegre 0:c12e968e5b60 7 //Preceed audio path with a 1/47 voltage divider and follow with a 47X inverting op amp to bring up to eurorack levels. Use DC
dallegre 0:c12e968e5b60 8 //blocking cap after the op amp.
dallegre 0:c12e968e5b60 9 //Note that this is setup for the left input only and drives both outputs. It is easy to modify the code for stereo effects
dallegre 0:c12e968e5b60 10 //and both inputs.
dallegre 0:c12e968e5b60 11
dallegre 0:c12e968e5b60 12 //June 2015..
dallegre 0:c12e968e5b60 13 //Added interpolation so it acts more like a bbd or tape delay. It is easy to switch between cosine and linear interpolation.
dallegre 0:c12e968e5b60 14 //Cubic interpolation might be a possibility if I can figure out how it works.
dallegre 0:c12e968e5b60 15 //Added a nice lowpass filter class. Might want to put the delay in a class like this for reverb work. Need to make an oscillator next.
dallegre 0:c12e968e5b60 16
dallegre 7:c84086dce9ac 17 #define DELAYLEN 2900 //24,000 is about as far as you can go in the ram.
dallegre 8:ef4dca8695d1 18 #define SAMPLINGFREQ 22 //roughly the smapling frequency in KHz. options are 22,29,44,88 for 22khz,29khz,etc..
dallegre 0:c12e968e5b60 19
dallegre 0:c12e968e5b60 20 #include "mbed.h"
dallegre 1:a4ce08417c60 21 #include "dsp.h"
dallegre 1:a4ce08417c60 22 #include "allpass.h"
dallegre 0:c12e968e5b60 23 #include "codec.h"
dallegre 2:1b50325e256f 24 #include "osc.h"
dallegre 0:c12e968e5b60 25
dallegre 0:c12e968e5b60 26 SPI spi(SPI_MOSI,SPI_MISO,SPI_SCK);
dallegre 0:c12e968e5b60 27 Ticker timer;
dallegre 0:c12e968e5b60 28 Ticker timer2;
dallegre 0:c12e968e5b60 29 AnalogIn analog_value(A1); //delay time pot
dallegre 0:c12e968e5b60 30 AnalogIn analog_value2(A0); //feedback amount pot
dallegre 0:c12e968e5b60 31 DigitalOut cs(D10);
dallegre 0:c12e968e5b60 32
dallegre 0:c12e968e5b60 33 int left_out = 0, right_out = 0, left_out_u = 0, right_out_u = 0, left_in = 0, right_in = 0,
dallegre 0:c12e968e5b60 34 index1 = 0, index2 = (DELAYLEN*0.99), index3 = (DELAYLEN*0.99);
dallegre 0:c12e968e5b60 35 uint16_t left_in_u = 0, meas = 0, measprev = 0;
dallegre 0:c12e968e5b60 36 float left_in_f = 0, feedback = 0, feedback2 = 0, feedback3 = 0, offset = 10.0,
dallegre 7:c84086dce9ac 37 meas2f = 0.5, damping = 0, damping2 = 0, damping3 = 0, modL = 0, modL2 = 0, modL3 = 0, modL4, modR = 0, modR2 = 0, modR3 = 0, modR4,
dallegre 8:ef4dca8695d1 38 modLos = 0, modL2os = 0, modL3os = 0, modL4os = 0, modRos = 0, modR2os = 0, modR3os = 0, modR4os = 0,
dallegre 8:ef4dca8695d1 39 upperLim, lowerLim,
dallegre 3:f8bc3ac22ffd 40 left_out_f = 0, right_out_f = 0;
dallegre 7:c84086dce9ac 41 float left_out_2 = 0, right_out_2 = 0, left_out_3 = 0, right_out_3 = 0, left_out_4 = 0, right_out_4 = 0, loopfb = 0, loopfb2 = 0;
dallegre 0:c12e968e5b60 42 float audioFeedbackRight,audioFeedbackLeft;
dallegre 0:c12e968e5b60 43
dallegre 0:c12e968e5b60 44 float LPdampingFreq = 11000, HPdampingFreq = 100; //some parameters you might want to adjust.
dallegre 0:c12e968e5b60 45 int LPdampingPoles = 2, HPdampingPoles = 0; //I don't think the highpass is quite working.
dallegre 0:c12e968e5b60 46
dallegre 0:c12e968e5b60 47 OnePoleLp feedbackFilter;
dallegre 0:c12e968e5b60 48 OnePoleLp lengthFilter;
dallegre 7:c84086dce9ac 49 OnePoleLp dampingFilter;
dallegre 1:a4ce08417c60 50 AllPass delayLeft;
dallegre 3:f8bc3ac22ffd 51 AllPass delayLeft2;
dallegre 3:f8bc3ac22ffd 52 AllPass delayLeft3;
dallegre 7:c84086dce9ac 53 AllPass delayLeft4;
dallegre 1:a4ce08417c60 54 AllPass delayRight;
dallegre 2:1b50325e256f 55 AllPass delayRight2;
dallegre 3:f8bc3ac22ffd 56 AllPass delayRight3;
dallegre 7:c84086dce9ac 57 AllPass delayRight4;
dallegre 3:f8bc3ac22ffd 58 gsOsc OscillatorL;
dallegre 3:f8bc3ac22ffd 59 gsOsc OscillatorL2;
dallegre 3:f8bc3ac22ffd 60 gsOsc OscillatorL3;
dallegre 7:c84086dce9ac 61 gsOsc OscillatorL4;
dallegre 3:f8bc3ac22ffd 62 gsOsc OscillatorR;
dallegre 3:f8bc3ac22ffd 63 gsOsc OscillatorR2;
dallegre 3:f8bc3ac22ffd 64 gsOsc OscillatorR3;
dallegre 7:c84086dce9ac 65 gsOsc OscillatorR4;
dallegre 0:c12e968e5b60 66
dallegre 0:c12e968e5b60 67 void I2S_send(void){
dallegre 0:c12e968e5b60 68 cs.write(0); //0 for left output
dallegre 0:c12e968e5b60 69 left_in = spi.write(left_out);
dallegre 0:c12e968e5b60 70 cs.write(1); //1 for right output
dallegre 0:c12e968e5b60 71 right_in = spi.write(right_out);
dallegre 0:c12e968e5b60 72
dallegre 0:c12e968e5b60 73 left_in_f = intToFloat(left_in);
dallegre 0:c12e968e5b60 74
dallegre 0:c12e968e5b60 75 /////////////////////////////////////////dsp part//////////////////////////////////////////////////////////////////////
dallegre 0:c12e968e5b60 76
dallegre 8:ef4dca8695d1 77 ///*
dallegre 0:c12e968e5b60 78 //process control signals
dallegre 0:c12e968e5b60 79 feedback2 = feedbackFilter.process(feedback);
dallegre 8:ef4dca8695d1 80 //maybe move this to the dac sampling interrupt. seems like there was a reason it's here though.
dallegre 8:ef4dca8695d1 81 //damping2 = lengthFilter.process(damping);
dallegre 8:ef4dca8695d1 82 //damping3 = lengthFilter.process(damping2);
dallegre 8:ef4dca8695d1 83 //damping3 *= (5000); //make about 10k the max cutoff for damping
dallegre 8:ef4dca8695d1 84
dallegre 8:ef4dca8695d1 85 //dampingFilter.setFc(damping3/(SAMPLINGFREQ*1000));
dallegre 0:c12e968e5b60 86
dallegre 2:1b50325e256f 87 //process audio. probably calculate these coefficients elsewhere so you don't do the multiply all the time.
dallegre 2:1b50325e256f 88 //left delay mod
dallegre 8:ef4dca8695d1 89 modL = modLos + OscillatorL.process(1);
dallegre 8:ef4dca8695d1 90 modL2 = modL2os + OscillatorL2.process(1);
dallegre 8:ef4dca8695d1 91 modL3 = modL3os + OscillatorL3.process(1);
dallegre 8:ef4dca8695d1 92 modL4 = modL4os + OscillatorL3.process(0);
dallegre 2:1b50325e256f 93 //right delay mod
dallegre 8:ef4dca8695d1 94 modR = modRos + OscillatorR.process(0);
dallegre 8:ef4dca8695d1 95 modR2 = modR2os + OscillatorR2.process(0);
dallegre 8:ef4dca8695d1 96 modR3 = modR3os + OscillatorR3.process(1);
dallegre 8:ef4dca8695d1 97 modR4 = modR4os + OscillatorR4.process(1);
dallegre 8:ef4dca8695d1 98
dallegre 8:ef4dca8695d1 99 if(modL > upperLim)
dallegre 8:ef4dca8695d1 100 modL = upperLim;
dallegre 8:ef4dca8695d1 101 if(modL < lowerLim)
dallegre 8:ef4dca8695d1 102 modL = lowerLim;
dallegre 8:ef4dca8695d1 103 if(modL2 > upperLim)
dallegre 8:ef4dca8695d1 104 modL2 = upperLim;
dallegre 8:ef4dca8695d1 105 if(modL2 < lowerLim)
dallegre 8:ef4dca8695d1 106 modL2 = lowerLim;
dallegre 8:ef4dca8695d1 107 if(modL3 > upperLim)
dallegre 8:ef4dca8695d1 108 modL3 = upperLim;
dallegre 8:ef4dca8695d1 109 if(modL3 < lowerLim)
dallegre 8:ef4dca8695d1 110 modL3 = lowerLim;
dallegre 8:ef4dca8695d1 111 if(modL4 > upperLim)
dallegre 8:ef4dca8695d1 112 modL4 = upperLim;
dallegre 8:ef4dca8695d1 113 if(modL4 < lowerLim)
dallegre 8:ef4dca8695d1 114 modL4 = lowerLim;
dallegre 8:ef4dca8695d1 115 if(modR > upperLim)
dallegre 8:ef4dca8695d1 116 modR = upperLim;
dallegre 8:ef4dca8695d1 117 if(modR < lowerLim)
dallegre 8:ef4dca8695d1 118 modR = lowerLim;
dallegre 8:ef4dca8695d1 119 if(modR2 > upperLim)
dallegre 8:ef4dca8695d1 120 modR2 = upperLim;
dallegre 8:ef4dca8695d1 121 if(modR2 < lowerLim)
dallegre 8:ef4dca8695d1 122 modR2 = lowerLim;
dallegre 8:ef4dca8695d1 123 if(modR3 > upperLim)
dallegre 8:ef4dca8695d1 124 modR3 = upperLim;
dallegre 8:ef4dca8695d1 125 if(modR3 < lowerLim)
dallegre 8:ef4dca8695d1 126 modR3 = lowerLim;
dallegre 8:ef4dca8695d1 127 if(modR4 > upperLim)
dallegre 8:ef4dca8695d1 128 modR4 = upperLim;
dallegre 8:ef4dca8695d1 129 if(modR4 < lowerLim)
dallegre 8:ef4dca8695d1 130 modR4 = lowerLim;
dallegre 8:ef4dca8695d1 131
dallegre 7:c84086dce9ac 132 left_out_2 = delayLeft2.process(satAdd(left_in_f,loopfb),.3,modL);
dallegre 7:c84086dce9ac 133 left_out_3 = delayLeft3.process(left_out_2,.4,modL2);
dallegre 7:c84086dce9ac 134 left_out_4 = delayLeft4.process(left_out_3,.4,modL3);
dallegre 7:c84086dce9ac 135 left_out_f = delayLeft.process(left_out_4,.4,modL4);
dallegre 7:c84086dce9ac 136 right_out_2 = delayRight2.process(satAdd(left_in_f,loopfb2),.3,modR);
dallegre 7:c84086dce9ac 137 right_out_3 = delayRight3.process(right_out_2,.4,modR2);
dallegre 7:c84086dce9ac 138 right_out_4 = delayRight4.process(right_out_3,.4,modR3);
dallegre 7:c84086dce9ac 139 right_out_f = delayRight.process(right_out_4,.4,modR4);
dallegre 7:c84086dce9ac 140
dallegre 8:ef4dca8695d1 141 loopfb2 = left_out_f*feedback2; //swizzle the feedbacks left to right
dallegre 8:ef4dca8695d1 142 loopfb = right_out_f*feedback2;
dallegre 8:ef4dca8695d1 143
dallegre 8:ef4dca8695d1 144 //apply damping
dallegre 7:c84086dce9ac 145 //loopfb = dampingFilter.process(loopfb);
dallegre 7:c84086dce9ac 146 //loopfb2 = dampingFilter.process(loopfb2);
dallegre 8:ef4dca8695d1 147 //*/
dallegre 8:ef4dca8695d1 148 //left_out_f = left_in_f;
dallegre 8:ef4dca8695d1 149 //right_out_f = left_in_f;
dallegre 8:ef4dca8695d1 150
dallegre 6:df635006ee1c 151 left_out_u = left_out_f;
dallegre 6:df635006ee1c 152 right_out_u = right_out_f;
dallegre 0:c12e968e5b60 153
dallegre 0:c12e968e5b60 154 /////////////////////////////////////////end of dsp part/////////////////////////////////////////////////////////////////
dallegre 0:c12e968e5b60 155
dallegre 0:c12e968e5b60 156 left_out = unsignedToSigned(left_out_u);
dallegre 0:c12e968e5b60 157 right_out = unsignedToSigned(right_out_u);
dallegre 0:c12e968e5b60 158
dallegre 0:c12e968e5b60 159 }
dallegre 0:c12e968e5b60 160
dallegre 0:c12e968e5b60 161 void analog_read(void){
dallegre 0:c12e968e5b60 162 //this is the stuff for the feedback amount pot
dallegre 0:c12e968e5b60 163 meas2f = analog_value2.read_u16(); //converts unint16 value to float
dallegre 0:c12e968e5b60 164 feedback = meas2f/4100; //now you have a value between 0 and 1 that will control the feedback amount.
dallegre 7:c84086dce9ac 165 feedback *= feedback;
dallegre 0:c12e968e5b60 166
dallegre 0:c12e968e5b60 167 //this is the stuff for the delay time pot
dallegre 0:c12e968e5b60 168 meas = 4096 - analog_value.read_u16(); //values go from 1 to 4095
dallegre 0:c12e968e5b60 169 //if(abs(meas - measprev) > 5){
dallegre 0:c12e968e5b60 170 measprev = meas;
dallegre 7:c84086dce9ac 171 damping = meas;
dallegre 7:c84086dce9ac 172 damping /= 4200; //this number took some tweaking.
dallegre 7:c84086dce9ac 173 damping *= damping;
dallegre 0:c12e968e5b60 174 //}
dallegre 0:c12e968e5b60 175 }
dallegre 0:c12e968e5b60 176
dallegre 0:c12e968e5b60 177 int main(){
dallegre 0:c12e968e5b60 178
dallegre 0:c12e968e5b60 179 //set up baud rate for 11.2MHz crystal
dallegre 0:c12e968e5b60 180 pc.baud(.7*9600*2);
dallegre 0:c12e968e5b60 181 wait(.1);
dallegre 0:c12e968e5b60 182
dallegre 0:c12e968e5b60 183 //do I2C transfter to initialize codec
dallegre 0:c12e968e5b60 184 codecInit();
dallegre 0:c12e968e5b60 185
dallegre 0:c12e968e5b60 186 //initialize fixed filters
dallegre 0:c12e968e5b60 187 double feedbackCutoff = 10.0/(SAMPLINGFREQ*1000); //adjust these cutoffs according to taste.
dallegre 0:c12e968e5b60 188 feedbackFilter.setFc(feedbackCutoff);
dallegre 0:c12e968e5b60 189 double lengthCutoff = 3.0/(SAMPLINGFREQ*1000);
dallegre 0:c12e968e5b60 190 lengthFilter.setFc(lengthCutoff);
dallegre 8:ef4dca8695d1 191
dallegre 8:ef4dca8695d1 192 //initize oscillators and mod offsets
dallegre 8:ef4dca8695d1 193 modLos = DELAYLEN*.74;
dallegre 8:ef4dca8695d1 194 modL2os = DELAYLEN*.43;
dallegre 8:ef4dca8695d1 195 modL3os = DELAYLEN*.33;
dallegre 8:ef4dca8695d1 196 modL4os = DELAYLEN*.37;
dallegre 8:ef4dca8695d1 197 OscillatorL.setF(.53,DELAYLEN/66);
dallegre 8:ef4dca8695d1 198 OscillatorL2.setF(.03,DELAYLEN/65);
dallegre 8:ef4dca8695d1 199 OscillatorL3.setF(.02,DELAYLEN/78);
dallegre 8:ef4dca8695d1 200 OscillatorL4.setF(.023,DELAYLEN/78);
dallegre 8:ef4dca8695d1 201 //right delay mod
dallegre 8:ef4dca8695d1 202 modRos = DELAYLEN*.75;
dallegre 8:ef4dca8695d1 203 modR2os = DELAYLEN*.49;
dallegre 8:ef4dca8695d1 204 modR3os = DELAYLEN*.33;
dallegre 8:ef4dca8695d1 205 modR4os = DELAYLEN*.37;
dallegre 8:ef4dca8695d1 206 OscillatorR.setF(.51,DELAYLEN/69);
dallegre 8:ef4dca8695d1 207 OscillatorR2.setF(.03,DELAYLEN/67);
dallegre 8:ef4dca8695d1 208 OscillatorR3.setF(.02,DELAYLEN/78);
dallegre 8:ef4dca8695d1 209 OscillatorR4.setF(.023,DELAYLEN/78);
dallegre 8:ef4dca8695d1 210 upperLim = .9*DELAYLEN;
dallegre 8:ef4dca8695d1 211 lowerLim = .05*DELAYLEN;
dallegre 0:c12e968e5b60 212
dallegre 0:c12e968e5b60 213 //set up I2S
dallegre 0:c12e968e5b60 214 spi.frequency(8e6*2); //8MHz spi. This is fast enough for 88KHz 16 bit sampling.
dallegre 0:c12e968e5b60 215 spi.format(16,0); //16 bit. clock polarity 0, phase 0.
dallegre 0:c12e968e5b60 216 wait(.1);
dallegre 0:c12e968e5b60 217
dallegre 0:c12e968e5b60 218 //audio rate timers. 29 and 44 are not very good. Might want to use an external clock for the Nucleo.
dallegre 0:c12e968e5b60 219 if(SAMPLINGFREQ == 22)
dallegre 0:c12e968e5b60 220 timer.attach(&I2S_send,32e-6); //22KHz sampling. 12.2008MHz/512 = 21.876KHz. 1/(21.876KHz(8/11.2008)) = 64e-6 Sec and / by 2 because the codec divides by to before sending the osc out.
dallegre 0:c12e968e5b60 221 if(SAMPLINGFREQ == 29)
dallegre 0:c12e968e5b60 222 timer.attach(&I2S_send,24e-6); //29.168KHz sampling. 11.2008MHz/384 = 19.168KHz. 1/(29.168KHz(8/11.2008)) = 48.0012e-6 Sec and / by 2 because the codec divides by to before sending the osc out.
dallegre 0:c12e968e5b60 223 if(SAMPLINGFREQ == 44)
dallegre 0:c12e968e5b60 224 timer.attach(&I2S_send,16.0e-6); //44.1KHz sampling. almost exactly 32e-6 and then divide by 2. Doesn't sound right yet.
dallegre 0:c12e968e5b60 225 if(SAMPLINGFREQ == 88)
dallegre 0:c12e968e5b60 226 timer.attach(&I2S_send,8e-6); //88KHz sampling. Need to calculate.
dallegre 0:c12e968e5b60 227
dallegre 0:c12e968e5b60 228 //control signal timer
dallegre 0:c12e968e5b60 229 timer2.attach(&analog_read,25e-3);
dallegre 0:c12e968e5b60 230
dallegre 0:c12e968e5b60 231 //go!
dallegre 0:c12e968e5b60 232 while(1){}
dallegre 0:c12e968e5b60 233 }