Dan Allegre / 401_reverb

Dependencies:   mbed

main.cpp

Committer:
dallegre
Date:
2015-06-23
Revision:
0:c12e968e5b60
Child:
1:a4ce08417c60

File content as of revision 0:c12e968e5b60:

//delay dsp for stm32f401re nucleo board with openmusiclabs audio codec shield.  Need to jumpter the i2c pins from the 
//top right arduino headers on the nucleo board to the bottom left 2 pins on the codec shield.  Bottom left i2c pins are
//not mbed enabled on the nucleo boards. 
//Also need to install a 11.2896MHz crystal on nucleo board and connect the appropriate jumpers as explained in the nucleo
//user manual.  Two 20pf capacitors are used with the crystal.  The series resistors going from the crystal to the stm32 chip
//are just shorts.   
//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
//blocking cap after the op amp.
//Note that this is setup for the left input only and drives both outputs.  It is easy to modify the code for stereo effects
//and both inputs.  

//June 2015..
//Added interpolation so it acts more like a bbd or tape delay.  It is easy to switch between cosine and linear interpolation.
//Cubic interpolation might be a possibility if I can figure out how it works.
//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.

#define DELAYLEN        11500       //24,000 is about as far as you can go in the ram.
#define SAMPLINGFREQ    22          //roughly the smapling frequency in KHz.  options are 22,29,44,88 for 22khz,29khz,etc..

#include "mbed.h"
#include "dsp.h" 
#include "codec.h"
 
SPI spi(SPI_MOSI,SPI_MISO,SPI_SCK);
Ticker timer;
Ticker timer2;
AnalogIn analog_value(A1);          //delay time pot
AnalogIn analog_value2(A0);         //feedback amount pot
DigitalOut cs(D10);

int left_out = 0, right_out = 0, left_out_u = 0, right_out_u = 0, left_in = 0, right_in = 0,
index1 = 0, index2 = (DELAYLEN*0.99), index3 = (DELAYLEN*0.99);
uint16_t left_in_u = 0, meas = 0, measprev = 0;
float left_in_f = 0, feedback = 0, feedback2 = 0, feedback3 = 0, offset = 10.0,
meas2f = 0.5, measf = 0, measf2 = 0, measf3 = 0, left_out_f = 0, right_out_f = 0;
float audioFeedbackRight,audioFeedbackLeft;

float LPdampingFreq = 11000, HPdampingFreq = 100;  //some parameters you might want to adjust.
int   LPdampingPoles = 2, HPdampingPoles = 0;       //I don't think the highpass is quite working.

OnePoleLp audioFilter;                          //might use this as a mor thorough DC offset removal tool.  Not yet implemented.
OnePoleHp audioFilterHP;
OnePoleLp feedbackFilter;
OnePoleLp lengthFilter;
Delay delayLeft;
Delay delayRight;

void I2S_send(void){
    cs.write(0);                                //0 for left output
    left_in = spi.write(left_out);
    cs.write(1);                                //1 for right output
    right_in = spi.write(right_out);
    
    left_in_f = intToFloat(left_in);
    
    /////////////////////////////////////////dsp part//////////////////////////////////////////////////////////////////////
        
    //process control signals
    feedback2 = feedbackFilter.process(feedback);
    feedback3 = feedbackFilter.process(feedback2);
    //update delay times with every audio sample if you're going to filter them.
    measf2 = lengthFilter.process(measf);
    measf3 = lengthFilter.process(measf2);
    measf3 *= (DELAYLEN);                       //convert to delay index normalization

    //process audio
    ///*
    //*/
    left_out_f = delayLeft.process(left_in_f,audioFeedbackRight*feedback3,measf3);
    right_out_f = delayRight.process(left_in_f,audioFeedbackLeft*feedback3,measf3+offset);     //add an offset in just for shits.
    left_out_u = satAdd(left_in_f,left_out_f);
    right_out_u = satAdd(left_in_f,right_out_f);
    
    //a little damping of the feedback
    audioFeedbackRight =  audioFilter.process(right_out_f);
    for(int i = 0; i < LPdampingPoles - 1; i++){
        audioFeedbackRight =  audioFilter.process(audioFeedbackRight);
    }
    for(int i = 0; i < HPdampingPoles; i++){
        audioFeedbackRight =  audioFilterHP.process(audioFeedbackRight);
    }
    audioFeedbackLeft =   audioFilter.process(left_out_f);
    for(int i = 0; i < LPdampingPoles - 1; i++){    
        audioFeedbackLeft =   audioFilter.process(audioFeedbackLeft);
    }
    for(int i = 0; i < HPdampingPoles; i++){    
        audioFeedbackLeft =  audioFilterHP.process(audioFeedbackLeft);
    }

    /////////////////////////////////////////end of dsp part/////////////////////////////////////////////////////////////////
    
    left_out = unsignedToSigned(left_out_u);
    right_out = unsignedToSigned(right_out_u);

}

void analog_read(void){
    //this is the stuff for the feedback amount pot
    meas2f = analog_value2.read_u16();          //converts unint16 value to float
    feedback = meas2f/4100;                     //now you have a value between 0 and 1 that will control the feedback amount.
    
    //this is the stuff for the delay time pot
    meas = 4096 - analog_value.read_u16();      //values go from 1 to 4095
    //if(abs(meas - measprev) > 5){
        measprev = meas;
        measf = meas;
        measf /= 4200;                              //this number took some tweaking.
        measf *= measf;
    //}
}

int main(){
    
    //set up baud rate for 11.2MHz crystal
    pc.baud(.7*9600*2);
    wait(.1);
    
    //do I2C transfter to initialize codec
    codecInit();
    
    //initialize fixed filters
    double feedbackCutoff = 10.0/(SAMPLINGFREQ*1000);       //adjust these cutoffs according to taste.
    feedbackFilter.setFc(feedbackCutoff);
    double lengthCutoff = 3.0/(SAMPLINGFREQ*1000);
    lengthFilter.setFc(lengthCutoff);
    
    //initialize audio filter
    double audioCutoff = LPdampingFreq/(SAMPLINGFREQ*1000);       //adjust these cutoffs according to taste.
    audioFilter.setFc(audioCutoff);
    audioCutoff = HPdampingFreq/(SAMPLINGFREQ*1000);       //adjust these cutoffs according to taste.
    audioFilterHP.setFc(audioCutoff);

    //set up I2S
    spi.frequency(8e6*2);                         //8MHz spi.  This is fast enough for 88KHz 16 bit sampling.
    spi.format(16,0);                           //16 bit.  clock polarity 0, phase 0.
    wait(.1);
    
    //audio rate timers.   29 and 44 are not very good.  Might want to use an external clock for the Nucleo.  
    if(SAMPLINGFREQ == 22)
        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.
    if(SAMPLINGFREQ == 29)
        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.
    if(SAMPLINGFREQ == 44)    
        timer.attach(&I2S_send,16.0e-6);        //44.1KHz sampling.         almost exactly 32e-6 and then divide by 2.  Doesn't sound right yet.
    if(SAMPLINGFREQ == 88)
        timer.attach(&I2S_send,8e-6);       //88KHz sampling.   Need to calculate.
    
    //control signal timer
    timer2.attach(&analog_read,25e-3);
    
    //go!
    while(1){}
}