CSUSM FM Synth 2017 / Mbed 2 deprecated FMSynthCSUSM

Dependencies:   mbed

Fork of STM32FMSynth by Steven Clark

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include "mbed.h"
00002 #include "sintable.h"
00003 
00004 AnalogOut outMono(PA_4);//Not labeled in the docs for the f401, but seems to be for all
00005 //AnalogOut DAC1(PA_5);
00006 
00007 AnalogIn inVol(PA_0);
00008 AnalogIn inModAmt(PA_1);
00009 //AnalogIn ADC2(PA_2);//these are the uart pins!!
00010 //AnalogIn ADC3(PA_3);//these are the uart pins!!
00011 //AnalogIn ADC4(PA_4);//we're using these for output
00012 //AnalogIn ADC5(PA_5);//we're using these for output
00013 AnalogIn inCarA(PA_6);
00014 AnalogIn inCarD(PA_7);
00015 //AnalogIn ADC8(PB_0);//lets leave the 2 we aren't using in a single port
00016 //AnalogIn ADC9(PB_1);//that way we know there's not ADCs on one of them
00017 AnalogIn inCarS(PC_0);
00018 AnalogIn inCarR(PC_1);
00019 AnalogIn inModA(PC_2);
00020 AnalogIn inModD(PC_3);
00021 AnalogIn inModS(PC_4);
00022 AnalogIn inModR(PC_5);
00023 
00024 //BusIn keyBank(PC_10, PC_11, PC_12, PC_13, PD_2, PH_1); old
00025 BusIn keyBank(PH_1, PD_2, PC_13, PC_12, PC_11, PC_10);
00026 BusOut bankSelect(PB_0, PB_1, PB_2, PB_3, PB_4, PB_5, PB_6, PB_7, PB_8);
00027 BusIn numerator(PA_8, PA_9, PA_10, PA_11);
00028 BusIn denominator(PA_12, PA_13, PA_14, PA_15);
00029 
00030 //Serial pc(USBTX, USBRX);
00031 
00032 Ticker synthesisClock;// this object sets up an ISR to execute every given fraction of a second.
00033 
00034 #define numKeys 49// our keyboard includes from two octaves above middle c to two octaves below it
00035 
00036 //constants
00037 
00038 //These are the pitches of the notes of our keyboard in hz * int16_max / sampling rate(20khz)
00039 const int carrierIncrements[] = {214, 227, 240, 254, 270, 286, 303, 321, 340, 
00040     360, 381, 404, 428, 454, 481, 509, 540, 572, 606, 642, 680, 720, 763, 809, 
00041     857, 908, 962, 1019, 1080, 1144, 1212, 1284, 1360, 1441, 1527, 1618, 1714, 
00042     1816, 1924, 2039, 2160, 2288, 2424, 2568, 2721, 2883, 3055, 3236, 3429};
00043     
00044 //The maximum value of our envelopes is int16_max
00045 #define attackLimit 0xFFFF
00046 
00047 //this gives us a value of pi to multiply things by
00048 #define U_PI 3.14159265358979
00049 
00050 //non-constants
00051 //Most of these will be recalculated or reset on every input cycle of the main
00052 //  loop, as appropriate
00053 
00054 int FMmult = 1;//The modulator pitch is FMmult * the base carrier pitch for that note
00055 int Volume = 0xffff;//the maximum volume to start, our number format is fixed 16 bits of fractional
00056 //                      inside a 32bit integer usually only in that fractional allowing for
00057 //                      integer multiplications and shifts to recenter instead of floating
00058 //                      -point arithmetic
00059 int modVol = 0x2000;//the amount of modulation to apply, most useful relatively low
00060 int64_t keyboard = 0;//our key state is stored as bit flags in the lower 49 bits of this
00061 int64_t modattack = 0x1ffffffffffff;//similar to keyboard, if the corrsponding bit is
00062 //                                      zero the envelope for that bit is in decay or sustain instead of attack
00063 int64_t carattack = 0x1ffffffffffff;
00064 int carrierPhases[numKeys];//store the phases of the notes in between samplings
00065 int modulatorPhases[numKeys];
00066 int envelopeAmpsC[numKeys];//store the amplitudes of the envelopes in between samplings
00067 int envelopeAmpsM[numKeys];
00068 
00069 //the envelope parameters for synthesis are read from these registers
00070 int modA = 0xffff;//modulator attack rate
00071 int modD = 0xffff;//modulator decay rate
00072 int modS = 0;//modulator sustain level
00073 int modR = 0xffff;//modulator release rate
00074 int carA = 0xffff;//carrier attack rate
00075 int carD = 0xffff;//carrier decay rate
00076 int carS = 0;//carrier sustain level
00077 int carR = 0xffff;//carrier release level
00078 
00079 ///@brief Converts a phase of period 2^16 into a sine value
00080 ///@phase The phase to calculate the sine of in phase/65536 * 2 pi radians
00081 ///@return the sine as a signed 16 bit fractonal part inside a 32 bit int
00082 int fastSin(const int phase){
00083     //the middle 12 bits are used to index into a lookuptable of pre computed sines
00084     int index = (phase & 0x3ffc) >> 2;
00085     
00086     //we used linear interpolation given out bottom 2 bits to turn a 2^12 Look Up Table into a 2^14 LUT
00087     int subindex = phase & 0x3;
00088     
00089     //We use mirroring of a quarter wave of sine so we only have to store a quarter of the samples again
00090     int quadrant = (phase & 0xc000) >> 14;
00091     int sum = 0;
00092     switch (quadrant) {//perform the mirroring and add the memebers of the weighted average for interpolation
00093         case 0:
00094             sum += (4 - subindex) * sinTable[index];
00095             sum += subindex * sinTable[index+1];
00096             break;
00097         case 1:
00098             sum += (4 - subindex) * sinTable[1+4095-index];
00099             sum += subindex * sinTable[4095-index];
00100             break;
00101         case 2:
00102             sum -= (4 - subindex) * sinTable[index];
00103             sum -= subindex * sinTable[index+1];        
00104             break;
00105         case 3:
00106             sum -= (4 - subindex) * sinTable[1+4095-index];
00107             sum -= subindex * sinTable[4095-index];
00108             break;
00109     }
00110     sum = sum >> 2;//divide the weighted sum of the neighborign samples by 4
00111     //to get a weighted average
00112     
00113     return sum;
00114 }
00115 
00116 ///@brief calculates one audio sample given the keyboard state and envelope paramaters and passes it to the DAC
00117 void synthesize(){
00118     int wave = 0;// holds the sample being constructed.
00119     int subsignal;// the subsample for one note
00120     int64_t keymask;// holds a mask of the current note for easy access to keyboard and attack registers
00121         
00122     //for all keys
00123     for(int64_t i = 0; i < numKeys; ++i){
00124         keymask = 1ll << i;//set the key mask
00125                 
00126         if(!(keymask & keyboard)){//if the key is NOT pressed
00127             carattack |= keymask;//allow attack the next time it is
00128             modattack |= keymask;
00129             
00130             //if envelope is still positive, decrement by decay rate
00131             if(envelopeAmpsC[i] > 0){
00132                 envelopeAmpsC[i] -= carR;
00133             }
00134             if(envelopeAmpsM[i] > 0){
00135                 envelopeAmpsM[i] -= modR;
00136             }
00137             
00138         }else{//if the key IS pressed
00139         
00140             if(envelopeAmpsC[i] <= 0){//if this key was silent before,
00141                 carrierPhases[i] = 0;//reset the wave states
00142                 modulatorPhases[i] = 0;//this should prevent frequency drift from stopped FM
00143                 envelopeAmpsM[i] = 0;
00144                 envelopeAmpsC[i] = 1;//only do it once
00145             }
00146 
00147             //if carrier has not left attack phase
00148             if(keymask & carattack){
00149                 //add attack rate to envelope if not already maximised
00150                 if(envelopeAmpsC[i] < attackLimit ){
00151                     envelopeAmpsC[i] += carA;
00152                 }else{//otherwise clip to maximum and leave attack pahse
00153                     envelopeAmpsC[i] = attackLimit;
00154                     carattack &= ~keymask;
00155                 }
00156             }else{//if in decay/sustain
00157                 if(envelopeAmpsC[i] > carS){//subtract the decay rate if above sustain level
00158                     envelopeAmpsC[i] -= carD;
00159                 }
00160             }
00161             
00162             //do all that again for the modulator envelope
00163             if(keymask & modattack){
00164                 if(envelopeAmpsM[i] < attackLimit){
00165                     envelopeAmpsM[i] += modA;
00166                 }else{
00167                     envelopeAmpsM[i] = attackLimit;
00168                     modattack &= ~keymask;
00169                 }
00170             }else{
00171                 if(envelopeAmpsM[i] > modS){
00172                     envelopeAmpsM[i] -= modD;
00173                 }
00174             }
00175             
00176         }
00177         
00178         //If this subsignal is not silent
00179         if(envelopeAmpsC[i] > 0){
00180             //calculate the new phase of the modulator
00181             modulatorPhases[i] += (carrierIncrements[i] * FMmult)>> 16;
00182                 
00183             //get the sine for that phase and scale it by the envelope
00184             int modulation = (fastSin(modulatorPhases[i]) * envelopeAmpsM[i])>>16;
00185              
00186             //scale it again by the modulation amount
00187             modulation = (modulation * modVol) >> 16;
00188            
00189             //calculate the new phase of the carrier, modualting frequency by the modulation
00190             carrierPhases[i] += carrierIncrements[i] + modulation;
00191                 
00192             //get the sine for that carrier phase and scale by the envelope
00193             //additionally divide by 8 to allow 8 notes to play without saturating the DAC
00194             subsignal = (fastSin(carrierPhases[i]) * envelopeAmpsC[i])>>19;
00195                 
00196             //add the sample for this note into the overall sample
00197             wave += subsignal;
00198         }
00199         
00200     }
00201 
00202     //Scale the complete sample by the volume    
00203     wave = wave * Volume >> 16;
00204 
00205     //clip the sample to within the limits of the DAC if neccessary
00206     wave = (wave > 32767) ? 32767 : wave;
00207     wave = (wave < -32768) ? - 32768 : wave;
00208     
00209     //Center the waveform within the range of the DAC
00210     wave += 32768;
00211     
00212     //output the sample
00213     outMono.write_u16(wave);
00214 }
00215 
00216 
00217 int main() {
00218     int ratNumer;
00219     int ratDenom;    
00220     int64_t keytemp;
00221     int tempCarA, tempCarD, tempCarR, tempModA, tempModD, tempModR;
00222 
00223     for(int i = 0; i < numKeys; ++i){ //zero out values
00224         carrierPhases[i] = 0;
00225         modulatorPhases[i] = 0;
00226         envelopeAmpsC[i] = 0;
00227         envelopeAmpsM[i] = 0;
00228     }
00229     
00230     keyBank.mode(PullNone); // we're using external pullup resistors, 
00231                 //and things weren't working this didn't fix it but better safe
00232                 
00233     synthesisClock.attach(synthesize, 0.00005); //this runs every 50 us or 20khz
00234     
00235     while(true){
00236         ratNumer = 0xf & ~ numerator; //read ratio numerator
00237         ratDenom = 0xf & ~ denominator; //read ratio denominator
00238         FMmult = (ratNumer << 16) / ratDenom; //FM multiplier = numerator / denominator
00239         
00240         Volume = (int)inVol.read_u16(); //read volume
00241         
00242         modVol = (int)inModAmt.read_u16(); //read modulation amount
00243         
00244         //ensure we don't divide by zero on any of these
00245 
00246         //read carrier attack
00247         tempCarA = inCarA.read_u16();
00248         if(! tempCarA)
00249             carA = 0xffff;
00250         else
00251             carA = 0xffff / tempCarA;
00252         
00253         //read carrier decay
00254         tempCarD = inCarD.read_u16();
00255         if(! tempCarD)
00256             carD = 0xffff;
00257         else
00258             carD = 0xffff / tempCarD;
00259         
00260         //read carrier sustain
00261         carS = (int)inCarS.read_u16();
00262         
00263         //read carrier release
00264         tempCarR = inCarR.read_u16();
00265         if(! tempCarR)
00266             carR = 0xffff;
00267         else
00268             carR = 0xffff / tempCarR;
00269         
00270         //read modulation attack
00271         tempModA = inModA.read_u16();
00272         if(! tempModA)
00273             modA = 0xffff;
00274         else
00275             modA = 0xffff / tempModA;
00276         
00277         //read modulation decay
00278         tempModD = inModD.read_u16();
00279         if(! tempModD)
00280             modD = 0xffff;
00281         else
00282             modD = 0xffff / tempModD;
00283         
00284         //read modulation sustain
00285         modS = (int)inModS.read_u16();
00286         
00287         //read modulation release
00288         tempModR = inModR.read_u16();
00289         if(! tempModR)
00290             modR = 0xffff;
00291         else
00292             modR = 0xffff / tempModR;
00293         
00294         keytemp = 0; //zero the keys before we start ORing on top of everything, 
00295         //keytemp is a buffer that waits until every key is read, then it pushes 
00296         //into the 'keyboard' variable
00297         
00298         for(int i = 0; i < 9; ++i) {//for all 9 half-octaves of the keyboard
00299             bankSelect = (~(1 << i)) & bankSelect.mask();//supply power (as ground) to that bank
00300             wait_us(200); //delay to get to get full reading
00301             int shiftOffset = 6LL * i; //read the keys in the bank
00302             
00303             //assign the bank to its corresponding position in the overall keyboard
00304             keytemp |= ((~(unsigned long long)keyBank) & (unsigned long long)keyBank.mask()) << (unsigned long long)shiftOffset;
00305         }
00306         keytemp >>= 5;//shift 5 over because bank 0 only has 1 key and it is the 6th key (...111111 111111 100000)
00307         
00308         keyboard = keytemp;//push our read values once we are complete. 
00309         //This only takes 1 cycle, especially since we are using 'keyboard' in the ISR
00310         
00311         //wait_ms(10);//we've stopped bothering to wait here.  it didn't make a difference
00312     }
00313 }