USBMIDI sampled pipe organ uses real pipe organ samples to produce a realistic sound with 16 note polyphony. A serial output will drive external TPIC6A596 shift registers that could be used to drive pipe organ magnets (Solenoid valves)
Dependencies: TextLCD USBDevice mbed
main.cpp@9:b0f110c02b1b, 2015-11-07 (annotated)
- Committer:
- djbottrill
- Date:
- Sat Nov 07 15:04:44 2015 +0000
- Revision:
- 9:b0f110c02b1b
- Parent:
- 8:df5f305aab22
- Child:
- 10:fa2dee836ceb
SW1 clears all playing notes
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
djbottrill | 0:4d06e0867376 | 1 | /* |
djbottrill | 0:4d06e0867376 | 2 | Program to drive organ magnets from a MIDI input |
djbottrill | 0:4d06e0867376 | 3 | From Midi note 36 the notes are send to a 96 bit shift register organ magnet driver board based on 12 x TPIC6B595 shift registers |
djbottrill | 9:b0f110c02b1b | 4 | The program uses the DAC to generate 16 sampled audio channel outputs at up to 32Khz that mirror the solenoid outputs, but also run from |
djbottrill | 0:4d06e0867376 | 5 | MIDI note 24 so the bottom 16' octave can be generated electronically if 16' pipes are not feasible. |
djbottrill | 0:4d06e0867376 | 6 | In fact the sampled output could be tailored to fill in any missing note ranges, |
djbottrill | 0:4d06e0867376 | 7 | Repeated pressing sw3 cycles through a number of display modes. |
djbottrill | 0:4d06e0867376 | 8 | */ |
djbottrill | 0:4d06e0867376 | 9 | #include "mbed.h" |
djbottrill | 0:4d06e0867376 | 10 | |
djbottrill | 5:13a1e5e4494d | 11 | //#include "Rohrflute.h" |
djbottrill | 2:8b22402c0b0f | 12 | //#include "Dubbelflojt.h" |
djbottrill | 2:8b22402c0b0f | 13 | //#include "Principal.h" |
djbottrill | 9:b0f110c02b1b | 14 | //#include "Bourdon.h" |
djbottrill | 9:b0f110c02b1b | 15 | #include "Bourdon_32.h" //This is the best sample 32Khz |
djbottrill | 0:4d06e0867376 | 16 | |
djbottrill | 0:4d06e0867376 | 17 | #include "USBMIDI.h" |
djbottrill | 0:4d06e0867376 | 18 | |
djbottrill | 0:4d06e0867376 | 19 | #include "TextLCD.h" |
djbottrill | 0:4d06e0867376 | 20 | //For Linksprite LCD Shield |
djbottrill | 0:4d06e0867376 | 21 | //TextLCD lcd(PTC12, D9, D4, D5, D6, D7); // rs, e, d4-d7 |
djbottrill | 0:4d06e0867376 | 22 | //DigitalOut bl(D10); |
djbottrill | 0:4d06e0867376 | 23 | //D8 is wrong on K64F definition it is actually PTC12 not PTA0 |
djbottrill | 0:4d06e0867376 | 24 | |
djbottrill | 0:4d06e0867376 | 25 | //For Midas 2x16 OLED Display |
djbottrill | 0:4d06e0867376 | 26 | TextLCD lcd (D2, D3, D4, D5,D6, D7, TextLCD::LCD16x2, NC, NC, TextLCD::WS0010 ); // 4bit bus: RS, E, D4-D7, LCDType=LCD16x2, BL=NC, E2=NC, LCDTCtrl=WS0010 |
djbottrill | 0:4d06e0867376 | 27 | |
djbottrill | 0:4d06e0867376 | 28 | //Serial pc(USBTX, USBRX); // tx, rx |
djbottrill | 0:4d06e0867376 | 29 | |
djbottrill | 0:4d06e0867376 | 30 | AnalogOut Aout(DAC0_OUT); |
djbottrill | 0:4d06e0867376 | 31 | |
djbottrill | 0:4d06e0867376 | 32 | DigitalOut redled(LED1); |
djbottrill | 0:4d06e0867376 | 33 | DigitalOut greenled(LED2); |
djbottrill | 0:4d06e0867376 | 34 | DigitalOut blueled(LED3); |
djbottrill | 0:4d06e0867376 | 35 | |
djbottrill | 0:4d06e0867376 | 36 | DigitalOut diag(D15); |
djbottrill | 0:4d06e0867376 | 37 | DigitalOut diag2(D14); |
djbottrill | 0:4d06e0867376 | 38 | |
djbottrill | 0:4d06e0867376 | 39 | DigitalIn sw1(PTC6); |
djbottrill | 0:4d06e0867376 | 40 | DigitalIn sw3(PTA4); |
djbottrill | 0:4d06e0867376 | 41 | |
djbottrill | 0:4d06e0867376 | 42 | //Wi-Fi connector J6 note pin 3 is incorrectly idenifed in the documentation as PTC12 |
djbottrill | 9:b0f110c02b1b | 43 | //Connects the shift register solenoid driver board |
djbottrill | 0:4d06e0867376 | 44 | DigitalOut SRCK(PTD7); //Shift Register clock |
djbottrill | 0:4d06e0867376 | 45 | DigitalOut RCK(PTD5); //Shift Register latch |
djbottrill | 0:4d06e0867376 | 46 | DigitalOut SER1(PTB20); //Shift Register serial data outout |
djbottrill | 0:4d06e0867376 | 47 | |
djbottrill | 0:4d06e0867376 | 48 | |
djbottrill | 9:b0f110c02b1b | 49 | Ticker output_ticker; //Ticker for sound generation |
djbottrill | 0:4d06e0867376 | 50 | |
djbottrill | 0:4d06e0867376 | 51 | int keybuf[128]= {}; |
djbottrill | 0:4d06e0867376 | 52 | int oldkeybuf[128]= {}; |
djbottrill | 0:4d06e0867376 | 53 | int keystat[128]= {}; |
djbottrill | 0:4d06e0867376 | 54 | int keyidx=0; //Key index //Polyphony counter |
djbottrill | 0:4d06e0867376 | 55 | int outidx=96; //Serial output index |
djbottrill | 0:4d06e0867376 | 56 | |
djbottrill | 0:4d06e0867376 | 57 | int key=0; |
djbottrill | 0:4d06e0867376 | 58 | int velocity=0; |
djbottrill | 0:4d06e0867376 | 59 | int chan=0; |
djbottrill | 0:4d06e0867376 | 60 | int onoff=0; |
djbottrill | 0:4d06e0867376 | 61 | |
djbottrill | 0:4d06e0867376 | 62 | unsigned int audio_out; //Audio output value accumulator |
djbottrill | 0:4d06e0867376 | 63 | |
djbottrill | 0:4d06e0867376 | 64 | //OLELD display bar graph characters |
djbottrill | 0:4d06e0867376 | 65 | const char udc0[] = {0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 66 | const char udc1[] = {0x15, 0x10, 0x10, 0x10, 0x10, 0x10, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 67 | const char udc2[] = {0x15, 0x04, 0x04, 0x04, 0x04, 0x04, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 68 | const char udc3[] = {0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 69 | const char udc4[] = {0x15, 0x01, 0x01, 0x01, 0x01, 0x01, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 70 | const char udc5[] = {0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 71 | const char udc6[] = {0x15, 0x05, 0x05, 0x05, 0x05, 0x05, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 72 | const char udc7[] = {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00}; |
djbottrill | 0:4d06e0867376 | 73 | |
djbottrill | 0:4d06e0867376 | 74 | //Variables for LCD/OLED display |
djbottrill | 0:4d06e0867376 | 75 | unsigned long int lcd_stat=0; |
djbottrill | 0:4d06e0867376 | 76 | unsigned long int lcd_stat_old=1; |
djbottrill | 0:4d06e0867376 | 77 | char display[2][16]; //Display Buffer |
djbottrill | 0:4d06e0867376 | 78 | char display_old[2][16]; //Old Display Buffer |
djbottrill | 0:4d06e0867376 | 79 | int pos=0; //Display Position counter |
djbottrill | 0:4d06e0867376 | 80 | int row=0; |
djbottrill | 0:4d06e0867376 | 81 | int tval=0; |
djbottrill | 0:4d06e0867376 | 82 | int keyidx_t=0; |
djbottrill | 0:4d06e0867376 | 83 | int lcdmode=0; //LCD Display Mode |
djbottrill | 8:df5f305aab22 | 84 | int x =0; |
djbottrill | 8:df5f305aab22 | 85 | int x1=1; |
djbottrill | 9:b0f110c02b1b | 86 | |
djbottrill | 0:4d06e0867376 | 87 | int sw1_count=0; //Switch de-bounce counter |
djbottrill | 0:4d06e0867376 | 88 | int sw1_old=0; |
djbottrill | 0:4d06e0867376 | 89 | int sw1_phase=0; |
djbottrill | 0:4d06e0867376 | 90 | int sw3_count=0; //Switch de-bounce counter |
djbottrill | 0:4d06e0867376 | 91 | int sw3_old=0; |
djbottrill | 0:4d06e0867376 | 92 | int sw3_phase=0; |
djbottrill | 0:4d06e0867376 | 93 | |
djbottrill | 0:4d06e0867376 | 94 | //Sound generator variables |
djbottrill | 0:4d06e0867376 | 95 | int tempidx=0; |
djbottrill | 0:4d06e0867376 | 96 | int freqidx=45; |
djbottrill | 0:4d06e0867376 | 97 | float synth[16]; |
djbottrill | 0:4d06e0867376 | 98 | float synthidx[16]; |
djbottrill | 0:4d06e0867376 | 99 | int synth_old[16]; |
djbottrill | 0:4d06e0867376 | 100 | int synthtab[16]= {}; |
djbottrill | 0:4d06e0867376 | 101 | int synthstat[16]= {}; |
djbottrill | 4:9f63e68b548e | 102 | unsigned char synthoctave[16]= {}; |
djbottrill | 4:9f63e68b548e | 103 | unsigned char synthnote[16]= {}; |
djbottrill | 0:4d06e0867376 | 104 | int noteidx=0; |
djbottrill | 0:4d06e0867376 | 105 | int i; |
djbottrill | 0:4d06e0867376 | 106 | int ii; |
djbottrill | 9:b0f110c02b1b | 107 | int cl; |
djbottrill | 0:4d06e0867376 | 108 | |
djbottrill | 0:4d06e0867376 | 109 | /* |
djbottrill | 0:4d06e0867376 | 110 | Ticker routine to calculate and output the audio signal. |
djbottrill | 0:4d06e0867376 | 111 | As the DAC is 12 bit this allows for 16 concurrennt 8 bit samples running with no additional loss of precision. |
djbottrill | 0:4d06e0867376 | 112 | The samples should be normalised to maximise the 8 bit range as only one sample is used there is no need to generate sounds with different amplitude. |
djbottrill | 5:13a1e5e4494d | 113 | Sound Generation is in 4 states stored in synthstat: |
djbottrill | 0:4d06e0867376 | 114 | 0 = Synth Channel idle |
djbottrill | 0:4d06e0867376 | 115 | 1 = Attack / Sustain phase note running and looping if necessary |
djbottrill | 5:13a1e5e4494d | 116 | 2 = Signal to start decay this may be delayed until the sound is paat the initial attack point typically 100-200 mS |
djbottrill | 0:4d06e0867376 | 117 | 3 = Sample is in the decay phase. |
djbottrill | 0:4d06e0867376 | 118 | |
djbottrill | 5:13a1e5e4494d | 119 | This routine also handles the Synchronous output to a 96 bit shift register Organ Pallet magnet driver board, one bit is sent per tick. |
djbottrill | 0:4d06e0867376 | 120 | The data clock pulse is generated during the 16 channel synth scan and the final latch pulse is generated on the 96th Tick. |
djbottrill | 0:4d06e0867376 | 121 | All 96 bits are clocked out in around 4.4mS. |
djbottrill | 0:4d06e0867376 | 122 | */ |
djbottrill | 0:4d06e0867376 | 123 | void aout() |
djbottrill | 0:4d06e0867376 | 124 | { |
djbottrill | 4:9f63e68b548e | 125 | diag=1; //Pulse DIAG Pin for Scoping purposes IE pin high |
djbottrill | 0:4d06e0867376 | 126 | redled=0; //Pulse Red LED to indicate Ticker working |
djbottrill | 0:4d06e0867376 | 127 | audio_out=0; //Clear Audio Accumulator |
djbottrill | 0:4d06e0867376 | 128 | |
djbottrill | 0:4d06e0867376 | 129 | SER1=keybuf[outidx+12]; //Send bit serially |
djbottrill | 0:4d06e0867376 | 130 | |
djbottrill | 0:4d06e0867376 | 131 | for (i =0; i<16; i++) { //Do 16 channels |
djbottrill | 4:9f63e68b548e | 132 | switch (synthstat[i]) { |
djbottrill | 4:9f63e68b548e | 133 | case 1: //Sustain phase |
djbottrill | 4:9f63e68b548e | 134 | if (synth[i]>sample_loop_end[synthoctave[i]]) { //Got to end of buffer? |
djbottrill | 4:9f63e68b548e | 135 | synth[i]=sample_loop_start[synthoctave[i]]; //Wrap around back to start |
djbottrill | 4:9f63e68b548e | 136 | } |
djbottrill | 4:9f63e68b548e | 137 | break; |
djbottrill | 5:13a1e5e4494d | 138 | case 2: //Note off demand state |
djbottrill | 0:4d06e0867376 | 139 | if (synth[i]>=sample_attack[synthoctave[i]]) { //Delay decay phase if not past end of attack |
djbottrill | 0:4d06e0867376 | 140 | //Check if the waveform is close to zero crossing this helps eliminate clicks looks for rising edge approaching 0x80 |
djbottrill | 0:4d06e0867376 | 141 | tempidx=synth[i]; |
djbottrill | 5:13a1e5e4494d | 142 | if (sample[synthoctave[i]][tempidx]<128 & sample[synthoctave[i]][tempidx]>120) { |
djbottrill | 0:4d06e0867376 | 143 | if (sample[synthoctave[i]][tempidx]>synth_old[i]) { |
djbottrill | 7:e1ea1623c6c2 | 144 | synth[i]=sample_loop_off[synthoctave[i]]; //Jump to start of decay |
djbottrill | 7:e1ea1623c6c2 | 145 | synthstat[i]=3; //Say note in decay |
djbottrill | 0:4d06e0867376 | 146 | } |
djbottrill | 0:4d06e0867376 | 147 | } |
djbottrill | 0:4d06e0867376 | 148 | } |
djbottrill | 4:9f63e68b548e | 149 | break; |
djbottrill | 7:e1ea1623c6c2 | 150 | case 3: //Check if decay has completed |
djbottrill | 8:df5f305aab22 | 151 | if (synth[i]>=sample_len[synthoctave[i]]) { //End of decay? |
djbottrill | 8:df5f305aab22 | 152 | synthstat[i]=0; //say channel free |
djbottrill | 8:df5f305aab22 | 153 | synth[i]=0; //Set sample pointer to 0 |
djbottrill | 8:df5f305aab22 | 154 | synthidx[i]=0; //Set sample index to 0 |
djbottrill | 8:df5f305aab22 | 155 | synthtab[i]=255; //Set to invalid |
djbottrill | 7:e1ea1623c6c2 | 156 | } |
djbottrill | 7:e1ea1623c6c2 | 157 | break ; |
djbottrill | 0:4d06e0867376 | 158 | } |
djbottrill | 4:9f63e68b548e | 159 | |
djbottrill | 4:9f63e68b548e | 160 | //get sample and add to Audio Accumulator |
djbottrill | 8:df5f305aab22 | 161 | synth_old[i]=sample[synthoctave[i]][(int)(synth[i])]; //Get and save old sample |
djbottrill | 0:4d06e0867376 | 162 | audio_out=audio_out+synth_old[i]; //add sample to audio out accumulator |
djbottrill | 0:4d06e0867376 | 163 | synth[i]=synth[i]+synthidx[i]; //Get next sample pointer |
djbottrill | 0:4d06e0867376 | 164 | |
djbottrill | 0:4d06e0867376 | 165 | |
djbottrill | 0:4d06e0867376 | 166 | //Generate clock pulses to send data serially |
djbottrill | 4:9f63e68b548e | 167 | switch (i) { |
djbottrill | 4:9f63e68b548e | 168 | case 2: |
djbottrill | 4:9f63e68b548e | 169 | SRCK=1; //Generate serial output clock pulse |
djbottrill | 4:9f63e68b548e | 170 | break; |
djbottrill | 4:9f63e68b548e | 171 | case 5: |
djbottrill | 4:9f63e68b548e | 172 | SRCK=0; |
djbottrill | 4:9f63e68b548e | 173 | break; |
djbottrill | 4:9f63e68b548e | 174 | case 10: |
djbottrill | 4:9f63e68b548e | 175 | if (outidx==0) { |
djbottrill | 4:9f63e68b548e | 176 | RCK=1; //Generate latch strobe after 96 bits sent |
djbottrill | 4:9f63e68b548e | 177 | } |
djbottrill | 4:9f63e68b548e | 178 | break; |
djbottrill | 4:9f63e68b548e | 179 | case 15: |
djbottrill | 4:9f63e68b548e | 180 | if (outidx==0) { |
djbottrill | 4:9f63e68b548e | 181 | RCK=0; //Generate latch strobe after 96 bits sent |
djbottrill | 4:9f63e68b548e | 182 | outidx=96; |
djbottrill | 4:9f63e68b548e | 183 | } |
djbottrill | 4:9f63e68b548e | 184 | break; |
djbottrill | 0:4d06e0867376 | 185 | } |
djbottrill | 4:9f63e68b548e | 186 | |
djbottrill | 0:4d06e0867376 | 187 | } //Next Note |
djbottrill | 0:4d06e0867376 | 188 | outidx--; //Next serial data bit |
djbottrill | 0:4d06e0867376 | 189 | |
djbottrill | 8:df5f305aab22 | 190 | |
djbottrill | 0:4d06e0867376 | 191 | //Output to DAC |
djbottrill | 0:4d06e0867376 | 192 | Aout.write_u16(audio_out*16); |
djbottrill | 7:e1ea1623c6c2 | 193 | |
djbottrill | 0:4d06e0867376 | 194 | redled=1; |
djbottrill | 0:4d06e0867376 | 195 | diag=0; |
djbottrill | 0:4d06e0867376 | 196 | } |
djbottrill | 0:4d06e0867376 | 197 | |
djbottrill | 0:4d06e0867376 | 198 | /* |
djbottrill | 0:4d06e0867376 | 199 | Interrupt routine to receive MIDI on/off message and set LED status accordingly |
djbottrill | 0:4d06e0867376 | 200 | MIDI note on/off events directly start/stop the synth channels and store the note status in keytab. |
djbottrill | 0:4d06e0867376 | 201 | */ |
djbottrill | 0:4d06e0867376 | 202 | void get_message(MIDIMessage msg) |
djbottrill | 0:4d06e0867376 | 203 | { |
djbottrill | 0:4d06e0867376 | 204 | greenled=0; //Pulse Green LED to indicate MIDI activity |
djbottrill | 0:4d06e0867376 | 205 | key=msg.key(); |
djbottrill | 0:4d06e0867376 | 206 | velocity=msg.velocity(); |
djbottrill | 0:4d06e0867376 | 207 | chan=msg.channel(); |
djbottrill | 0:4d06e0867376 | 208 | switch (msg.type()) { |
djbottrill | 0:4d06e0867376 | 209 | case MIDIMessage::NoteOnType: //MIDI note on received |
djbottrill | 8:df5f305aab22 | 210 | if (key>23 & key<120) { |
djbottrill | 0:4d06e0867376 | 211 | onoff=1; |
djbottrill | 0:4d06e0867376 | 212 | keybuf[(key-24)]=1; //Store in keybuf, except for notes 24-35 |
djbottrill | 0:4d06e0867376 | 213 | //Process keys on |
djbottrill | 0:4d06e0867376 | 214 | //Find a free note generator and start the note playing, if no slots available just ignore the note |
djbottrill | 0:4d06e0867376 | 215 | for (ii=0; ii<16; ii++) { |
djbottrill | 5:13a1e5e4494d | 216 | if (synthtab[ii]==(key-24) & synthstat[ii]>0) { //Is synth already playing the note? |
djbottrill | 6:073e10217962 | 217 | synth[ii]=0; //Set sample pointer to 0 |
djbottrill | 5:13a1e5e4494d | 218 | synthstat[ii]=1; //Restart the note |
djbottrill | 5:13a1e5e4494d | 219 | break; //exit loop |
djbottrill | 5:13a1e5e4494d | 220 | } |
djbottrill | 5:13a1e5e4494d | 221 | if (synthstat[ii]==0) { //Is synth channel free? |
djbottrill | 0:4d06e0867376 | 222 | synthtab[ii]=key-24; //Store note value |
djbottrill | 0:4d06e0867376 | 223 | synthoctave[ii]=synthtab[ii]/12; //Store the octave |
djbottrill | 4:9f63e68b548e | 224 | synthnote[ii]= synthtab[ii]%12; //Note within the octave |
djbottrill | 0:4d06e0867376 | 225 | synthstat[ii]=1; //Set status to playing |
djbottrill | 0:4d06e0867376 | 226 | synthidx[ii]=freqtab[synthnote[ii]]; //Set the frequency |
djbottrill | 5:13a1e5e4494d | 227 | break; //exit loop |
djbottrill | 0:4d06e0867376 | 228 | } //Next Synth slot |
djbottrill | 0:4d06e0867376 | 229 | } |
djbottrill | 0:4d06e0867376 | 230 | } |
djbottrill | 6:073e10217962 | 231 | |
djbottrill | 0:4d06e0867376 | 232 | break; |
djbottrill | 0:4d06e0867376 | 233 | |
djbottrill | 0:4d06e0867376 | 234 | //Process keys off |
djbottrill | 0:4d06e0867376 | 235 | case MIDIMessage::NoteOffType: //Midi note off received |
djbottrill | 0:4d06e0867376 | 236 | if (key>23) { |
djbottrill | 0:4d06e0867376 | 237 | onoff=0; |
djbottrill | 0:4d06e0867376 | 238 | keybuf[(key-24)]=0; //Update keybuf |
djbottrill | 0:4d06e0867376 | 239 | for (ii=0; ii<16; ii++) { |
djbottrill | 5:13a1e5e4494d | 240 | if (synthstat[ii]==1 & synthtab[ii]==(key-24)) { //Note currently playing |
djbottrill | 0:4d06e0867376 | 241 | synthstat[ii]=2; //Set Start decay |
djbottrill | 5:13a1e5e4494d | 242 | break; //Exit loop |
djbottrill | 0:4d06e0867376 | 243 | } |
djbottrill | 0:4d06e0867376 | 244 | } |
djbottrill | 0:4d06e0867376 | 245 | } |
djbottrill | 0:4d06e0867376 | 246 | break; |
djbottrill | 0:4d06e0867376 | 247 | |
djbottrill | 0:4d06e0867376 | 248 | //Process all notes off command |
djbottrill | 0:4d06e0867376 | 249 | case MIDIMessage::AllNotesOffType: //Midi all notes off |
djbottrill | 0:4d06e0867376 | 250 | for (ii=0; ii<108; i++) { |
djbottrill | 0:4d06e0867376 | 251 | keybuf[ii]=0; //Clear Keybuf |
djbottrill | 0:4d06e0867376 | 252 | } |
djbottrill | 0:4d06e0867376 | 253 | for (ii=0; ii>16; ii++) { //Kill any sampled notes playing |
djbottrill | 0:4d06e0867376 | 254 | synthstat[ii]=0; //say channel free |
djbottrill | 0:4d06e0867376 | 255 | synth[ii]=0; //Set sample pointer to 0 |
djbottrill | 0:4d06e0867376 | 256 | synthidx[ii]=0; //Set sample index to 0 |
djbottrill | 0:4d06e0867376 | 257 | synthtab[ii]=255; //Set to invalid |
djbottrill | 0:4d06e0867376 | 258 | } |
djbottrill | 0:4d06e0867376 | 259 | break; |
djbottrill | 4:9f63e68b548e | 260 | |
djbottrill | 0:4d06e0867376 | 261 | //Any other MIDI Commands just ignore |
djbottrill | 0:4d06e0867376 | 262 | default: |
djbottrill | 0:4d06e0867376 | 263 | break; |
djbottrill | 0:4d06e0867376 | 264 | } |
djbottrill | 0:4d06e0867376 | 265 | greenled=1; |
djbottrill | 0:4d06e0867376 | 266 | } |
djbottrill | 0:4d06e0867376 | 267 | |
djbottrill | 0:4d06e0867376 | 268 | |
djbottrill | 0:4d06e0867376 | 269 | int main() |
djbottrill | 0:4d06e0867376 | 270 | { |
djbottrill | 0:4d06e0867376 | 271 | greenled=1; |
djbottrill | 0:4d06e0867376 | 272 | redled=1; |
djbottrill | 0:4d06e0867376 | 273 | blueled=1; |
djbottrill | 0:4d06e0867376 | 274 | SRCK=0; //Serial Clock low |
djbottrill | 0:4d06e0867376 | 275 | RCK=0; //Latch Clock low |
djbottrill | 0:4d06e0867376 | 276 | |
djbottrill | 0:4d06e0867376 | 277 | sw1.mode(PullUp); |
djbottrill | 0:4d06e0867376 | 278 | sw3.mode(PullUp); |
djbottrill | 0:4d06e0867376 | 279 | |
djbottrill | 0:4d06e0867376 | 280 | output_ticker.attach(&aout, sample_rate); //Set Sample frequency |
djbottrill | 0:4d06e0867376 | 281 | |
djbottrill | 0:4d06e0867376 | 282 | lcd.cls(); |
djbottrill | 0:4d06e0867376 | 283 | wait(0.1); |
djbottrill | 0:4d06e0867376 | 284 | lcd.setCursor(TextLCD::CurOff_BlkOff); |
djbottrill | 0:4d06e0867376 | 285 | lcd.cls(); |
djbottrill | 0:4d06e0867376 | 286 | lcd.printf("MIDI Pipe Organ Waiting for USB"); |
djbottrill | 0:4d06e0867376 | 287 | |
djbottrill | 0:4d06e0867376 | 288 | NVIC_SetPriority(USB0_IRQn, 99); //Reduce Interrupt priority of USB |
djbottrill | 0:4d06e0867376 | 289 | |
djbottrill | 0:4d06e0867376 | 290 | USBMIDI midi; //Start up MIDI |
djbottrill | 0:4d06e0867376 | 291 | midi.attach(get_message); //callback for MIDI messages received |
djbottrill | 0:4d06e0867376 | 292 | |
djbottrill | 0:4d06e0867376 | 293 | lcd.cls(); |
djbottrill | 0:4d06e0867376 | 294 | lcd.printf("MIDI Pipe Organ"); |
djbottrill | 0:4d06e0867376 | 295 | wait(1); |
djbottrill | 0:4d06e0867376 | 296 | lcd.cls(); |
djbottrill | 0:4d06e0867376 | 297 | lcd.printf("On Chan Note Vel"); |
djbottrill | 0:4d06e0867376 | 298 | //Program user defined characters into OLED display for bar graph |
djbottrill | 0:4d06e0867376 | 299 | lcd.setUDC(0, (char *) udc0); |
djbottrill | 0:4d06e0867376 | 300 | lcd.setUDC(1, (char *) udc1); |
djbottrill | 0:4d06e0867376 | 301 | lcd.setUDC(2, (char *) udc2); |
djbottrill | 0:4d06e0867376 | 302 | lcd.setUDC(3, (char *) udc3); |
djbottrill | 0:4d06e0867376 | 303 | lcd.setUDC(4, (char *) udc4); |
djbottrill | 0:4d06e0867376 | 304 | lcd.setUDC(5, (char *) udc5); |
djbottrill | 0:4d06e0867376 | 305 | lcd.setUDC(6, (char *) udc6); |
djbottrill | 0:4d06e0867376 | 306 | lcd.setUDC(7, (char *) udc7); |
djbottrill | 0:4d06e0867376 | 307 | |
djbottrill | 0:4d06e0867376 | 308 | key=0; |
djbottrill | 0:4d06e0867376 | 309 | velocity=0; |
djbottrill | 0:4d06e0867376 | 310 | chan=0; |
djbottrill | 0:4d06e0867376 | 311 | onoff=0; |
djbottrill | 0:4d06e0867376 | 312 | |
djbottrill | 0:4d06e0867376 | 313 | //Main Loop |
djbottrill | 0:4d06e0867376 | 314 | while(1) { |
djbottrill | 0:4d06e0867376 | 315 | |
djbottrill | 7:e1ea1623c6c2 | 316 | /* |
djbottrill | 7:e1ea1623c6c2 | 317 | Additional code to de-bounce the K64F onboard switches again using multiple ticks to de-bounce; has 4 states: |
djbottrill | 7:e1ea1623c6c2 | 318 | 0 - Button not pressed |
djbottrill | 7:e1ea1623c6c2 | 319 | 1 - Button pressed waiting for de-bounce count of 100 ticks (4.53 mS) |
djbottrill | 7:e1ea1623c6c2 | 320 | 2 - Button press stable, this staus can be read as the de-bounced status indicating the button press is clean |
djbottrill | 7:e1ea1623c6c2 | 321 | */ |
djbottrill | 6:073e10217962 | 322 | // De-bounce SW1 |
djbottrill | 9:b0f110c02b1b | 323 | if (sw1_phase==0 & sw1==0) { //Button just been pressed |
djbottrill | 6:073e10217962 | 324 | sw1_phase=1; |
djbottrill | 6:073e10217962 | 325 | sw1_count=10; |
djbottrill | 6:073e10217962 | 326 | } |
djbottrill | 9:b0f110c02b1b | 327 | if (sw1_phase==1 & sw1_count==0 & sw1==0) { //Button still pressed after de-bounce period |
djbottrill | 6:073e10217962 | 328 | sw1_phase=2; |
djbottrill | 6:073e10217962 | 329 | } |
djbottrill | 9:b0f110c02b1b | 330 | if (sw1_phase==2 & sw1==1) { //Button released |
djbottrill | 6:073e10217962 | 331 | sw1_phase=0; |
djbottrill | 6:073e10217962 | 332 | } |
djbottrill | 6:073e10217962 | 333 | sw1_count--; |
djbottrill | 6:073e10217962 | 334 | // De-bounce SW1 |
djbottrill | 9:b0f110c02b1b | 335 | if (sw3_phase==0 & sw3==0) { //Button just been pressed |
djbottrill | 7:e1ea1623c6c2 | 336 | sw3_phase=1; |
djbottrill | 7:e1ea1623c6c2 | 337 | sw3_count=10; |
djbottrill | 7:e1ea1623c6c2 | 338 | } |
djbottrill | 9:b0f110c02b1b | 339 | if (sw3_phase==1 & sw3_count==0 & sw3==0) { //Button still pressed after de-bounce period |
djbottrill | 7:e1ea1623c6c2 | 340 | sw3_phase=2; |
djbottrill | 7:e1ea1623c6c2 | 341 | } |
djbottrill | 6:073e10217962 | 342 | |
djbottrill | 9:b0f110c02b1b | 343 | if (sw3_phase==2 & sw3==1) { //Button released |
djbottrill | 7:e1ea1623c6c2 | 344 | sw3_phase=0; |
djbottrill | 7:e1ea1623c6c2 | 345 | } |
djbottrill | 7:e1ea1623c6c2 | 346 | sw3_count--; |
djbottrill | 6:073e10217962 | 347 | |
djbottrill | 6:073e10217962 | 348 | |
djbottrill | 6:073e10217962 | 349 | |
djbottrill | 6:073e10217962 | 350 | |
djbottrill | 0:4d06e0867376 | 351 | if (sw1_phase==2 | sw3_phase==2) { |
djbottrill | 0:4d06e0867376 | 352 | blueled=0; |
djbottrill | 0:4d06e0867376 | 353 | } else { |
djbottrill | 0:4d06e0867376 | 354 | blueled=1; |
djbottrill | 0:4d06e0867376 | 355 | } |
djbottrill | 0:4d06e0867376 | 356 | |
djbottrill | 0:4d06e0867376 | 357 | |
djbottrill | 9:b0f110c02b1b | 358 | //Button 1 will clear all playing notes |
djbottrill | 9:b0f110c02b1b | 359 | if (sw1_phase != sw1_old) { |
djbottrill | 9:b0f110c02b1b | 360 | if(sw1_phase==2) { |
djbottrill | 9:b0f110c02b1b | 361 | for (cl=0; cl<108; cl++) { |
djbottrill | 9:b0f110c02b1b | 362 | keybuf[cl]=0; //Clear Keybuf |
djbottrill | 9:b0f110c02b1b | 363 | } |
djbottrill | 9:b0f110c02b1b | 364 | for (cl=0; cl<16; cl++) { //say channel free |
djbottrill | 9:b0f110c02b1b | 365 | synth[cl]=0; //Set sample pointer to 0 |
djbottrill | 9:b0f110c02b1b | 366 | synthidx[cl]=0; //Set sample index to 0 |
djbottrill | 9:b0f110c02b1b | 367 | synthtab[cl]=255; //Set to invalid |
djbottrill | 9:b0f110c02b1b | 368 | } |
djbottrill | 9:b0f110c02b1b | 369 | } |
djbottrill | 9:b0f110c02b1b | 370 | } |
djbottrill | 9:b0f110c02b1b | 371 | |
djbottrill | 9:b0f110c02b1b | 372 | |
djbottrill | 0:4d06e0867376 | 373 | //Check for display mode button being presed |
djbottrill | 9:b0f110c02b1b | 374 | if (sw3_phase != sw3_old) { //Mode Switch pressed |
djbottrill | 0:4d06e0867376 | 375 | if(sw3_phase==2) { |
djbottrill | 0:4d06e0867376 | 376 | lcdmode++; |
djbottrill | 8:df5f305aab22 | 377 | if (lcdmode>3) { |
djbottrill | 0:4d06e0867376 | 378 | lcdmode=0; |
djbottrill | 0:4d06e0867376 | 379 | } |
djbottrill | 0:4d06e0867376 | 380 | lcd.cls(); |
djbottrill | 0:4d06e0867376 | 381 | if (lcdmode==0) { |
djbottrill | 0:4d06e0867376 | 382 | lcd.printf("On Chan Note Vel"); |
djbottrill | 0:4d06e0867376 | 383 | } |
djbottrill | 0:4d06e0867376 | 384 | if (lcdmode==1) { |
djbottrill | 0:4d06e0867376 | 385 | //Initialise bar graph display |
djbottrill | 0:4d06e0867376 | 386 | |
djbottrill | 0:4d06e0867376 | 387 | for (row=0; row<2; row++) { |
djbottrill | 0:4d06e0867376 | 388 | for (pos=0; pos<16; pos++) { |
djbottrill | 0:4d06e0867376 | 389 | display[row][pos]=0; |
djbottrill | 0:4d06e0867376 | 390 | display_old[row][pos]=1; |
djbottrill | 0:4d06e0867376 | 391 | } |
djbottrill | 0:4d06e0867376 | 392 | } |
djbottrill | 0:4d06e0867376 | 393 | } |
djbottrill | 0:4d06e0867376 | 394 | if (lcdmode==2) { |
djbottrill | 0:4d06e0867376 | 395 | lcd.locate(0,1); |
djbottrill | 0:4d06e0867376 | 396 | lcd.printf("0123456789ABCDEF"); |
djbottrill | 0:4d06e0867376 | 397 | } |
djbottrill | 8:df5f305aab22 | 398 | if (lcdmode==3) { |
djbottrill | 8:df5f305aab22 | 399 | lcd.cls(); |
djbottrill | 8:df5f305aab22 | 400 | lcd.locate(0,0); |
djbottrill | 8:df5f305aab22 | 401 | lcd.printf("Utilisation:"); |
djbottrill | 8:df5f305aab22 | 402 | } |
djbottrill | 0:4d06e0867376 | 403 | } |
djbottrill | 0:4d06e0867376 | 404 | } |
djbottrill | 0:4d06e0867376 | 405 | sw3_old=sw3_phase; |
djbottrill | 0:4d06e0867376 | 406 | |
djbottrill | 0:4d06e0867376 | 407 | |
djbottrill | 0:4d06e0867376 | 408 | |
djbottrill | 0:4d06e0867376 | 409 | // OLED MIDI Status display |
djbottrill | 0:4d06e0867376 | 410 | if (lcdmode==0) { |
djbottrill | 0:4d06e0867376 | 411 | lcd_stat=key+(128*velocity)+(16384*chan)+(262144*onoff); |
djbottrill | 0:4d06e0867376 | 412 | if (lcd_stat!=lcd_stat_old) { |
djbottrill | 0:4d06e0867376 | 413 | |
djbottrill | 0:4d06e0867376 | 414 | lcd.locate(0,1); |
djbottrill | 0:4d06e0867376 | 415 | lcd.printf("%1d %2d %3d %3d", onoff, chan, key, velocity); |
djbottrill | 0:4d06e0867376 | 416 | lcd_stat_old=lcd_stat; |
djbottrill | 0:4d06e0867376 | 417 | } |
djbottrill | 0:4d06e0867376 | 418 | } |
djbottrill | 0:4d06e0867376 | 419 | |
djbottrill | 0:4d06e0867376 | 420 | // OLED MIDI Bar Display |
djbottrill | 0:4d06e0867376 | 421 | if (lcdmode==1) { |
djbottrill | 0:4d06e0867376 | 422 | keyidx=0; |
djbottrill | 0:4d06e0867376 | 423 | for (row=1; row>=0; row--) { |
djbottrill | 0:4d06e0867376 | 424 | for (pos=0; pos<16; pos++) { |
djbottrill | 0:4d06e0867376 | 425 | keyidx_t=keyidx*2; |
djbottrill | 0:4d06e0867376 | 426 | if(keyidx_t>94) { |
djbottrill | 0:4d06e0867376 | 427 | keyidx_t=keyidx_t-95; |
djbottrill | 0:4d06e0867376 | 428 | } |
djbottrill | 0:4d06e0867376 | 429 | tval=keybuf[keyidx_t]; |
djbottrill | 0:4d06e0867376 | 430 | keyidx++; |
djbottrill | 0:4d06e0867376 | 431 | keyidx_t=keyidx*2; |
djbottrill | 0:4d06e0867376 | 432 | if(keyidx_t>94) { |
djbottrill | 0:4d06e0867376 | 433 | keyidx_t=keyidx_t-95; |
djbottrill | 0:4d06e0867376 | 434 | } |
djbottrill | 0:4d06e0867376 | 435 | tval=tval+(2*keybuf[keyidx_t]); |
djbottrill | 0:4d06e0867376 | 436 | keyidx++; |
djbottrill | 0:4d06e0867376 | 437 | |
djbottrill | 0:4d06e0867376 | 438 | keyidx_t=keyidx*2; |
djbottrill | 0:4d06e0867376 | 439 | if(keyidx_t>94) { |
djbottrill | 0:4d06e0867376 | 440 | keyidx_t=keyidx_t-95; |
djbottrill | 0:4d06e0867376 | 441 | } |
djbottrill | 0:4d06e0867376 | 442 | tval=tval+(4*keybuf[keyidx_t]); |
djbottrill | 0:4d06e0867376 | 443 | keyidx++; |
djbottrill | 0:4d06e0867376 | 444 | display[row][pos]=tval; |
djbottrill | 0:4d06e0867376 | 445 | |
djbottrill | 0:4d06e0867376 | 446 | if(display[row][pos]!=display_old[row][pos]) { |
djbottrill | 0:4d06e0867376 | 447 | lcd.locate(pos,row); |
djbottrill | 0:4d06e0867376 | 448 | lcd.putc(display[row][pos]); |
djbottrill | 0:4d06e0867376 | 449 | display_old[row][pos]=display[row][pos]; |
djbottrill | 0:4d06e0867376 | 450 | } |
djbottrill | 0:4d06e0867376 | 451 | } |
djbottrill | 0:4d06e0867376 | 452 | } |
djbottrill | 0:4d06e0867376 | 453 | } |
djbottrill | 0:4d06e0867376 | 454 | |
djbottrill | 0:4d06e0867376 | 455 | //Display status of the Synth channels |
djbottrill | 0:4d06e0867376 | 456 | if (lcdmode==2) { |
djbottrill | 0:4d06e0867376 | 457 | lcd.locate(0,0); |
djbottrill | 0:4d06e0867376 | 458 | for (noteidx=0; noteidx<16; noteidx++) { |
djbottrill | 0:4d06e0867376 | 459 | lcd.putc((synthstat[noteidx]+48)); |
djbottrill | 0:4d06e0867376 | 460 | } |
djbottrill | 0:4d06e0867376 | 461 | } |
djbottrill | 4:9f63e68b548e | 462 | |
djbottrill | 8:df5f305aab22 | 463 | //Display utilisation bar graph |
djbottrill | 8:df5f305aab22 | 464 | if (lcdmode==3) { |
djbottrill | 8:df5f305aab22 | 465 | x=0; |
djbottrill | 8:df5f305aab22 | 466 | for (noteidx=0; noteidx<16; noteidx++) { |
djbottrill | 8:df5f305aab22 | 467 | if (synthstat[noteidx] >0) { |
djbottrill | 8:df5f305aab22 | 468 | x++; |
djbottrill | 8:df5f305aab22 | 469 | } |
djbottrill | 8:df5f305aab22 | 470 | } |
djbottrill | 8:df5f305aab22 | 471 | for (pos=0; pos<x; pos++) { |
djbottrill | 8:df5f305aab22 | 472 | display[1][pos]=0xff; |
djbottrill | 8:df5f305aab22 | 473 | } |
djbottrill | 8:df5f305aab22 | 474 | while(pos<16) { |
djbottrill | 8:df5f305aab22 | 475 | display[1][pos]=0x20; |
djbottrill | 8:df5f305aab22 | 476 | pos++; |
djbottrill | 8:df5f305aab22 | 477 | } |
djbottrill | 8:df5f305aab22 | 478 | row=1; |
djbottrill | 8:df5f305aab22 | 479 | for (pos=0; pos<16; pos++) { |
djbottrill | 8:df5f305aab22 | 480 | if (x!=x1) { |
djbottrill | 8:df5f305aab22 | 481 | lcd.locate(13,0); |
djbottrill | 8:df5f305aab22 | 482 | lcd.printf("%2d", x); |
djbottrill | 8:df5f305aab22 | 483 | x1=x; |
djbottrill | 8:df5f305aab22 | 484 | } |
djbottrill | 8:df5f305aab22 | 485 | if(display[row][pos]!=display_old[row][pos]) { |
djbottrill | 8:df5f305aab22 | 486 | lcd.locate(pos,row); |
djbottrill | 8:df5f305aab22 | 487 | lcd.putc(display[row][pos]); |
djbottrill | 8:df5f305aab22 | 488 | display_old[row][pos]=display[row][pos]; |
djbottrill | 8:df5f305aab22 | 489 | } |
djbottrill | 8:df5f305aab22 | 490 | } |
djbottrill | 8:df5f305aab22 | 491 | } |
djbottrill | 8:df5f305aab22 | 492 | |
djbottrill | 8:df5f305aab22 | 493 | |
djbottrill | 8:df5f305aab22 | 494 | |
djbottrill | 0:4d06e0867376 | 495 | } //End of main loop |
djbottrill | 0:4d06e0867376 | 496 | } //End of program |
djbottrill | 0:4d06e0867376 | 497 | |
djbottrill | 0:4d06e0867376 | 498 | |
djbottrill | 0:4d06e0867376 | 499 | |
djbottrill | 0:4d06e0867376 | 500 |