Dan Allegre / 401_reverb

Dependencies:   mbed

Committer:
dallegre
Date:
Tue Jun 23 06:22:47 2015 +0000
Revision:
0:c12e968e5b60
Child:
1:a4ce08417c60
working audio delay with large array as sram buffer.  doesn't work with mbed library revision 89 or later.

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 0:c12e968e5b60 17 #define DELAYLEN 11500 //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 0:c12e968e5b60 21 #include "dsp.h"
dallegre 0:c12e968e5b60 22 #include "codec.h"
dallegre 0:c12e968e5b60 23
dallegre 0:c12e968e5b60 24 SPI spi(SPI_MOSI,SPI_MISO,SPI_SCK);
dallegre 0:c12e968e5b60 25 Ticker timer;
dallegre 0:c12e968e5b60 26 Ticker timer2;
dallegre 0:c12e968e5b60 27 AnalogIn analog_value(A1); //delay time pot
dallegre 0:c12e968e5b60 28 AnalogIn analog_value2(A0); //feedback amount pot
dallegre 0:c12e968e5b60 29 DigitalOut cs(D10);
dallegre 0:c12e968e5b60 30
dallegre 0:c12e968e5b60 31 int left_out = 0, right_out = 0, left_out_u = 0, right_out_u = 0, left_in = 0, right_in = 0,
dallegre 0:c12e968e5b60 32 index1 = 0, index2 = (DELAYLEN*0.99), index3 = (DELAYLEN*0.99);
dallegre 0:c12e968e5b60 33 uint16_t left_in_u = 0, meas = 0, measprev = 0;
dallegre 0:c12e968e5b60 34 float left_in_f = 0, feedback = 0, feedback2 = 0, feedback3 = 0, offset = 10.0,
dallegre 0:c12e968e5b60 35 meas2f = 0.5, measf = 0, measf2 = 0, measf3 = 0, left_out_f = 0, right_out_f = 0;
dallegre 0:c12e968e5b60 36 float audioFeedbackRight,audioFeedbackLeft;
dallegre 0:c12e968e5b60 37
dallegre 0:c12e968e5b60 38 float LPdampingFreq = 11000, HPdampingFreq = 100; //some parameters you might want to adjust.
dallegre 0:c12e968e5b60 39 int LPdampingPoles = 2, HPdampingPoles = 0; //I don't think the highpass is quite working.
dallegre 0:c12e968e5b60 40
dallegre 0:c12e968e5b60 41 OnePoleLp audioFilter; //might use this as a mor thorough DC offset removal tool. Not yet implemented.
dallegre 0:c12e968e5b60 42 OnePoleHp audioFilterHP;
dallegre 0:c12e968e5b60 43 OnePoleLp feedbackFilter;
dallegre 0:c12e968e5b60 44 OnePoleLp lengthFilter;
dallegre 0:c12e968e5b60 45 Delay delayLeft;
dallegre 0:c12e968e5b60 46 Delay delayRight;
dallegre 0:c12e968e5b60 47
dallegre 0:c12e968e5b60 48 void I2S_send(void){
dallegre 0:c12e968e5b60 49 cs.write(0); //0 for left output
dallegre 0:c12e968e5b60 50 left_in = spi.write(left_out);
dallegre 0:c12e968e5b60 51 cs.write(1); //1 for right output
dallegre 0:c12e968e5b60 52 right_in = spi.write(right_out);
dallegre 0:c12e968e5b60 53
dallegre 0:c12e968e5b60 54 left_in_f = intToFloat(left_in);
dallegre 0:c12e968e5b60 55
dallegre 0:c12e968e5b60 56 /////////////////////////////////////////dsp part//////////////////////////////////////////////////////////////////////
dallegre 0:c12e968e5b60 57
dallegre 0:c12e968e5b60 58 //process control signals
dallegre 0:c12e968e5b60 59 feedback2 = feedbackFilter.process(feedback);
dallegre 0:c12e968e5b60 60 feedback3 = feedbackFilter.process(feedback2);
dallegre 0:c12e968e5b60 61 //update delay times with every audio sample if you're going to filter them.
dallegre 0:c12e968e5b60 62 measf2 = lengthFilter.process(measf);
dallegre 0:c12e968e5b60 63 measf3 = lengthFilter.process(measf2);
dallegre 0:c12e968e5b60 64 measf3 *= (DELAYLEN); //convert to delay index normalization
dallegre 0:c12e968e5b60 65
dallegre 0:c12e968e5b60 66 //process audio
dallegre 0:c12e968e5b60 67 ///*
dallegre 0:c12e968e5b60 68 //*/
dallegre 0:c12e968e5b60 69 left_out_f = delayLeft.process(left_in_f,audioFeedbackRight*feedback3,measf3);
dallegre 0:c12e968e5b60 70 right_out_f = delayRight.process(left_in_f,audioFeedbackLeft*feedback3,measf3+offset); //add an offset in just for shits.
dallegre 0:c12e968e5b60 71 left_out_u = satAdd(left_in_f,left_out_f);
dallegre 0:c12e968e5b60 72 right_out_u = satAdd(left_in_f,right_out_f);
dallegre 0:c12e968e5b60 73
dallegre 0:c12e968e5b60 74 //a little damping of the feedback
dallegre 0:c12e968e5b60 75 audioFeedbackRight = audioFilter.process(right_out_f);
dallegre 0:c12e968e5b60 76 for(int i = 0; i < LPdampingPoles - 1; i++){
dallegre 0:c12e968e5b60 77 audioFeedbackRight = audioFilter.process(audioFeedbackRight);
dallegre 0:c12e968e5b60 78 }
dallegre 0:c12e968e5b60 79 for(int i = 0; i < HPdampingPoles; i++){
dallegre 0:c12e968e5b60 80 audioFeedbackRight = audioFilterHP.process(audioFeedbackRight);
dallegre 0:c12e968e5b60 81 }
dallegre 0:c12e968e5b60 82 audioFeedbackLeft = audioFilter.process(left_out_f);
dallegre 0:c12e968e5b60 83 for(int i = 0; i < LPdampingPoles - 1; i++){
dallegre 0:c12e968e5b60 84 audioFeedbackLeft = audioFilter.process(audioFeedbackLeft);
dallegre 0:c12e968e5b60 85 }
dallegre 0:c12e968e5b60 86 for(int i = 0; i < HPdampingPoles; i++){
dallegre 0:c12e968e5b60 87 audioFeedbackLeft = audioFilterHP.process(audioFeedbackLeft);
dallegre 0:c12e968e5b60 88 }
dallegre 0:c12e968e5b60 89
dallegre 0:c12e968e5b60 90 /////////////////////////////////////////end of dsp part/////////////////////////////////////////////////////////////////
dallegre 0:c12e968e5b60 91
dallegre 0:c12e968e5b60 92 left_out = unsignedToSigned(left_out_u);
dallegre 0:c12e968e5b60 93 right_out = unsignedToSigned(right_out_u);
dallegre 0:c12e968e5b60 94
dallegre 0:c12e968e5b60 95 }
dallegre 0:c12e968e5b60 96
dallegre 0:c12e968e5b60 97 void analog_read(void){
dallegre 0:c12e968e5b60 98 //this is the stuff for the feedback amount pot
dallegre 0:c12e968e5b60 99 meas2f = analog_value2.read_u16(); //converts unint16 value to float
dallegre 0:c12e968e5b60 100 feedback = meas2f/4100; //now you have a value between 0 and 1 that will control the feedback amount.
dallegre 0:c12e968e5b60 101
dallegre 0:c12e968e5b60 102 //this is the stuff for the delay time pot
dallegre 0:c12e968e5b60 103 meas = 4096 - analog_value.read_u16(); //values go from 1 to 4095
dallegre 0:c12e968e5b60 104 //if(abs(meas - measprev) > 5){
dallegre 0:c12e968e5b60 105 measprev = meas;
dallegre 0:c12e968e5b60 106 measf = meas;
dallegre 0:c12e968e5b60 107 measf /= 4200; //this number took some tweaking.
dallegre 0:c12e968e5b60 108 measf *= measf;
dallegre 0:c12e968e5b60 109 //}
dallegre 0:c12e968e5b60 110 }
dallegre 0:c12e968e5b60 111
dallegre 0:c12e968e5b60 112 int main(){
dallegre 0:c12e968e5b60 113
dallegre 0:c12e968e5b60 114 //set up baud rate for 11.2MHz crystal
dallegre 0:c12e968e5b60 115 pc.baud(.7*9600*2);
dallegre 0:c12e968e5b60 116 wait(.1);
dallegre 0:c12e968e5b60 117
dallegre 0:c12e968e5b60 118 //do I2C transfter to initialize codec
dallegre 0:c12e968e5b60 119 codecInit();
dallegre 0:c12e968e5b60 120
dallegre 0:c12e968e5b60 121 //initialize fixed filters
dallegre 0:c12e968e5b60 122 double feedbackCutoff = 10.0/(SAMPLINGFREQ*1000); //adjust these cutoffs according to taste.
dallegre 0:c12e968e5b60 123 feedbackFilter.setFc(feedbackCutoff);
dallegre 0:c12e968e5b60 124 double lengthCutoff = 3.0/(SAMPLINGFREQ*1000);
dallegre 0:c12e968e5b60 125 lengthFilter.setFc(lengthCutoff);
dallegre 0:c12e968e5b60 126
dallegre 0:c12e968e5b60 127 //initialize audio filter
dallegre 0:c12e968e5b60 128 double audioCutoff = LPdampingFreq/(SAMPLINGFREQ*1000); //adjust these cutoffs according to taste.
dallegre 0:c12e968e5b60 129 audioFilter.setFc(audioCutoff);
dallegre 0:c12e968e5b60 130 audioCutoff = HPdampingFreq/(SAMPLINGFREQ*1000); //adjust these cutoffs according to taste.
dallegre 0:c12e968e5b60 131 audioFilterHP.setFc(audioCutoff);
dallegre 0:c12e968e5b60 132
dallegre 0:c12e968e5b60 133 //set up I2S
dallegre 0:c12e968e5b60 134 spi.frequency(8e6*2); //8MHz spi. This is fast enough for 88KHz 16 bit sampling.
dallegre 0:c12e968e5b60 135 spi.format(16,0); //16 bit. clock polarity 0, phase 0.
dallegre 0:c12e968e5b60 136 wait(.1);
dallegre 0:c12e968e5b60 137
dallegre 0:c12e968e5b60 138 //audio rate timers. 29 and 44 are not very good. Might want to use an external clock for the Nucleo.
dallegre 0:c12e968e5b60 139 if(SAMPLINGFREQ == 22)
dallegre 0:c12e968e5b60 140 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 141 if(SAMPLINGFREQ == 29)
dallegre 0:c12e968e5b60 142 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 143 if(SAMPLINGFREQ == 44)
dallegre 0:c12e968e5b60 144 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 145 if(SAMPLINGFREQ == 88)
dallegre 0:c12e968e5b60 146 timer.attach(&I2S_send,8e-6); //88KHz sampling. Need to calculate.
dallegre 0:c12e968e5b60 147
dallegre 0:c12e968e5b60 148 //control signal timer
dallegre 0:c12e968e5b60 149 timer2.attach(&analog_read,25e-3);
dallegre 0:c12e968e5b60 150
dallegre 0:c12e968e5b60 151 //go!
dallegre 0:c12e968e5b60 152 while(1){}
dallegre 0:c12e968e5b60 153 }