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
00001 /* 00002 Program to drive organ magnets from a MIDI input 00003 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 00004 The program uses the DAC to generate 16 sampled audio channel outputs at up to 44.1Khz that mirror the solenoid outputs, but also run from 00005 MIDI note 24 so the bottom 16' octave can be generated electronically if 16' pipes are not feasible. 00006 In fact the sampled output could be tailored to fill in any missing note ranges, 00007 Repeated pressing sw3 cycles through a number of display modes. 00008 Pressing sw1 switches between two sound samples Bourdon and Montre only one rank is availble at any one time. 00009 This program is currently only compatible with the K64F as it's one of the few MBED boards that has sufficient speed, Flash ROM storage 00010 and of course a DAC. 00011 The sounds samples are derived from the Jeux D'Orgue 2 sample set http://www.jeuxdorgues.com and are used with permission. 00012 */ 00013 #include "mbed.h" 00014 00015 #include "Bourdon.h" 00016 #include "Montre.h" 00017 00018 /* 00019 As the ticker cannot be accurately controlled it is necessary to apply a fine adjustment capability 00020 hence the fine tune below that is used to multiply the step index as read from freqtab. 00021 freqtab is based on the assumption the ticker is running at exactly 44.1Khz 00022 */ 00023 const float sample_rate = 22.68; //44.1KHz 00024 const float freqfine=0.970; 00025 const float freqtab[] = {1, 1.0596, 1.1227, 1.1893, 1.2599, 1.3348, 1.4144, 1.4985, 1.5872, 1.6819, 1.782, 1.888, 2}; 00026 00027 #include "USBMIDI.h" 00028 00029 #include "TextLCD.h" 00030 //For Linksprite LCD Shield 00031 //TextLCD lcd(PTC12, D9, D4, D5, D6, D7); // rs, e, d4-d7 00032 //DigitalOut bl(D10); 00033 //D8 is wrong on K64F definition it is actually PTC12 not PTA0 00034 00035 //For Midas 2x16 OLED Display 00036 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 00037 00038 //Serial pc(USBTX, USBRX); // tx, rx 00039 00040 AnalogOut Aout(DAC0_OUT); 00041 00042 DigitalOut redled(LED1); 00043 DigitalOut greenled(LED2); 00044 DigitalOut blueled(LED3); 00045 00046 DigitalOut diag(D15); 00047 DigitalOut diag2(D14); 00048 00049 DigitalIn sw1(PTC6); 00050 DigitalIn sw3(PTA4); 00051 00052 //Stop switches mommentary connection to 0V will toggle on and off. 8' pitch defaults to on at power up. 00053 DigitalIn p1 (PTB2); //16' 00054 DigitalIn p2 (PTB3); //8' 00055 DigitalIn p3 (PTB10); //4' 00056 DigitalIn p4 (PTB11); //2 2/3' 00057 DigitalIn p5 (PTC11); //2' 00058 00059 //Wi-Fi connector J6 note pin 3 is incorrectly idenifed in the documentation as PTC12 00060 //Connects the shift register solenoid driver board 00061 DigitalOut SRCK(PTD7); //Shift Register clock 00062 DigitalOut RCK(PTD5); //Shift Register latch 00063 DigitalOut SER1(PTB20); //Shift Register serial data outout 00064 00065 00066 Ticker output_ticker; //Ticker for sound generation 00067 00068 unsigned char keybuf[128]= {}; //Note buffer 00069 unsigned char oldkeybuf[128]= {}; //Last note buffer 00070 int keyidx=0; //Key index 00071 00072 //Received MIDI note variables 00073 int key=0; 00074 int velocity=0; 00075 int chan=0; 00076 int onoff=0; 00077 00078 unsigned int audio_out; //Audio output value accumulator 00079 00080 //OLELD display bar graph characters 00081 const char udc0[] = {0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00}; 00082 const char udc1[] = {0x15, 0x10, 0x10, 0x10, 0x10, 0x10, 0x15, 0x00}; 00083 const char udc2[] = {0x15, 0x04, 0x04, 0x04, 0x04, 0x04, 0x15, 0x00}; 00084 const char udc3[] = {0x15, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x00}; 00085 const char udc4[] = {0x15, 0x01, 0x01, 0x01, 0x01, 0x01, 0x15, 0x00}; 00086 const char udc5[] = {0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x15, 0x00}; 00087 const char udc6[] = {0x15, 0x05, 0x05, 0x05, 0x05, 0x05, 0x15, 0x00}; 00088 const char udc7[] = {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00}; 00089 00090 //Variables for LCD/OLED display 00091 unsigned long int lcd_stat=0; 00092 unsigned long int lcd_stat_old=1; 00093 char display[2][16]; //Display Buffer 00094 char display_old[2][16]; //Old Display Buffer 00095 int pos=0; //Display Position counter 00096 int row=0; 00097 int tval=0; 00098 int tval1=0; 00099 int keyidx_t=0; 00100 int lcdmode=0; //LCD Display Mode 00101 int x =0; 00102 int x1=1; 00103 00104 //Button and stop variables 00105 unsigned int swi; 00106 unsigned int pressed; 00107 unsigned int sw[8]; 00108 unsigned int sw_count[8]; //Switch de-bounce counter 00109 unsigned int sw_phase[8]; 00110 unsigned int sw_status[8]= {0,1,0,0,0,0,0,0}; //Stop status 8' on by default 00111 unsigned int sw_old[8]; 00112 int oldstops=1; 00113 00114 //Sound generator variables 00115 int sampleset=0; 00116 int tempidx=0; 00117 int freqidx=45; 00118 float synth[16]; 00119 float synthidx[16]; 00120 int synth_old[16]; 00121 int synthtab[16]= {}; 00122 int synthstat[16]= {}; 00123 unsigned char synthoctave[16]= {}; 00124 unsigned char synthnote[16]= {}; 00125 int sucess=0; 00126 int noteidx=0; 00127 int i; 00128 int ii; 00129 int cl; 00130 00131 /* 00132 Ticker routine to calculate and output the audio signal. 00133 As the DAC is 12 bit this allows for 16 concurrent 8 bit samples running with no additional loss of precision. 00134 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. 00135 Sound Generation is in 4 states stored in synthstat: 00136 0 = Synth Channel idle 00137 1 = Attack / Sustain phase note running and looping if necessary 00138 2 = Signal to start release this may be delayed until the sound is paat the initial attack/decay point typically 100-200 mS 00139 3 = Sample is in the release phase. 00140 00141 */ 00142 void aout() 00143 { 00144 //The lines below are commented out and actually add to much time to the ticker routine each command adds around 1 uS which is significant 00145 //when the whole routine only takes around 16uS and is repeated every 23mS 00146 // diag=1; //Pulse DIAG Pin for Scoping purposes IE pin high 00147 // redled=0; //Pulse Red LED to indicate Ticker working 00148 audio_out=0; //Clear Audio Accumulator 00149 if (sampleset==0) { 00150 for (i =0; i<16; i++) { //Do 16 channels 00151 switch (synthstat[i]) { 00152 case 1: //Sustain phase 00153 if (synth[i]>sample1_loop_end[synthoctave[i]]) { //Got to end of buffer? 00154 synth[i]=sample1_loop_start[synthoctave[i]]; //Wrap around back to start 00155 } 00156 break; 00157 case 2: //Note off demand state 00158 if (synth[i]>=sample1_attack[synthoctave[i]]) { //Delay decay phase if not past end of attack 00159 //Check if the waveform is close to zero crossing this helps eliminate clicks looks for rising edge approaching 0x80 00160 tempidx=synth[i]; 00161 if (sample1[synthoctave[i]][tempidx]<128 & sample1[synthoctave[i]][tempidx]>120) { 00162 if (sample1[synthoctave[i]][tempidx]>synth_old[i]) { 00163 synth[i]=sample1_loop_off[synthoctave[i]]; //Jump to start of release 00164 synthstat[i]=3; //Say note in release 00165 } 00166 } 00167 } 00168 break; 00169 case 3: //Check if decay has completed 00170 if (synth[i]>=sample1_len[synthoctave[i]]) { //End of release? 00171 synthstat[i]=0; //say channel free 00172 synth[i]=0; //Set sample pointer to 0 00173 synthidx[i]=0; //Set sample index to 0 00174 synthtab[i]=255; //Set to invalid 00175 } 00176 break ; 00177 } 00178 00179 //get sample and add to Audio Accumulator 00180 synth_old[i]=sample1[synthoctave[i]][(int)(synth[i])]; //Get and save old sample 00181 audio_out=audio_out+synth_old[i]; //add sample to audio out accumulator 00182 synth[i]=synth[i]+synthidx[i]; //Get next sample pointer 00183 00184 } //Next Note 00185 } else { 00186 00187 //Sample Set 2 00188 00189 for (i =0; i<16; i++) { //Do 16 channels 00190 switch (synthstat[i]) { 00191 case 1: //Sustain phase 00192 if (synth[i]>sample2_loop_end[synthoctave[i]]) { //Got to end of buffer? 00193 synth[i]=sample2_loop_start[synthoctave[i]]; //Wrap around back to start 00194 } 00195 break; 00196 case 2: //Note off demand state 00197 if (synth[i]>=sample2_attack[synthoctave[i]]) { //Delay release phase if not past end of attack 00198 //Check if the waveform is close to zero crossing this helps eliminate clicks looks for rising edge approaching 0x80 00199 tempidx=synth[i]; 00200 if (sample2[synthoctave[i]][tempidx]<128 & sample2[synthoctave[i]][tempidx]>120) { 00201 if (sample2[synthoctave[i]][tempidx]>synth_old[i]) { 00202 synth[i]=sample2_loop_off[synthoctave[i]]; //Jump to start of release 00203 synthstat[i]=3; //Say note in release 00204 } 00205 } 00206 } 00207 break; 00208 case 3: //Check if release has completed 00209 if (synth[i]>=sample2_len[synthoctave[i]]) { //End of release? 00210 synthstat[i]=0; //say channel free 00211 synth[i]=0; //Set sample pointer to 0 00212 synthidx[i]=0; //Set sample index to 0 00213 synthtab[i]=255; //Set to invalid 00214 } 00215 break ; 00216 } 00217 00218 //get sample and add to Audio Accumulator 00219 synth_old[i]=sample2[synthoctave[i]][(int)(synth[i])]; //Get and save old sample 00220 audio_out=audio_out+synth_old[i]; //add sample to audio out accumulator 00221 synth[i]=synth[i]+synthidx[i]; //Get next sample pointer 00222 00223 } //Next Note 00224 } 00225 00226 00227 //Output to DAC 00228 Aout.write_u16(audio_out*16); 00229 00230 // redled=1; 00231 // diag=0; 00232 } 00233 00234 /* 00235 Interrupt routine to receive MIDI on/off message 00236 MIDI note on/off events are stored in the note status buffer keytab. 00237 the lower 5 bits of keytab represent a note being on or off 00238 Bit 0 = 16' 00239 Bit 1 = 8' 00240 Bit 2 = 4' 00241 Bit 3 = 2 2/3' (12th) 00242 Bit 4 = 2' (15th) 00243 Thus if keytab >0 then the note should be played 00244 Currently MIDI note on/off messages are accepted on any channel 00245 */ 00246 void get_message(MIDIMessage msg) 00247 { 00248 greenled=0; //Pulse Green LED to indicate MIDI activity 00249 key=msg.key(); 00250 velocity=msg.velocity(); 00251 chan=msg.channel(); 00252 switch (msg.type()) { 00253 case MIDIMessage::NoteOnType: //MIDI note on received 00254 if (key >23 & key<120) { 00255 onoff=1; 00256 if (sw_status[0]==1 & key >35) { 00257 keybuf[(key-36)]|= 1 << 0; //Store @ 16' pitch 00258 } 00259 if (sw_status[1]==1) { 00260 keybuf[(key-24)]|= 1 << 1; //Store @ 8' pitch 00261 } 00262 if (sw_status[2]==1& key<108) { 00263 keybuf[(key)-12]|= 1 << 2; //Store @ 4' pitch 00264 } 00265 if (sw_status[3]==1 & key<101) { 00266 keybuf[(key)-5]|= 1 << 3; //Store @ 2 2/3' pitch 00267 } 00268 if (sw_status[4]==1 & key <96) { 00269 keybuf[(key)]|= 1 << 4; //Store @ 2' pitch 00270 } 00271 } 00272 00273 break; 00274 00275 //Process keys off 00276 case MIDIMessage::NoteOffType: //Midi note off received 00277 if (key >23 & key<120) { 00278 onoff=0; 00279 if (key>35) { 00280 keybuf[(key-36)]&= ~(1 << 0); //Kill note @ 16' pitch 00281 } 00282 keybuf[(key-24)]&= ~(1 << 1); //Kill note @ 8' pitch 00283 if (key<108) { 00284 keybuf[(key-12)]&= ~(1 << 2); //Kill note @ 4' pitch 00285 } 00286 if (key<101) { 00287 keybuf[(key-5)]&= ~(1 << 3); //Kill note @ 2 2/3' pitch 00288 } 00289 if (key<96) { 00290 keybuf[(key)]&= ~(1 << 4); //Kill note @ 2' pitch 00291 } 00292 } 00293 break; 00294 00295 //Process all notes off command 00296 case MIDIMessage::AllNotesOffType: //Midi all notes off 00297 for (int it=0; it<108; it++) { 00298 keybuf[it]=0; //Clear Keybuf 00299 } 00300 break; 00301 00302 //Any other MIDI Commands just ignore 00303 default: 00304 break; 00305 } 00306 greenled=1; 00307 } 00308 00309 00310 int main() 00311 { 00312 greenled=1; 00313 redled=1; 00314 blueled=1; 00315 SRCK=0; //Serial Clock low 00316 RCK=0; //Latch Clock low 00317 00318 sw1.mode(PullUp); 00319 sw3.mode(PullUp); 00320 p1.mode(PullUp); 00321 p2.mode(PullUp); 00322 p3.mode(PullUp); 00323 p4.mode(PullUp); 00324 p5.mode(PullUp); 00325 00326 output_ticker.attach_us(&aout, sample_rate); //Start the ticker 00327 00328 lcd.cls(); 00329 wait(0.1); 00330 lcd.setCursor(TextLCD::CurOff_BlkOff); 00331 lcd.cls(); 00332 lcd.printf("MIDI Pipe Organ Waiting for USB"); 00333 /* 00334 I couldn't figure out which interrupt is used for the ticker so I lowered the USB interrupt priority so that it didn't 00335 interfere with the smooth operation of the sound generation ticker 00336 */ 00337 NVIC_SetPriority(USB0_IRQn, 99); //Reduce Interrupt priority of USB 00338 00339 USBMIDI midi; //Start up MIDI 00340 midi.attach(get_message); //callback for MIDI messages received 00341 00342 lcd.cls(); 00343 lcd.printf("MIDI Pipe Organ"); 00344 wait(1); 00345 lcd.cls(); 00346 lcd.printf("On Chan Note Vel"); 00347 key=0; 00348 velocity=0; 00349 chan=0; 00350 onoff=0; 00351 00352 //Main Loop 00353 while(1) { 00354 00355 00356 //Process notes off 00357 for (ii=0; ii<16; ii++) { //Scan through 16 channels 00358 if (synthstat[ii]==1 & keybuf[synthtab[ii]]==0) { //Note currently playing but should be off 00359 synthstat[ii]=2; //Set Start release 00360 } 00361 } 00362 //Process keys on 00363 //Find a free note generator and start the note playing, if no slots available just ignore the note 00364 for (keyidx=95; keyidx>=0; keyidx--) { 00365 if (keybuf[keyidx]>0 & oldkeybuf[keyidx]==0) { //Key is pressed 00366 //Find and use any channel that is free 00367 sucess=0; 00368 ii=0; 00369 while (ii<16) { //Find available synth channel 00370 if (synthstat[ii]==0) { //Is synth channel free? 00371 synthtab[ii]=keyidx; //Store note value 00372 synthoctave[ii]=synthtab[ii]/12; //Store the octave 00373 //Uncomment the following lines if you want to wrap around the top octave 00374 // if (synthoctave[ii]==7) { //Wrap around the top octave 00375 // synthoctave[ii]--; 00376 // } 00377 synthnote[ii]= synthtab[ii]%12; //Note within the octave 00378 synthstat[ii]=1; //Set status to playing 00379 synthidx[ii]=freqtab[synthnote[ii]]*freqfine; //Set the frequency 00380 sucess=1; 00381 ii=16; //exit loop 00382 } //Next Synth slot 00383 ii++; 00384 } 00385 //As a last resort find any channel that is in release 00386 if (sucess==0) { 00387 ii=0; 00388 while (ii<16) { //Find available synth channel 00389 if (synthstat[ii]==3) { //Is synth channel free? 00390 synthtab[ii]=keyidx; //Store note value 00391 synthoctave[ii]=synthtab[ii]/12; //Store the octave 00392 synthnote[ii]= synthtab[ii]%12; //Note within the octave 00393 synthstat[ii]=1; //Set status to playing 00394 synthidx[ii]=freqtab[synthnote[ii]]*freqfine; //Set the frequency 00395 sucess=1; 00396 ii=16; //exit loop 00397 } //Next Synth slot 00398 ii++; 00399 } 00400 } 00401 } 00402 if (sucess==1) { 00403 oldkeybuf[keyidx]=keybuf[keyidx]; //Store old value if note sucessfull 00404 } //If not sucessfull try on the next scan 00405 } 00406 00407 00408 //Output to Shift register pallet magnet driver board 00409 for (keyidx=107; keyidx>11; keyidx--) { 00410 if (keybuf[keyidx]>0) { 00411 SER1=1; 00412 } else { 00413 SER1=0; 00414 } 00415 SRCK=1; //Pulse Serial clock 00416 wait_us(4); 00417 SRCK=0; 00418 wait_us(4); 00419 } //Next bit 00420 00421 RCK=1; //Transfer data to outputs 00422 wait_us(4); 00423 RCK=0; 00424 wait_us(4); 00425 00426 //Read Stop inputs and onboard switches 00427 sw[0]=p1; 00428 sw[1]=p2; 00429 sw[2]=p3; 00430 sw[3]=p4; 00431 sw[4]=p5; 00432 sw[6]=sw1; 00433 sw[7]=sw3; 00434 /* 00435 code to de-bounce the K64F onboard and external switches using multiple loops to de-bounce; has 3 states: 00436 0 - Button not pressed 00437 1 - Button pressed waiting for de-bounce count of 5 loops 00438 2 - Button press stable, this status can be read as the de-bounced status indicating the button press is clean 00439 sw_status is toggled by each sucessive key press 0 / 1 00440 */ 00441 pressed=0; 00442 for (swi=0; swi<8; swi++) { //Process 8 push switches 00443 if (sw_phase[swi]==0 & sw[swi]==0) { //Button just been pressed 00444 sw_phase[swi]=1; 00445 sw_count[swi]=5; 00446 } 00447 if (sw_phase[swi]==1 & sw_count[swi]==0 & sw[swi]==0) { //Button still pressed after de-bounce period 00448 sw_phase[swi]=2; 00449 pressed++; //Inc button pressed count 00450 sw_status[swi]=!sw_status[swi]; //Toggle switch status 00451 } 00452 if (sw_phase[swi]==1 & sw_count[swi]==0 & sw[swi]==1) { //Button no longer pressed after de-bounce period 00453 sw_phase[swi]=0; 00454 } 00455 if (sw_phase[swi]==2 & sw[swi]==1) { //Button released 00456 sw_phase[swi]=0; 00457 } 00458 sw_count[swi]--; 00459 } 00460 //light blue LED if any button presed 00461 if (pressed>0) { 00462 blueled=0; 00463 } else { 00464 blueled=1; 00465 } 00466 00467 00468 //Button 1 will clear all playing notes & switch sampleset 00469 if (sw_status[6] != sw_old[6]) { 00470 for (cl=0; cl<108; cl++) { 00471 keybuf[cl]=0; //Clear Keybuf 00472 } 00473 sampleset=sw_status[6]; 00474 oldstops=255; //Force a display refresh 00475 sw_old[6]=sw_status[6]; 00476 } 00477 00478 00479 //Check for display mode button being presed 00480 if (sw_status[7] != sw_old[7]) { //Mode Switch pressed 00481 lcdmode++; 00482 if (lcdmode>4) { 00483 lcdmode=0; 00484 } 00485 lcd.cls(); 00486 if (lcdmode==0) { 00487 lcd.printf("On Chan Note Vel"); 00488 } 00489 if (lcdmode==1) { 00490 //Initialise bar graph display 00491 //Program user defined characters into OLED display for bar graph 00492 lcd.setUDC(0, (char *) udc0); 00493 lcd.setUDC(1, (char *) udc1); 00494 lcd.setUDC(2, (char *) udc2); 00495 lcd.setUDC(3, (char *) udc3); 00496 lcd.setUDC(4, (char *) udc4); 00497 lcd.setUDC(5, (char *) udc5); 00498 lcd.setUDC(6, (char *) udc6); 00499 lcd.setUDC(7, (char *) udc7); 00500 for (row=0; row<2; row++) { 00501 for (pos=0; pos<16; pos++) { 00502 display[row][pos]=0; 00503 display_old[row][pos]=1; 00504 } 00505 } 00506 } 00507 if (lcdmode==2) { 00508 //Initilise synth channel status display 00509 lcd.locate(0,1); 00510 lcd.printf("0123456789ABCDEF"); 00511 } 00512 //Initialise synth channel unilisation 00513 if (lcdmode==3) { 00514 lcd.cls(); 00515 lcd.locate(0,0); 00516 lcd.printf("Utilisation:"); 00517 } 00518 if (lcdmode==4) { 00519 //Initialise Stops selection display 00520 oldstops=255; //Force a refresh 00521 } 00522 sw_old[7]=sw_status[7]; 00523 } 00524 00525 00526 00527 00528 // OLED MIDI Status display 00529 if (lcdmode==0) { 00530 lcd_stat=key+(128*velocity)+(16384*chan)+(262144*onoff); 00531 if (lcd_stat!=lcd_stat_old) { 00532 00533 lcd.locate(0,1); 00534 lcd.printf("%1d %2d %3d %3d", onoff, chan, key, velocity); 00535 lcd_stat_old=lcd_stat; 00536 } 00537 } 00538 00539 // OLED MIDI Bar Display 00540 if (lcdmode==1) { 00541 keyidx=0; 00542 for (row=1; row>=0; row--) { 00543 for (pos=0; pos<16; pos++) { 00544 keyidx_t=keyidx*2; 00545 if(keyidx_t>94) { 00546 keyidx_t=keyidx_t-95; 00547 } 00548 tval=keybuf[keyidx_t]; 00549 if(tval>0) { 00550 tval=1; 00551 } 00552 keyidx++; 00553 keyidx_t=keyidx*2; 00554 if(keyidx_t>94) { 00555 keyidx_t=keyidx_t-95; 00556 } 00557 tval1=keybuf[keyidx_t]; 00558 if (tval1>0) { 00559 tval1=1; 00560 } 00561 tval=tval+(2*tval1); 00562 keyidx++; 00563 00564 keyidx_t=keyidx*2; 00565 if(keyidx_t>94) { 00566 keyidx_t=keyidx_t-95; 00567 } 00568 tval1=keybuf[keyidx_t]; 00569 if (tval1>0) { 00570 tval1=1; 00571 } 00572 tval=tval+(4*tval1); 00573 keyidx++; 00574 display[row][pos]=tval; 00575 00576 if(display[row][pos]!=display_old[row][pos]) { 00577 lcd.locate(pos,row); 00578 lcd.putc(display[row][pos]); 00579 display_old[row][pos]=display[row][pos]; 00580 } 00581 } 00582 } 00583 } 00584 00585 //Display status of the Synth channels 00586 if (lcdmode==2) { 00587 lcd.locate(0,0); 00588 for (noteidx=0; noteidx<16; noteidx++) { 00589 lcd.putc((synthstat[noteidx]+48)); 00590 } 00591 } 00592 00593 //Display utilisation bar graph 00594 if (lcdmode==3) { 00595 x=0; 00596 for (noteidx=0; noteidx<16; noteidx++) { 00597 if (synthstat[noteidx] >0) { 00598 x++; 00599 } 00600 } 00601 for (pos=0; pos<x; pos++) { 00602 display[1][pos]=0xff; 00603 } 00604 while(pos<16) { 00605 display[1][pos]=0x20; 00606 pos++; 00607 } 00608 row=1; 00609 for (pos=0; pos<16; pos++) { 00610 if (x!=x1) { 00611 lcd.locate(13,0); 00612 lcd.printf("%2d", x); 00613 x1=x; 00614 } 00615 if(display[row][pos]!=display_old[row][pos]) { 00616 lcd.locate(pos,row); 00617 lcd.putc(display[row][pos]); 00618 display_old[row][pos]=display[row][pos]; 00619 } 00620 } 00621 } 00622 //Stop display 00623 if (lcdmode==4) { 00624 pos=sw_status[0] + sw_status[1]+sw_status[2]+sw_status[3]+sw_status[4]; 00625 if (oldstops != pos) { 00626 oldstops=pos; 00627 lcd.cls(); 00628 for (pos=0; pos<16; pos++) { 00629 lcd.locate(pos,0); 00630 if (sampleset==0) { 00631 lcd.putc(stopname1[pos]); 00632 } else { 00633 lcd.putc(stopname2[pos]); 00634 } 00635 } 00636 lcd.locate(0,1); 00637 if (sw_status[0]==1) { 00638 lcd.printf("16 "); 00639 } 00640 00641 if (sw_status[1]==1) { 00642 lcd.printf("8 "); 00643 } 00644 00645 if (sw_status[2]==1) { 00646 lcd.printf("4 "); 00647 } 00648 00649 if (sw_status[3]==1) { 00650 lcd.printf("2-2/3 "); 00651 } 00652 00653 if (sw_status[4]==1) { 00654 lcd.printf("2"); 00655 } 00656 } 00657 } 00658 00659 } //End of main loop 00660 } //End of program 00661 00662 00663 00664
Generated on Tue Jul 19 2022 14:10:14 by 1.7.2