Dan Allegre / 401_reverb

Dependencies:   mbed

Committer:
dallegre
Date:
Sat Jul 30 06:04:21 2016 +0000
Revision:
2:1b50325e256f
Parent:
1:a4ce08417c60
Child:
3:f8bc3ac22ffd
pretty much got a working reverb.  needs some work still though..

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 2:1b50325e256f 17 #define DELAYLEN 3900 //24,000 is about as far as you can go in the ram.
dallegre 0:c12e968e5b60 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 2:1b50325e256f 37 meas2f = 0.5, measf = 0, measf2 = 0, measf3 = 0, measf3b = 0, measf3c = 0, measf3d = 0, left_out_f = 0, right_out_f = 0;
dallegre 2:1b50325e256f 38 float left_out_2 = 0, right_out_2 = 0, loopfb = 0, loopfb2 = 0;
dallegre 0:c12e968e5b60 39 float audioFeedbackRight,audioFeedbackLeft;
dallegre 0:c12e968e5b60 40
dallegre 0:c12e968e5b60 41 float LPdampingFreq = 11000, HPdampingFreq = 100; //some parameters you might want to adjust.
dallegre 0:c12e968e5b60 42 int LPdampingPoles = 2, HPdampingPoles = 0; //I don't think the highpass is quite working.
dallegre 0:c12e968e5b60 43
dallegre 0:c12e968e5b60 44 OnePoleLp audioFilter; //might use this as a mor thorough DC offset removal tool. Not yet implemented.
dallegre 0:c12e968e5b60 45 OnePoleHp audioFilterHP;
dallegre 0:c12e968e5b60 46 OnePoleLp feedbackFilter;
dallegre 0:c12e968e5b60 47 OnePoleLp lengthFilter;
dallegre 1:a4ce08417c60 48 AllPass delayLeft;
dallegre 1:a4ce08417c60 49 AllPass delayRight;
dallegre 2:1b50325e256f 50 AllPass delayLeft2;
dallegre 2:1b50325e256f 51 AllPass delayRight2;
dallegre 2:1b50325e256f 52 gsOsc Oscillator;
dallegre 2:1b50325e256f 53 gsOsc Oscillator2;
dallegre 2:1b50325e256f 54 gsOsc Oscillator3;
dallegre 2:1b50325e256f 55 gsOsc Oscillator4;
dallegre 0:c12e968e5b60 56
dallegre 0:c12e968e5b60 57 void I2S_send(void){
dallegre 0:c12e968e5b60 58 cs.write(0); //0 for left output
dallegre 0:c12e968e5b60 59 left_in = spi.write(left_out);
dallegre 0:c12e968e5b60 60 cs.write(1); //1 for right output
dallegre 0:c12e968e5b60 61 right_in = spi.write(right_out);
dallegre 0:c12e968e5b60 62
dallegre 0:c12e968e5b60 63 left_in_f = intToFloat(left_in);
dallegre 0:c12e968e5b60 64
dallegre 0:c12e968e5b60 65 /////////////////////////////////////////dsp part//////////////////////////////////////////////////////////////////////
dallegre 0:c12e968e5b60 66
dallegre 0:c12e968e5b60 67 //process control signals
dallegre 0:c12e968e5b60 68 feedback2 = feedbackFilter.process(feedback);
dallegre 0:c12e968e5b60 69 feedback3 = feedbackFilter.process(feedback2);
dallegre 0:c12e968e5b60 70 //update delay times with every audio sample if you're going to filter them.
dallegre 0:c12e968e5b60 71 measf2 = lengthFilter.process(measf);
dallegre 0:c12e968e5b60 72 measf3 = lengthFilter.process(measf2);
dallegre 0:c12e968e5b60 73 measf3 *= (DELAYLEN); //convert to delay index normalization
dallegre 0:c12e968e5b60 74
dallegre 2:1b50325e256f 75 //process audio. probably calculate these coefficients elsewhere so you don't do the multiply all the time.
dallegre 2:1b50325e256f 76 //left delay mod
dallegre 2:1b50325e256f 77 measf3 = DELAYLEN*.64 + Oscillator.process(.013,DELAYLEN/16,1);
dallegre 2:1b50325e256f 78 measf3c = DELAYLEN*.23 + Oscillator3.process(.012,DELAYLEN/15,0);
dallegre 2:1b50325e256f 79 //right delay mod
dallegre 2:1b50325e256f 80 measf3b = DELAYLEN*.75 + Oscillator2.process(.011,DELAYLEN/19,0);
dallegre 2:1b50325e256f 81 measf3d = DELAYLEN*.29 + Oscillator4.process(.015,DELAYLEN/17,0);
dallegre 2:1b50325e256f 82 if(measf3 > DELAYLEN*.9)
dallegre 2:1b50325e256f 83 measf3 = DELAYLEN*.9;
dallegre 2:1b50325e256f 84 if(measf3 < DELAYLEN*.05)
dallegre 2:1b50325e256f 85 measf3 = DELAYLEN*.05;
dallegre 2:1b50325e256f 86 if(measf3b > DELAYLEN*.9)
dallegre 2:1b50325e256f 87 measf3b = DELAYLEN*.9;
dallegre 2:1b50325e256f 88 if(measf3b < DELAYLEN*.05)
dallegre 2:1b50325e256f 89 measf3b = DELAYLEN*.05;
dallegre 2:1b50325e256f 90 if(measf3c > DELAYLEN*.9)
dallegre 2:1b50325e256f 91 measf3c = DELAYLEN*.9;
dallegre 2:1b50325e256f 92 if(measf3c < DELAYLEN*.05)
dallegre 2:1b50325e256f 93 measf3c = DELAYLEN*.05;
dallegre 2:1b50325e256f 94 if(measf3d > DELAYLEN*.9)
dallegre 2:1b50325e256f 95 measf3d = DELAYLEN*.9;
dallegre 2:1b50325e256f 96 if(measf3d < DELAYLEN*.05)
dallegre 2:1b50325e256f 97 measf3d = DELAYLEN*.05;
dallegre 2:1b50325e256f 98 left_out_2 = delayLeft2.process(satSubtract(left_in_f,loopfb),.7,measf3c);
dallegre 2:1b50325e256f 99 left_out_f = delayLeft.process(left_out_2,.8,measf3);
dallegre 2:1b50325e256f 100 right_out_2 = delayRight2.process(satSubtract(left_in_f,loopfb2),.7,measf3d);
dallegre 2:1b50325e256f 101 right_out_f = delayRight.process(right_out_2,.8,measf3b); //add an offset in just for shits.
dallegre 2:1b50325e256f 102 loopfb = left_out_2*feedback3;
dallegre 2:1b50325e256f 103 loopfb2 = right_out_2*feedback3;
dallegre 0:c12e968e5b60 104 left_out_u = satAdd(left_in_f,left_out_f);
dallegre 0:c12e968e5b60 105 right_out_u = satAdd(left_in_f,right_out_f);
dallegre 0:c12e968e5b60 106
dallegre 0:c12e968e5b60 107 /////////////////////////////////////////end of dsp part/////////////////////////////////////////////////////////////////
dallegre 0:c12e968e5b60 108
dallegre 0:c12e968e5b60 109 left_out = unsignedToSigned(left_out_u);
dallegre 0:c12e968e5b60 110 right_out = unsignedToSigned(right_out_u);
dallegre 0:c12e968e5b60 111
dallegre 0:c12e968e5b60 112 }
dallegre 0:c12e968e5b60 113
dallegre 0:c12e968e5b60 114 void analog_read(void){
dallegre 0:c12e968e5b60 115 //this is the stuff for the feedback amount pot
dallegre 0:c12e968e5b60 116 meas2f = analog_value2.read_u16(); //converts unint16 value to float
dallegre 0:c12e968e5b60 117 feedback = meas2f/4100; //now you have a value between 0 and 1 that will control the feedback amount.
dallegre 0:c12e968e5b60 118
dallegre 0:c12e968e5b60 119 //this is the stuff for the delay time pot
dallegre 0:c12e968e5b60 120 meas = 4096 - analog_value.read_u16(); //values go from 1 to 4095
dallegre 0:c12e968e5b60 121 //if(abs(meas - measprev) > 5){
dallegre 0:c12e968e5b60 122 measprev = meas;
dallegre 0:c12e968e5b60 123 measf = meas;
dallegre 0:c12e968e5b60 124 measf /= 4200; //this number took some tweaking.
dallegre 0:c12e968e5b60 125 measf *= measf;
dallegre 0:c12e968e5b60 126 //}
dallegre 0:c12e968e5b60 127 }
dallegre 0:c12e968e5b60 128
dallegre 0:c12e968e5b60 129 int main(){
dallegre 0:c12e968e5b60 130
dallegre 0:c12e968e5b60 131 //set up baud rate for 11.2MHz crystal
dallegre 0:c12e968e5b60 132 pc.baud(.7*9600*2);
dallegre 0:c12e968e5b60 133 wait(.1);
dallegre 0:c12e968e5b60 134
dallegre 0:c12e968e5b60 135 //do I2C transfter to initialize codec
dallegre 0:c12e968e5b60 136 codecInit();
dallegre 0:c12e968e5b60 137
dallegre 0:c12e968e5b60 138 //initialize fixed filters
dallegre 0:c12e968e5b60 139 double feedbackCutoff = 10.0/(SAMPLINGFREQ*1000); //adjust these cutoffs according to taste.
dallegre 0:c12e968e5b60 140 feedbackFilter.setFc(feedbackCutoff);
dallegre 0:c12e968e5b60 141 double lengthCutoff = 3.0/(SAMPLINGFREQ*1000);
dallegre 0:c12e968e5b60 142 lengthFilter.setFc(lengthCutoff);
dallegre 0:c12e968e5b60 143
dallegre 0:c12e968e5b60 144 //initialize audio filter
dallegre 0:c12e968e5b60 145 double audioCutoff = LPdampingFreq/(SAMPLINGFREQ*1000); //adjust these cutoffs according to taste.
dallegre 0:c12e968e5b60 146 audioFilter.setFc(audioCutoff);
dallegre 0:c12e968e5b60 147 audioCutoff = HPdampingFreq/(SAMPLINGFREQ*1000); //adjust these cutoffs according to taste.
dallegre 0:c12e968e5b60 148 audioFilterHP.setFc(audioCutoff);
dallegre 0:c12e968e5b60 149
dallegre 0:c12e968e5b60 150 //set up I2S
dallegre 0:c12e968e5b60 151 spi.frequency(8e6*2); //8MHz spi. This is fast enough for 88KHz 16 bit sampling.
dallegre 0:c12e968e5b60 152 spi.format(16,0); //16 bit. clock polarity 0, phase 0.
dallegre 0:c12e968e5b60 153 wait(.1);
dallegre 0:c12e968e5b60 154
dallegre 0:c12e968e5b60 155 //audio rate timers. 29 and 44 are not very good. Might want to use an external clock for the Nucleo.
dallegre 0:c12e968e5b60 156 if(SAMPLINGFREQ == 22)
dallegre 0:c12e968e5b60 157 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 158 if(SAMPLINGFREQ == 29)
dallegre 0:c12e968e5b60 159 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 160 if(SAMPLINGFREQ == 44)
dallegre 0:c12e968e5b60 161 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 162 if(SAMPLINGFREQ == 88)
dallegre 0:c12e968e5b60 163 timer.attach(&I2S_send,8e-6); //88KHz sampling. Need to calculate.
dallegre 0:c12e968e5b60 164
dallegre 0:c12e968e5b60 165 //control signal timer
dallegre 0:c12e968e5b60 166 timer2.attach(&analog_read,25e-3);
dallegre 0:c12e968e5b60 167
dallegre 0:c12e968e5b60 168 //go!
dallegre 0:c12e968e5b60 169 while(1){}
dallegre 0:c12e968e5b60 170 }