Bluetooth Enabled Keyboard/Synthesizer for mbed
Dependencies: mbed 4DGL-uLCD-SE SDFileSystem mbed-rtos
main.cpp@24:3bd4e691ae59, 2016-05-01 (annotated)
- Committer:
- jmpin
- Date:
- Sun May 01 00:25:02 2016 +0000
- Revision:
- 24:3bd4e691ae59
- Parent:
- 23:cf9d43d5a5b4
- Child:
- 25:5a312725710a
Revamped the way the ADSR functionality is implemented. Percentages are now specified for A D S and R to determine how much of the waveform each of these should take up. Also, there are now only 4 coefficient matrices total corresponding to ADSR.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jmpin | 0:48311ffdfa96 | 1 | #include "mbed.h" |
jmpin | 3:3aba1d783730 | 2 | #include "SDFileSystem.h" |
jmpin | 6:68c6a50e1437 | 3 | #include "rtos.h" |
jmpin | 6:68c6a50e1437 | 4 | #include <vector> |
jmpin | 6:68c6a50e1437 | 5 | #include "uLCD_4DGL.h" |
jmpin | 3:3aba1d783730 | 6 | #include "synthesizer.h" |
Jake867 | 21:0df25c61c475 | 7 | #include "Speaker.h" |
Jake867 | 11:c87f55a3b9e0 | 8 | RawSerial Blue(p13,p14); |
Jake867 | 11:c87f55a3b9e0 | 9 | RawSerial PC(USBTX,USBRX); |
jmpin | 0:48311ffdfa96 | 10 | DigitalOut myled(LED1); |
jmpin | 0:48311ffdfa96 | 11 | DigitalOut myled4(LED4); |
jmpin | 3:3aba1d783730 | 12 | |
jmpin | 3:3aba1d783730 | 13 | SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card setup |
jmpin | 3:3aba1d783730 | 14 | |
Jake867 | 11:c87f55a3b9e0 | 15 | uLCD_4DGL uLCD(p28,p27,p30); // serial tx, serial rx, reset pin; |
jmpin | 6:68c6a50e1437 | 16 | |
Jake867 | 21:0df25c61c475 | 17 | Speaker mySpeaker(p18);; // p18 is the pin that will have the output voltages on it |
jmpin | 8:f6699fd30737 | 18 | |
jmpin | 6:68c6a50e1437 | 19 | |
jmpin | 0:48311ffdfa96 | 20 | //global variables for main and interrupt routine |
Jake867 | 11:c87f55a3b9e0 | 21 | volatile bool readyFlag = false; |
jmpin | 0:48311ffdfa96 | 22 | volatile char keyPress; |
jmpin | 3:3aba1d783730 | 23 | WaveType myWave = sine; // default to sine wave |
jmpin | 3:3aba1d783730 | 24 | volatile int currentOctave = 4; // default to 4 because thats where middle C is |
jmpin | 24:3bd4e691ae59 | 25 | int currentADSR = 3; // value representing which envelope shape is currently selected. default is 3 |
jmpin | 24:3bd4e691ae59 | 26 | float attackVals[32] = {}; // array that holds the attack coefficients |
jmpin | 24:3bd4e691ae59 | 27 | float decayVals[32] = {}; // array that holds the decay coefficients |
jmpin | 24:3bd4e691ae59 | 28 | float sustainVals[32]= {}; // array that holds the sustain coefficients |
jmpin | 24:3bd4e691ae59 | 29 | float releaseVals[32] = {}; // array that holds the release coefficients |
jmpin | 24:3bd4e691ae59 | 30 | short unsigned Analog_out_data[32]; // holds the samples that will be output to p18 |
jmpin | 6:68c6a50e1437 | 31 | volatile int noteFreq; // the current frequency of the note being played |
jmpin | 24:3bd4e691ae59 | 32 | float noteDuration = 2.0f; // default note duration will be 2 seconds |
jmpin | 24:3bd4e691ae59 | 33 | float attackPercentage[5] = {}; // holds values for percentage of waveform that the attack should take up |
jmpin | 24:3bd4e691ae59 | 34 | float decayPercentage[5] = {}; // holds values for percentage of waveform that the decay should take up |
jmpin | 24:3bd4e691ae59 | 35 | float sustainPercentage[5] = {}; // holds values for the percentage of waveform that the sustain should take up |
jmpin | 24:3bd4e691ae59 | 36 | float releasePercentage[5] = {}; // holds values for the percentage of waveform that the sutain should take up |
jmpin | 5:afd67e985df0 | 37 | |
jmpin | 5:afd67e985df0 | 38 | /* Coefficient Matrices Corresponding to Different Attack Values |
jmpin | 22:9c80f7bcef86 | 39 | each matrix is comprised of 4 elements (32/8). The first matrix corresponds |
jmpin | 12:d60a9d0052a7 | 40 | to an attack value of 5. |
jmpin | 5:afd67e985df0 | 41 | */ |
jmpin | 5:afd67e985df0 | 42 | |
Jake867 | 23:cf9d43d5a5b4 | 43 | float attackVals5[4] = {0 , 0.9 , 0.98 , 1}; //Approaches the maximum amplitude the quickest - corresponds to an attackValue of 5 |
jmpin | 22:9c80f7bcef86 | 44 | |
Jake867 | 23:cf9d43d5a5b4 | 45 | float attackVals4[4] = {0 , 0.78 , 0.92 , 1}; //Corresponds to an attackValue of 4 |
jmpin | 22:9c80f7bcef86 | 46 | |
Jake867 | 23:cf9d43d5a5b4 | 47 | float attackVals3[4] = {0 , 0.63 , 0.84 , 1}; //Corresponds to an attackValue of 3 |
jmpin | 22:9c80f7bcef86 | 48 | |
Jake867 | 23:cf9d43d5a5b4 | 49 | float attackVals2[4] = {0 , 0.5 , 0.75 , 1}; //Corresponds to an attackValue of 2 |
jmpin | 22:9c80f7bcef86 | 50 | |
Jake867 | 23:cf9d43d5a5b4 | 51 | float attackVals1[4] = {0 , 0.33 , 0.66 , 1}; //Approaches the mamimum amplitude the slowest, in a linear fashion - corresponds to an attackValue of 1 |
jmpin | 22:9c80f7bcef86 | 52 | |
jmpin | 5:afd67e985df0 | 53 | |
jmpin | 12:d60a9d0052a7 | 54 | /* Coefficient Matrices Corresponding to Different Decay Values |
jmpin | 22:9c80f7bcef86 | 55 | each matrix is comprised of 4 elements (32/8). The first matrix corresponds |
jmpin | 12:d60a9d0052a7 | 56 | to a decay value of 5. |
jmpin | 12:d60a9d0052a7 | 57 | */ |
jmpin | 12:d60a9d0052a7 | 58 | |
Jake867 | 23:cf9d43d5a5b4 | 59 | float decayVals5[4] = {0.67 , 0.63 , 0.62 , 0.6}; //Approaches the sustain amplitude the quickest - corresponds to a decay value of 5 |
Jake867 | 23:cf9d43d5a5b4 | 60 | float decayVals4[4] = {0.73 , 0.675 , 0.63 , 0.60}; // Decay value of 4 |
Jake867 | 23:cf9d43d5a5b4 | 61 | float decayVals3[4] = {0.77 , 0.7 , 0.63 , 0.60}; // Decay value of 3 |
Jake867 | 23:cf9d43d5a5b4 | 62 | float decayVals2[4] = {0.84 , 0.73 , 0.65 , 0.6}; // Decay value of 2 |
Jake867 | 23:cf9d43d5a5b4 | 63 | float decayVals1[4] = {0.9 , 0.8 , 0.7 , 0.6}; // Decays the slowest, in a linear fashion - corresponds to a decay value of 1 |
jmpin | 8:f6699fd30737 | 64 | |
jmpin | 12:d60a9d0052a7 | 65 | /* Coefficient Matrices Corresponding to Different sustain values |
jmpin | 22:9c80f7bcef86 | 66 | each matrix is comprised of 20 elements 5 * (32/8). The first matrix corresponds |
jmpin | 12:d60a9d0052a7 | 67 | to a sustain value of 5. The matrices get initialized later in a for loop due to their size. |
jmpin | 12:d60a9d0052a7 | 68 | */ |
jmpin | 12:d60a9d0052a7 | 69 | |
Jake867 | 23:cf9d43d5a5b4 | 70 | float sustainVals5[20]; |
Jake867 | 23:cf9d43d5a5b4 | 71 | float sustainVals4[20]; |
Jake867 | 23:cf9d43d5a5b4 | 72 | float sustainVals3[20]; |
Jake867 | 23:cf9d43d5a5b4 | 73 | float sustainVals2[20]; |
Jake867 | 23:cf9d43d5a5b4 | 74 | float sustainVals1[20]; |
jmpin | 12:d60a9d0052a7 | 75 | |
jmpin | 12:d60a9d0052a7 | 76 | /* Coefficient Matrices Corresponding to Different release values |
jmpin | 12:d60a9d0052a7 | 77 | each matrix is comprised of 32 elements (256/8). The first matrix corresponds |
jmpin | 12:d60a9d0052a7 | 78 | to a release value of 5. |
jmpin | 12:d60a9d0052a7 | 79 | */ |
jmpin | 12:d60a9d0052a7 | 80 | |
Jake867 | 23:cf9d43d5a5b4 | 81 | float releaseVals5[4] = {0.1 , 0.03 , 0.01 , 0}; // Releases (goes to 0 amplitude) the quickest - corresponds to a release value of 5 |
Jake867 | 23:cf9d43d5a5b4 | 82 | float releaseVals4[4] = {0.2 , 0.1 , .04 , 0}; // Release value of 4 |
Jake867 | 23:cf9d43d5a5b4 | 83 | float releaseVals3[4] = {0.33 , 0.16 , 0.08 , 0}; // Release value of 3 |
Jake867 | 23:cf9d43d5a5b4 | 84 | float releaseVals2[4] = {0.4 , 0.23 , 0.1 , 0}; // Release value of 2 |
Jake867 | 23:cf9d43d5a5b4 | 85 | float releaseVals1[4] = {0.45 , 0.30 , 0.15 , 0}; // Release value of 1 - proceeds slowest, in a linear fashion |
jmpin | 22:9c80f7bcef86 | 86 | |
jmpin | 5:afd67e985df0 | 87 | |
jmpin | 6:68c6a50e1437 | 88 | int noteArray[7][7] = { // Array holding different note frequencies |
jmpin | 6:68c6a50e1437 | 89 | C1 , D1 , E1 , F1 , G1 , A1 , B1 , |
jmpin | 6:68c6a50e1437 | 90 | C2 , D2 , E2 , F2 , G2 , A2 , B2, |
jmpin | 6:68c6a50e1437 | 91 | C3 , D3 , E3 , F3 , G3 , A3 , B2 , |
jmpin | 6:68c6a50e1437 | 92 | C4 , D4 , E4 , F4 , G4 , A4 , B4 , |
jmpin | 6:68c6a50e1437 | 93 | C5 , D5 , E5 , F5 , G5 , A5 , B5 , |
jmpin | 6:68c6a50e1437 | 94 | C6 , D6 , E6 , F6 , G6 , A6 , B6 , |
jmpin | 6:68c6a50e1437 | 95 | C7 , D7 , E7 , F7 , G7 , A7 , B7 |
jmpin | 6:68c6a50e1437 | 96 | }; |
jmpin | 5:afd67e985df0 | 97 | |
jmpin | 12:d60a9d0052a7 | 98 | void uLCD_Display_Thread(void const *args){ // uLCD displays curernt waveform shape, current octave, and the values for the ADSR coefficients |
Jake867 | 11:c87f55a3b9e0 | 99 | while(1){ |
Jake867 | 11:c87f55a3b9e0 | 100 | uLCD.locate(0,0); |
jmpin | 12:d60a9d0052a7 | 101 | switch(myWave){ |
jmpin | 12:d60a9d0052a7 | 102 | case sine: |
jmpin | 15:8ff317cc5d2c | 103 | uLCD.printf("Shape: Sine \r\n"); // if wave type is sine wave, display sine |
jmpin | 12:d60a9d0052a7 | 104 | break; |
jmpin | 12:d60a9d0052a7 | 105 | case square: |
jmpin | 15:8ff317cc5d2c | 106 | uLCD.printf("Shape: Square \r\n"); // if wave type is square wave, display square |
jmpin | 12:d60a9d0052a7 | 107 | break; |
jmpin | 12:d60a9d0052a7 | 108 | case sawtooth: |
jmpin | 12:d60a9d0052a7 | 109 | uLCD.printf("Shape: Sawtooth\r\n"); // if wave type is sawtooth wave, display sawtooth |
jmpin | 12:d60a9d0052a7 | 110 | break; |
jmpin | 12:d60a9d0052a7 | 111 | default: |
jmpin | 12:d60a9d0052a7 | 112 | break; |
jmpin | 12:d60a9d0052a7 | 113 | } |
jmpin | 12:d60a9d0052a7 | 114 | uLCD.printf("Octave: %i\r\n",currentOctave); // displays octave |
jmpin | 12:d60a9d0052a7 | 115 | uLCD.printf("Attack: %i\r\n",currentAttackVal); // displays attack value |
jmpin | 12:d60a9d0052a7 | 116 | uLCD.printf("Decay: %i\r\n",currentDecayVal); // displays decay value |
jmpin | 12:d60a9d0052a7 | 117 | uLCD.printf("Sustain: %i\r\n",currentSustainVal); // displays sustain value |
jmpin | 12:d60a9d0052a7 | 118 | uLCD.printf("Release: %i\r\n",currentReleaseVal); // displays release value |
Jake867 | 11:c87f55a3b9e0 | 119 | } |
jmpin | 12:d60a9d0052a7 | 120 | } |
jmpin | 6:68c6a50e1437 | 121 | |
jmpin | 12:d60a9d0052a7 | 122 | void set_Note_Freq(int frequency){ // updates the frequency of the note being played |
jmpin | 6:68c6a50e1437 | 123 | noteFreq = frequency; |
jmpin | 6:68c6a50e1437 | 124 | } |
jmpin | 6:68c6a50e1437 | 125 | |
jmpin | 24:3bd4e691ae59 | 126 | /* Generates the coefficients that will shape the waveform */ |
jmpin | 24:3bd4e691ae59 | 127 | |
jmpin | 24:3bd4e691ae59 | 128 | void initialize_ADSRVals() |
jmpin | 6:68c6a50e1437 | 129 | { |
jmpin | 24:3bd4e691ae59 | 130 | for(int j = 0; j < 32; j++) |
jmpin | 24:3bd4e691ae59 | 131 | { |
jmpin | 24:3bd4e691ae59 | 132 | attackVals[j] = (float)j/32.0f; |
jmpin | 24:3bd4e691ae59 | 133 | decayVals[j] = 1.0f - (j*((1-sustainAmplitude)/32)) |
jmpin | 24:3bd4e691ae59 | 134 | sustainVals[j] = (float)sustainAmplitude; |
jmpin | 24:3bd4e691ae59 | 135 | releaseVals[j] = (float)sustainAmplitude - (((sustainAmplitude)/32)*j); |
jmpin | 6:68c6a50e1437 | 136 | } |
jmpin | 6:68c6a50e1437 | 137 | } |
jmpin | 5:afd67e985df0 | 138 | |
jmpin | 24:3bd4e691ae59 | 139 | /* Generates the durations of each part of the waveform (attack,decay,sustain, and release)*/ |
jmpin | 6:68c6a50e1437 | 140 | |
jmpin | 24:3bd4e691ae59 | 141 | void generate_durations(int index) |
jmpin | 6:68c6a50e1437 | 142 | { |
jmpin | 24:3bd4e691ae59 | 143 | attackDuration = attackPercentage[index-1] * noteDuration; |
jmpin | 24:3bd4e691ae59 | 144 | decayDuration = decayPercentage[index-1] * noteDuration; |
jmpin | 24:3bd4e691ae59 | 145 | sustainDuration = sustainPercentage[index-1] * noteDuration; |
jmpin | 24:3bd4e691ae59 | 146 | releaseDuration = releasePercentage[index-1] * noteDuration; |
jmpin | 24:3bd4e691ae59 | 147 | } |
jmpin | 24:3bd4e691ae59 | 148 | |
jmpin | 12:d60a9d0052a7 | 149 | |
jmpin | 12:d60a9d0052a7 | 150 | |
jmpin | 12:d60a9d0052a7 | 151 | /* Applies the envelope to the waveform. Each set of coefficients is applied to a certain portion of the waveform to alter its shape. |
jmpin | 22:9c80f7bcef86 | 152 | The attack coefficients are appplied to the first 4 samples, the decay coefficients are applied to samples 5-8, the sustain coefficients |
jmpin | 22:9c80f7bcef86 | 153 | are applied to samples 9 - 28, and the release coefficients are appplied to samples 29-32. |
jmpin | 12:d60a9d0052a7 | 154 | */ |
jmpin | 6:68c6a50e1437 | 155 | |
jmpin | 12:d60a9d0052a7 | 156 | |
jmpin | 24:3bd4e691ae59 | 157 | |
jmpin | 5:afd67e985df0 | 158 | |
jmpin | 12:d60a9d0052a7 | 159 | void generate_sineWave(int frequency) // Generates samples for a sine wave of a given input frequency |
jmpin | 9:e4df1a31a098 | 160 | { |
Jake867 | 21:0df25c61c475 | 161 | for(int i = 0; i < 32 ; i++) |
jmpin | 9:e4df1a31a098 | 162 | { |
Jake867 | 21:0df25c61c475 | 163 | Analog_out_data[i] = int (65536.0 * ((1.0 + sin((float(i)/32.0*6.28318530717959)))/2.0)); // scaled to be 16bit |
jmpin | 9:e4df1a31a098 | 164 | } |
jmpin | 9:e4df1a31a098 | 165 | } |
jmpin | 9:e4df1a31a098 | 166 | |
jmpin | 12:d60a9d0052a7 | 167 | void generate_sawtoothWave(int frequency) // Generates samples for a sawtooth wave of a given input frequency |
jmpin | 9:e4df1a31a098 | 168 | { |
Jake867 | 21:0df25c61c475 | 169 | float t = 0; // Represents time |
Jake867 | 21:0df25c61c475 | 170 | for(int i = 0; i<32 ; i++) |
jmpin | 9:e4df1a31a098 | 171 | { |
Jake867 | 21:0df25c61c475 | 172 | Analog_out_data[i] = int(t * 65536.0); //scaled to 16bit |
Jake867 | 21:0df25c61c475 | 173 | t+= 1.0/32.0; // increment t for calculation of next value in the waveform |
jmpin | 9:e4df1a31a098 | 174 | } |
jmpin | 9:e4df1a31a098 | 175 | } |
jmpin | 9:e4df1a31a098 | 176 | |
jmpin | 12:d60a9d0052a7 | 177 | void generate_squareWave(int frequency) // Generates samples for a square wave of a given input frequency. Looks at whether we have seen an even or odd number of 'widths' to determine if wave should be high or low at given t |
jmpin | 9:e4df1a31a098 | 178 | { |
Jake867 | 21:0df25c61c475 | 179 | for(int i = 0; i < 32; i++){ |
Jake867 | 21:0df25c61c475 | 180 | if(i<16){ |
Jake867 | 21:0df25c61c475 | 181 | Analog_out_data[i] = 65535; //scaled to 16bit |
Jake867 | 21:0df25c61c475 | 182 | } |
Jake867 | 21:0df25c61c475 | 183 | else{ |
Jake867 | 21:0df25c61c475 | 184 | Analog_out_data[i] = 0; //scaled to 16bit |
Jake867 | 21:0df25c61c475 | 185 | } |
jmpin | 9:e4df1a31a098 | 186 | } |
jmpin | 9:e4df1a31a098 | 187 | } |
jmpin | 9:e4df1a31a098 | 188 | |
jmpin | 12:d60a9d0052a7 | 189 | /* Generates the waveforms that will be output to the AnalogOut pin after being altered by the ADSR coefficient matrices. |
jmpin | 12:d60a9d0052a7 | 190 | The envelope is only applied to sine waves here because when applied to the other wave shapes, the sound does not sounds good. |
jmpin | 12:d60a9d0052a7 | 191 | @param: frequency - the frequency of the waveform to be generated |
jmpin | 12:d60a9d0052a7 | 192 | @param: currentWaveType - the shape of the wave that needs to be generated |
jmpin | 12:d60a9d0052a7 | 193 | */ |
jmpin | 12:d60a9d0052a7 | 194 | |
jmpin | 12:d60a9d0052a7 | 195 | |
jmpin | 9:e4df1a31a098 | 196 | void create_samples(int frequency, WaveType currentWaveType) |
jmpin | 8:f6699fd30737 | 197 | { |
jmpin | 8:f6699fd30737 | 198 | switch(currentWaveType){ |
jmpin | 8:f6699fd30737 | 199 | case sine: |
jmpin | 8:f6699fd30737 | 200 | //Generate sine wave values |
jmpin | 8:f6699fd30737 | 201 | generate_sineWave(frequency); |
jmpin | 24:3bd4e691ae59 | 202 | generate_durations(currentASDR); |
jmpin | 8:f6699fd30737 | 203 | break; |
jmpin | 8:f6699fd30737 | 204 | case square: |
jmpin | 8:f6699fd30737 | 205 | //Generate square wave values |
jmpin | 8:f6699fd30737 | 206 | generate_squareWave(frequency); |
jmpin | 24:3bd4e691ae59 | 207 | generate_durations(currentASDR); |
jmpin | 8:f6699fd30737 | 208 | break; |
jmpin | 8:f6699fd30737 | 209 | case sawtooth: |
jmpin | 8:f6699fd30737 | 210 | //Generate sawtooth wave values |
jmpin | 8:f6699fd30737 | 211 | generate_sawtoothWave(frequency); |
jmpin | 24:3bd4e691ae59 | 212 | generate_durations(currentASDR); |
jmpin | 8:f6699fd30737 | 213 | break; |
jmpin | 8:f6699fd30737 | 214 | default: |
jmpin | 8:f6699fd30737 | 215 | break; |
jmpin | 8:f6699fd30737 | 216 | } |
jmpin | 8:f6699fd30737 | 217 | } |
jmpin | 8:f6699fd30737 | 218 | |
jmpin | 5:afd67e985df0 | 219 | |
jmpin | 0:48311ffdfa96 | 220 | //Interrupt routine to parse message with one new character per serial RX interrupt |
jmpin | 0:48311ffdfa96 | 221 | void parse_message() |
jmpin | 0:48311ffdfa96 | 222 | { |
jmpin | 12:d60a9d0052a7 | 223 | //PC.printf("Parse_message was called"); |
Jake867 | 11:c87f55a3b9e0 | 224 | while(Blue.readable()) |
jmpin | 10:085c49fe2509 | 225 | { |
Jake867 | 11:c87f55a3b9e0 | 226 | keyPress = Blue.getc(); |
Jake867 | 11:c87f55a3b9e0 | 227 | readyFlag = true; |
jmpin | 10:085c49fe2509 | 228 | } |
jmpin | 0:48311ffdfa96 | 229 | } |
jmpin | 3:3aba1d783730 | 230 | |
jmpin | 3:3aba1d783730 | 231 | |
jmpin | 3:3aba1d783730 | 232 | /* |
jmpin | 3:3aba1d783730 | 233 | This function writes which note was just played to a text file on the SDCard. |
jmpin | 3:3aba1d783730 | 234 | The note played will be encoded in hexadecimal, as well as the octave, Attack Value, |
jmpin | 3:3aba1d783730 | 235 | Delay Value, Sustain Value, and Release Value. The format of the bits will be as follows: |
jmpin | 3:3aba1d783730 | 236 | | 3 bits | 3 bits | 3 bits | 3 bits | 3 bits | 3 bits | |
jmpin | 6:68c6a50e1437 | 237 | | Attack | Decay | Susttain | Release | Octave | Note | |
jmpin | 3:3aba1d783730 | 238 | For the 3 bits representing note, A will correspond to 1, B to 2, and so on. |
jmpin | 3:3aba1d783730 | 239 | For example, if the lower 3 bits corresponding to note are 001, then the note is an A. |
jmpin | 3:3aba1d783730 | 240 | |
jmpin | 3:3aba1d783730 | 241 | @param: The note that is being played/recorded into the text file |
jmpin | 3:3aba1d783730 | 242 | */ |
jmpin | 3:3aba1d783730 | 243 | |
jmpin | 3:3aba1d783730 | 244 | void write_to_SDCard(char note) |
jmpin | 3:3aba1d783730 | 245 | { |
jmpin | 6:68c6a50e1437 | 246 | int AttackBits, SustainBits, DecayBits, ReleaseBits, OctaveBits, NoteBits; |
jmpin | 2:f06ba516b1ad | 247 | |
jmpin | 12:d60a9d0052a7 | 248 | AttackBits = currentAttackVal; // Holds the value of the attack parameter |
jmpin | 12:d60a9d0052a7 | 249 | DecayBits = currentDecayVal; // Holds the value of the decay parameter |
jmpin | 12:d60a9d0052a7 | 250 | SustainBits = currentSustainVal;// Holds the value of the sustain parameter |
jmpin | 12:d60a9d0052a7 | 251 | ReleaseBits = currentReleaseVal;// Holds the value of the release parameter |
jmpin | 3:3aba1d783730 | 252 | OctaveBits = currentOctave; |
jmpin | 3:3aba1d783730 | 253 | switch(note){ |
jmpin | 12:d60a9d0052a7 | 254 | case 'C': // a C corresponds to a 3 |
jmpin | 3:3aba1d783730 | 255 | NoteBits = 3; |
jmpin | 3:3aba1d783730 | 256 | break; |
jmpin | 3:3aba1d783730 | 257 | case 'D': |
jmpin | 12:d60a9d0052a7 | 258 | NoteBits = 4; // a D corresponds to a 4 |
jmpin | 3:3aba1d783730 | 259 | break; |
jmpin | 3:3aba1d783730 | 260 | case 'E': |
jmpin | 12:d60a9d0052a7 | 261 | NoteBits = 5; // an E corresponds to a 5 |
jmpin | 3:3aba1d783730 | 262 | break; |
jmpin | 3:3aba1d783730 | 263 | case 'F': |
jmpin | 12:d60a9d0052a7 | 264 | NoteBits = 6; // an F corresponds to a 6 |
jmpin | 3:3aba1d783730 | 265 | break; |
jmpin | 3:3aba1d783730 | 266 | case 'G': |
jmpin | 12:d60a9d0052a7 | 267 | NoteBits = 7; // a G corresponds to a 7 |
jmpin | 3:3aba1d783730 | 268 | break; |
jmpin | 3:3aba1d783730 | 269 | case 'A': |
jmpin | 12:d60a9d0052a7 | 270 | NoteBits = 1; // an A corresponds to a 1 |
jmpin | 3:3aba1d783730 | 271 | break; |
jmpin | 3:3aba1d783730 | 272 | case 'B': |
jmpin | 12:d60a9d0052a7 | 273 | NoteBits = 2; // a B corresponds to a 2 |
jmpin | 3:3aba1d783730 | 274 | break; |
jmpin | 3:3aba1d783730 | 275 | default: |
jmpin | 3:3aba1d783730 | 276 | NoteBits = 0; |
jmpin | 3:3aba1d783730 | 277 | break; |
jmpin | 3:3aba1d783730 | 278 | } |
jmpin | 3:3aba1d783730 | 279 | int writeVal; |
jmpin | 6:68c6a50e1437 | 280 | writeVal = (AttackBits << 15) | (DecayBits << 12) | (SustainBits << 9) | (ReleaseBits << 6) | (OctaveBits << 3) | (NoteBits); |
jmpin | 22:9c80f7bcef86 | 281 | FILE *fp = fopen("/sd/noteRecords/note_record_01.txt", "a"); // creates handle for file we want to write to |
jmpin | 3:3aba1d783730 | 282 | if(fp == NULL) { |
jmpin | 12:d60a9d0052a7 | 283 | error("Could not open file for write\n"); // if this is not a valid name, tell user there is an error |
jmpin | 3:3aba1d783730 | 284 | } |
jmpin | 3:3aba1d783730 | 285 | fprintf(fp,"%X\r\n",writeVal); // writes value to the text file in hexadecimal |
jmpin | 3:3aba1d783730 | 286 | fclose(fp); |
jmpin | 3:3aba1d783730 | 287 | } |
jmpin | 3:3aba1d783730 | 288 | |
jmpin | 0:48311ffdfa96 | 289 | int main() |
jmpin | 0:48311ffdfa96 | 290 | { |
jmpin | 12:d60a9d0052a7 | 291 | Thread thread1(uLCD_Display_Thread); // the thread that displays the current values of the parameters as well as the octave and wave shape |
jmpin | 10:085c49fe2509 | 292 | |
jmpin | 12:d60a9d0052a7 | 293 | |
jmpin | 12:d60a9d0052a7 | 294 | mkdir("/sd/noteRecords", 0777); // make directory to hold the record of notes played |
jmpin | 3:3aba1d783730 | 295 | |
jmpin | 12:d60a9d0052a7 | 296 | initialize_sustainVals(); // fill the lookup tables with the sustain values in them |
jmpin | 24:3bd4e691ae59 | 297 | initialize_ADSRVals(); // fill the lookup tables for ADSR percentages |
Jake867 | 11:c87f55a3b9e0 | 298 | |
jmpin | 12:d60a9d0052a7 | 299 | PC.baud(9600); // setup baud rate for PC serial connection |
jmpin | 12:d60a9d0052a7 | 300 | Blue.baud(9600); // setup baud rate for bluetooth serial connection |
jmpin | 3:3aba1d783730 | 301 | |
jmpin | 12:d60a9d0052a7 | 302 | |
jmpin | 12:d60a9d0052a7 | 303 | Blue.attach(&parse_message,Serial::RxIrq); //attach interrupt function for each new Bluetooth serial character |
jmpin | 0:48311ffdfa96 | 304 | while(1) { |
jmpin | 0:48311ffdfa96 | 305 | //check for a new button message ready |
jmpin | 13:25d53936d385 | 306 | if((keyPress == C_NOTE_KEY) && (readyFlag)){ // Play note C |
jmpin | 12:d60a9d0052a7 | 307 | set_Note_Freq(noteArray[currentOctave-1][0]); // set the note frequency to the proper value |
jmpin | 13:25d53936d385 | 308 | create_samples(noteFreq, myWave); // creates the samples that are going to be output to the waveform |
Jake867 | 23:cf9d43d5a5b4 | 309 | mySpeaker.PlayNote(noteFreq, 2, coefficientMatrix, Analog_out_data); // outputs the samples that are currently in the buffer to p18 |
jmpin | 13:25d53936d385 | 310 | write_to_SDCard('C'); // writes to the SD card |
jmpin | 13:25d53936d385 | 311 | readyFlag = false; // set this flag to false so that the program will not try to process the key press more than once |
jmpin | 13:25d53936d385 | 312 | |
Jake867 | 11:c87f55a3b9e0 | 313 | } |
jmpin | 13:25d53936d385 | 314 | else if((keyPress == D_NOTE_KEY) && (readyFlag)){ // Play note D |
jmpin | 15:8ff317cc5d2c | 315 | set_Note_Freq(noteArray[currentOctave-1][1]); |
jmpin | 15:8ff317cc5d2c | 316 | create_samples(noteFreq, myWave); |
Jake867 | 23:cf9d43d5a5b4 | 317 | mySpeaker.PlayNote(noteFreq, 2, coefficientMatrix, Analog_out_data); |
jmpin | 15:8ff317cc5d2c | 318 | write_to_SDCard('D'); |
jmpin | 15:8ff317cc5d2c | 319 | readyFlag = false; |
jmpin | 13:25d53936d385 | 320 | |
Jake867 | 11:c87f55a3b9e0 | 321 | } |
jmpin | 13:25d53936d385 | 322 | else if((keyPress == E_NOTE_KEY) && (readyFlag)){ // Play note E |
jmpin | 6:68c6a50e1437 | 323 | set_Note_Freq(noteArray[currentOctave-1][2]); |
jmpin | 9:e4df1a31a098 | 324 | create_samples(noteFreq, myWave); |
Jake867 | 23:cf9d43d5a5b4 | 325 | mySpeaker.PlayNote(noteFreq, 2, coefficientMatrix, Analog_out_data); |
jmpin | 3:3aba1d783730 | 326 | write_to_SDCard('E'); |
jmpin | 4:406f59c6a1a6 | 327 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 328 | } |
jmpin | 13:25d53936d385 | 329 | else if((keyPress == F_NOTE_KEY) && (readyFlag)){ // Play note F |
jmpin | 6:68c6a50e1437 | 330 | set_Note_Freq(noteArray[currentOctave-1][3]); |
jmpin | 9:e4df1a31a098 | 331 | create_samples(noteFreq, myWave); |
Jake867 | 23:cf9d43d5a5b4 | 332 | mySpeaker.PlayNote(noteFreq, 2, coefficientMatrix, Analog_out_data); |
jmpin | 3:3aba1d783730 | 333 | write_to_SDCard('F'); |
jmpin | 4:406f59c6a1a6 | 334 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 335 | } |
jmpin | 13:25d53936d385 | 336 | else if((keyPress == G_NOTE_KEY) && (readyFlag)){ // Play note G |
jmpin | 6:68c6a50e1437 | 337 | set_Note_Freq(noteArray[currentOctave-1][4]); |
jmpin | 9:e4df1a31a098 | 338 | create_samples(noteFreq, myWave); |
Jake867 | 23:cf9d43d5a5b4 | 339 | mySpeaker.PlayNote(noteFreq, 2, coefficientMatrix, Analog_out_data); |
jmpin | 3:3aba1d783730 | 340 | write_to_SDCard('G'); |
jmpin | 4:406f59c6a1a6 | 341 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 342 | } |
jmpin | 13:25d53936d385 | 343 | else if((keyPress == A_NOTE_KEY) && (readyFlag)){ // Play note A |
jmpin | 6:68c6a50e1437 | 344 | set_Note_Freq(noteArray[currentOctave][5]); |
jmpin | 9:e4df1a31a098 | 345 | create_samples(noteFreq, myWave); |
Jake867 | 23:cf9d43d5a5b4 | 346 | mySpeaker.PlayNote(noteFreq, 2, coefficientMatrix, Analog_out_data); |
jmpin | 3:3aba1d783730 | 347 | write_to_SDCard('A'); |
jmpin | 4:406f59c6a1a6 | 348 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 349 | } |
jmpin | 15:8ff317cc5d2c | 350 | else if((keyPress == B_NOTE_KEY) && (readyFlag)){ // Play note B |
jmpin | 6:68c6a50e1437 | 351 | set_Note_Freq(noteArray[currentOctave][6]); |
jmpin | 9:e4df1a31a098 | 352 | create_samples(noteFreq, myWave); |
Jake867 | 23:cf9d43d5a5b4 | 353 | mySpeaker.PlayNote(noteFreq, 2, coefficientMatrix, Analog_out_data); |
jmpin | 3:3aba1d783730 | 354 | write_to_SDCard('B'); |
jmpin | 4:406f59c6a1a6 | 355 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 356 | } |
jmpin | 2:f06ba516b1ad | 357 | else if((keyPress == RAISE_OCTAVE_KEY) && (readyFlag)){ // button O pressed |
jmpin | 0:48311ffdfa96 | 358 | // Raise an octave |
jmpin | 6:68c6a50e1437 | 359 | if(currentOctave < 7) |
jmpin | 2:f06ba516b1ad | 360 | currentOctave++; |
jmpin | 4:406f59c6a1a6 | 361 | else |
jmpin | 4:406f59c6a1a6 | 362 | printf("Cannot raise octave above 7.\r\n"); |
Jake867 | 11:c87f55a3b9e0 | 363 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 364 | } |
jmpin | 2:f06ba516b1ad | 365 | else if((keyPress == LOWER_OCTAVE_KEY) && (readyFlag)){ // button L pressed |
jmpin | 2:f06ba516b1ad | 366 | // Lower an octave |
jmpin | 4:406f59c6a1a6 | 367 | if(currentOctave > 1) |
jmpin | 2:f06ba516b1ad | 368 | currentOctave--; |
jmpin | 4:406f59c6a1a6 | 369 | else |
jmpin | 4:406f59c6a1a6 | 370 | printf("Cannot lower octave below 1.\r\n"); |
Jake867 | 11:c87f55a3b9e0 | 371 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 372 | } |
jmpin | 24:3bd4e691ae59 | 373 | |
jmpin | 24:3bd4e691ae59 | 374 | else if((keyPress == RAISE_DURATION_KEY) && (readyFlag)){ // button E pressed |
jmpin | 24:3bd4e691ae59 | 375 | noteDuration++; |
Jake867 | 11:c87f55a3b9e0 | 376 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 377 | } |
jmpin | 24:3bd4e691ae59 | 378 | else if((keyPress == LOWER_DURATION_KEY) && (readyFlag)){ // button D pressed |
jmpin | 24:3bd4e691ae59 | 379 | if(noteDuration >= 2) |
jmpin | 24:3bd4e691ae59 | 380 | noteDuration--; |
jmpin | 4:406f59c6a1a6 | 381 | else |
jmpin | 24:3bd4e691ae59 | 382 | printf("Cannot decrease duration further.\n\r"); |
Jake867 | 11:c87f55a3b9e0 | 383 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 384 | } |
jmpin | 24:3bd4e691ae59 | 385 | else if((keyPress == RAISE_ADSR_KEY) && (readyFlag)){ // button R pressed |
jmpin | 24:3bd4e691ae59 | 386 | // Raise Release Value |
jmpin | 24:3bd4e691ae59 | 387 | if(currentReleaseVal < 5){ |
jmpin | 24:3bd4e691ae59 | 388 | currentADSR++; |
jmpin | 6:68c6a50e1437 | 389 | } |
jmpin | 4:406f59c6a1a6 | 390 | else |
jmpin | 4:406f59c6a1a6 | 391 | printf("Cannot raise value above 5.\r\n"); |
Jake867 | 11:c87f55a3b9e0 | 392 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 393 | } |
jmpin | 24:3bd4e691ae59 | 394 | else if((keyPress == LOWER_ADSR_KEY) && (readyFlag)){ // button F pressed |
jmpin | 0:48311ffdfa96 | 395 | // Lower Release Value |
jmpin | 6:68c6a50e1437 | 396 | if(currentReleaseVal > 1){ |
jmpin | 24:3bd4e691ae59 | 397 | currentADSR--; |
jmpin | 6:68c6a50e1437 | 398 | } |
jmpin | 4:406f59c6a1a6 | 399 | else |
jmpin | 6:68c6a50e1437 | 400 | printf("Cannot lower value below 1.\r\n"); |
Jake867 | 11:c87f55a3b9e0 | 401 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 402 | } |
jmpin | 2:f06ba516b1ad | 403 | else if((keyPress == CHANGE_WAVESHAPE_UP) && (readyFlag)){ // button T pressed |
jmpin | 2:f06ba516b1ad | 404 | // Change waveform shape to next waveform type |
jmpin | 2:f06ba516b1ad | 405 | switch(myWave){ |
jmpin | 2:f06ba516b1ad | 406 | case sine: |
jmpin | 2:f06ba516b1ad | 407 | myWave = square; |
jmpin | 2:f06ba516b1ad | 408 | break; |
jmpin | 2:f06ba516b1ad | 409 | case square: |
jmpin | 2:f06ba516b1ad | 410 | myWave = sawtooth; |
jmpin | 2:f06ba516b1ad | 411 | break; |
jmpin | 2:f06ba516b1ad | 412 | case sawtooth: |
jmpin | 2:f06ba516b1ad | 413 | myWave = sine; |
jmpin | 2:f06ba516b1ad | 414 | break; |
jmpin | 2:f06ba516b1ad | 415 | default: |
jmpin | 2:f06ba516b1ad | 416 | break; |
jmpin | 2:f06ba516b1ad | 417 | } |
Jake867 | 11:c87f55a3b9e0 | 418 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 419 | } |
jmpin | 2:f06ba516b1ad | 420 | else if((keyPress == CHANGE_WAVESHAPE_DOWN) && (readyFlag)){ // button G pressed |
jmpin | 2:f06ba516b1ad | 421 | // Change waveform shape to previous waveform type |
jmpin | 2:f06ba516b1ad | 422 | switch(myWave){ |
jmpin | 2:f06ba516b1ad | 423 | case sine: |
jmpin | 2:f06ba516b1ad | 424 | myWave = sawtooth; |
jmpin | 2:f06ba516b1ad | 425 | break; |
jmpin | 2:f06ba516b1ad | 426 | case square: |
jmpin | 2:f06ba516b1ad | 427 | myWave = sine; |
jmpin | 2:f06ba516b1ad | 428 | break; |
jmpin | 2:f06ba516b1ad | 429 | case sawtooth: |
jmpin | 2:f06ba516b1ad | 430 | myWave = square; |
jmpin | 2:f06ba516b1ad | 431 | break; |
jmpin | 2:f06ba516b1ad | 432 | default: |
jmpin | 2:f06ba516b1ad | 433 | break; |
jmpin | 2:f06ba516b1ad | 434 | } |
Jake867 | 11:c87f55a3b9e0 | 435 | readyFlag = false; |
Jake867 | 11:c87f55a3b9e0 | 436 | |
Jake867 | 11:c87f55a3b9e0 | 437 | } |
jmpin | 10:085c49fe2509 | 438 | } |
jmpin | 0:48311ffdfa96 | 439 | } |