//============================================================================= /* * Project name; MIDI_Bash2.c v2.0 (set TABS to 4) * Description; PIC16F876 based MIDI drum controller with 10 digital pads. This v2 saves drum setup to flash memory and has a volume pot that controls total drum velocity and can set individual drum pad velocities. When any button is pressed it sends a MIDI note-on signal to MIDI-out plug, which makes a MIDI device play a drum sound. v1.0 has no velocity info, all drum sounds are the same velocity (volume). v1.0 has 10 drum hit buttons. There are 2 other buttons; up/down If a drum is hit while either button is pressed the drum sound changes up/down to the next note (next drum sound). All notes are limited to MIDI channel 10 (standard for drums). * Test configuration; MCU: PIC16F876 (NOT A) Dev.Board: EasyPIC4 Oscillator: HS, 08.0000 MHz (2pin short-can xtal) SW: mikroC v7.0.0.3 * Version; v2.0 started 12/02/2009 Specific for v2.0; On bootup it loads the previous settings (notes) for all 10 drums from non-volatile internal EEPROM. This keeps the same notes (sounds) on the 10 pads as when it was last used. When any drum sound is changed for a pad the new note data for that pad is now saved to internal EEPROM. Also for v2.0 is a "volume" pot that sets global velocity for all 10 drums. This is a 0v-5v linear pot reading into PIC ADC input AN0, the PIC reads this voltage about 20 times per second and then sets the global MIDI "velocity" value that is used for all 10 drums. So the pot can be adjusted in real time to add expression to the drums or just simply set global drum volume. Also, if BOTH up/down buttons are held down and a drum pad is hit, the current velocity (pot setting) is permanently set for that drum pad only. This allows each pad to have its own fixed velocity (if desired). These velocity settings are saved to EEPROM, to restore ANY ONE drum pad back to global velocity turn the pot to zero then hit that drum pad while pressing both the up/down buttons. * PIC pins (same as v1.0); RC6 out serial MIDI out, manual bit banging (no usart needed) RC5 out drum led, flashes at power up and when any pad is hit RC0 in Note down button, pullup resistor, low=pressed RC1 in Note up button, pullup resistor, low=pressed RB0-RB7 in 8 "drum" buttons (0-7), pullup resistor, low=pressed RC2 in drum button (8), " RC3 in drum button (9), " (total 0-9 =10 drums) (v2.0 pin changes below) RA0 in AN0 0v-5v analog ADC voltage in from "volume" pot */ //============================================================================= // global vars char sdata; // disposable 2 bytes used for serial bit-banging; char sbit; // (must be first, need low place in ram for asm use) //char i; // used for anything char the_pad; // the pad that was just hit char the_note; // the note to send to MIDI for this drum hit char the_vel; // the velocity to send to MIDI for this drum hit char flash_address; // (V2.0) to store drum note setup to PIC internal flash char flash_data; // " char timer; // (v2.0) inc on TMR0 overflow; used for ADC timing char velocity; // for global velocity (loudness) of the 10 drums char note0; // MIDI note value for each of the 10 drum buttons char note1; // (which can be changed when device is operating) char note2; // char note3; // char note4; // char note5; // char note6; // char note7; // char note8; // char note9; // char vel0; // MIDI velocity used for each drum pad, only used char vel1; // if it was specially set for that pad. char vel2; // char vel3; // char vel4; // char vel5; // char vel6; // char vel7; // char vel8; // char vel9; // char wait_n0; // used for debounce and afterpause for each drum note char wait_n1; // char wait_n2; // char wait_n3; // char wait_n4; // char wait_n5; // char wait_n6; // char wait_n7; // char wait_n8; // char wait_n9; // // Constants used in my MIDI transmit funcions; #define MIDI_CHANNEL 10 // MIDI output channel (1-16) to drum machine #define MIDI_NOTE_ON (0b10010000 + (MIDI_CHANNEL-1)) // byte used to send MIDI note-on command //#define MIDI_NOTE_ON 0b10011001 // byte used to send MIDI note-on command #define NOTE_MIN 23 // lowest MIDI note that can be selected #define NOTE_MAX 98 // highest " (Zoom MRS1608 range is 31-70) 40 sounds // (Roland D-20 drum range is 35-97) 63 sounds // (Tested; D-20 has 23/24 are metornome sounds // they work but at fixed max velocity only) #define DEB_COUNT 21 // debounce wait count for debounce timer; // PIC 8Mhz prescale 32:1, so 21 TMR0 overflows = 84mS #define DEB_COUNTSAFE 5 // safe period for after debounce special situations #define PORT_MIDI PORTC // used for bit-banged serial out to MIDI #define PIN_MIDI 6 // " #define PIN_LED_DRUM PORTC.F5 // flashes a led when any drum button is pressed #define PIN_DOWNBUT PORTC.F0 #define PIN_UPBUT PORTC.F1 // drums 0-7 input pins is PORTB.F0 - PORTB.F7 #define PIN_DRUM8 PORTC.F2 // with these 2 is 10 drums total #define PIN_DRUM9 PORTC.F3 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //void interrupt(void) //{ // is (TMR1) CCP2 capture int, so just clear TMR1 ?? //} //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //============================================================================= // WRITE_FLASH //============================================================================= void write_flash(void) { //---------------------------------------------------- // This writes one byte to the PIC internal EEPROM. // The byte written is the current drum "note" (sound) // for the selected pad; // // flash_address = the pad (0-9), is also the EEPROM address // flash_data = the note value to save for that pad //---------------------------------------------------- // first check if a write is already in progress!! if so; // wait until it completes before this write starts. // this is a real issue for MIDI_Bash v2.0 as we can have // 2 or more drum pads adjusted at the same time... wf_wait: if(EECON1.WR == 1) goto wf_wait; // now is safe, so perform this write EEADR = flash_address; // point to location to write EEDATA = flash_data; // the byte to write EECON1.WREN = 1; // set bit to allow writing operations // PIC safety feature requires these instructions exactly // for EEPROM write to commence... (as stated in PIC datasheet); asm { BSF STATUS, RP1 ; set PIC to register Bank 3 BSF STATUS, RP0 ; MOVLW 0x55 ; Write 55h to MOVWF EECON2 ; EECON2 MOVLW 0xAA ; Write AAh to MOVWF EECON2 ; EECON2 BSF EECON1, WR ; Start write operation BCF EECON1, WREN ; clr bit to disable further writes (default) } // now the EEPROM write is happening... // we can return and do other stuff } //----------------------------------------------------------------------------- //============================================================================= // READ_FLASH //============================================================================= void read_flash(void) { //---------------------------------------------------- // This reads one byte from the PIC internal non-volatile // EEPROM memory. This allows MIDI_Bash v2.0 to save the // drum pad setup so it will restore when next turned on. // // I have used simple global vars; flash_address, flash_data // so this can be converted to PIC assembler or other // language easily. //---------------------------------------------------- EEADR = flash_address; // point to location to read EECON1.RD = 1; // set bit to start read operation flash_data = EEDATA; // save the byte to my var } //----------------------------------------------------------------------------- //============================================================================= // SEND_MIDI_BYTE //============================================================================= void send_midi_byte(void) { //---------------------------------------------------- // This version uses TMR0 for bit-banging, no usart needed. // I wrote this function in PIC assembler to speed it up as the // MikroC compiler SUCKS when it comes to fast bit manipulation. //------------------------------------------------- // NOTE! MIDI data is electrically inverted! ie MIDI bit=1 is PIC pin=O // // start bit, 8 data bits (LSBit first), then stop bit // // PIC 8MHz = 2MHz ticks, so MIDI at 31250 baud = 64 timer ticks // using TMR0 prescaled at 32:1 so 31250 baud = 2 timer ticks // therefore whenever TMR0 bit1 changes = a baud // // This is a zero cumulative error system, even though there // is a variable 0-6 instruction delay for each bit // it still always re-syncs to TMR0,bit1 for the next bit. // Given that there is 64 insts between bits and that // the receiving device samples the bit right in the middle // (which is standard) this should give reliable serial // transmission. It will probably still work with an // internal RC osc at 4MHz too.. test later. //---------------------------------------------------- sbit = 0; // this is needed to make MikroC compiler recognise // variables in the asm block below... // weird, but it is covered in MikroC help file. asm { ;---------------------------- ; PIC 31250 baud MIDI bit-banging serial code - RomanBlack 2009 ; sends one byte out to MIDI port. byte is in sdata variable. ; PIC 8 MHz, TMR0 is free-running and prescaled at 32:1 ; it is easily adapted to 4 Mhz or 16 Mhz, just change the prescale. ; This assembler cource code is public domain, use it as you wish. ;---------------------------- ; pre-delay, to sync to a "baud", then send start bit predelay: BTFSC TMR0, 1 ; pre-delay to sync baud with TMR0 GOTO predelay ; wbStart: BTFSS TMR0, 1 ; again wait to ensure sync with baud GOTO wbStart ; BCF PORT_MIDI,PIN_MIDI ; send start bit (inverted remember) ;---------------------------- ; now send the 8 serial bits, as 4 pairs of 2 bits (even then odd). ; each bit tested first, then sync to baud using TMR0, then send bit. ; 8 MHz PIC, each baud is 64 insts. jitter per baud is 0 to 2 insts. ; system is zero-cumulative error, ie; it re syncs with every baud. ; this gives very solid performance without needing a usart. MOVLW 4 ; 4 bit pairs to send MOVWF sbit ; serial_even: BTFSC sdata,0 ; test serial even bit GOTO even1 ; even0: BTFSC TMR0, 1 ; wait for baud GOTO even0 ; BCF PORT_MIDI,PIN_MIDI ; send bit (inverted remember) GOTO serial_odd ; even1: BTFSC TMR0, 1 ; wait for baud GOTO even1 ; BSF PORT_MIDI,PIN_MIDI ; send bit (inverted remember) serial_odd: RRF sdata,f ; load next serial bit into sdata,0 BTFSC sdata,0 ; test serial odd bit GOTO odd1 ; odd0: BTFSS TMR0, 1 ; wait for baud GOTO odd0 ; BCF PORT_MIDI,PIN_MIDI ; send bit (inverted remember) GOTO pair_done ; odd1: BTFSS TMR0, 1 ; wait for baud GOTO odd1 ; BSF PORT_MIDI,PIN_MIDI ; send bit (inverted remember) pair_done: RRF sdata,f ; load next serial bit into sdata,0 DECFSZ sbit,f ; another bit pair was done, so test GOTO serial_even ; bits left! so send another pair ;---------------------------- ; send the stop bit wbStop: BTFSC TMR0, 1 ; wait to sync with baud GOTO wbStop ; BSF PORT_MIDI,PIN_MIDI ; send stop bit (inverted remember) } } //----------------------------------------------------------------------------- //============================================================================= // SEND_NOTE_ON //============================================================================= void send_note_on(void) { //------------------------------------------------- // Sends 3 serial bytes out to MIDI port at 31250 baud; // byte0 MIDI note on = 1001cccc (cccc = MIDI channel(1-16) -1) // byte1 note 0-127 (the specific drum sound) // byte2 velocity 0-127 (volume) i'm using fixed value of 100? // // This system just ties up the PIC while it sends // all 3 bytes. At standard MIDI 31250 baud that is less // than 1mS to send all 3 bytes so it shouldn't matter. // That is the fastest that MIDI can send drum messages anyway. //---------------------------------------------------- // byte0 = MIDI specific note-on command sdata = MIDI_NOTE_ON; // data byte to send send_midi_byte(); // byte1 = the note (which drum sound to play) MIDI range 0-127 if(the_note > 127) the_note = 127; // protect against illegal notes sdata = the_note; // data byte to send send_midi_byte(); // byte2 = velocity (note volume) MIDI range 0-127 // MIDI_Bash v2.0; gets value based on the specific velocity setting // for that pad, if that value is set to zero it uses global // velocity pot position if(the_vel > 127) the_vel = 127; // protect against illegal velocity sdata = the_vel; // data byte to send send_midi_byte(); //---------------------------------------------------- } //----------------------------------------------------------------------------- //============================================================================= // DRUM_WAS_HIT //============================================================================= void drum_was_hit(void) { //------------------------------------------------- // a drum pad was hit, so; // if both up/down pressed; save new velocity to EEPROM // if note down was pressed; save new note to EEPROM // if note up was pressed; save new note to EEPROM // then always play the drum sound //------------------------------------------------- if(PIN_DOWNBUT==0 && PIN_UPBUT==0) // if BOTH up/down are pressed { // make global velocity the new set velocity for that pad only if(the_pad == 0) vel0 = velocity; if(the_pad == 1) vel1 = velocity; if(the_pad == 2) vel2 = velocity; if(the_pad == 3) vel3 = velocity; if(the_pad == 4) vel4 = velocity; if(the_pad == 5) vel5 = velocity; if(the_pad == 6) vel6 = velocity; if(the_pad == 7) vel7 = velocity; if(the_pad == 8) vel8 = velocity; if(the_pad == 9) vel9 = velocity; // save the new pad set velocity to EEPROM the_vel = velocity; flash_address = (32 + the_pad); flash_data = the_vel; write_flash(); } else // else NOT both buttons { if(PIN_DOWNBUT == 0) // if DOWN was pressed { // change note the_note--; if(the_note < NOTE_MIN) the_note=NOTE_MIN; // and limit at min/max flash_address = the_pad; flash_data = the_note; write_flash(); // write new note setting to EEPROM // and fix the pad setting in ram if(the_pad == 0) note0 = the_note; if(the_pad == 1) note1 = the_note; if(the_pad == 2) note2 = the_note; if(the_pad == 3) note3 = the_note; if(the_pad == 4) note4 = the_note; if(the_pad == 5) note5 = the_note; if(the_pad == 6) note6 = the_note; if(the_pad == 7) note7 = the_note; if(the_pad == 8) note8 = the_note; if(the_pad == 9) note9 = the_note; } else if(PIN_UPBUT == 0) // else if UP was pressed { // change note the_note++; if(the_note > NOTE_MAX) the_note=NOTE_MAX; flash_address = the_pad; flash_data = the_note; write_flash(); // write new note setting to EEPROM // and fix the pad setting in ram if(the_pad == 0) note0 = the_note; if(the_pad == 1) note1 = the_note; if(the_pad == 2) note2 = the_note; if(the_pad == 3) note3 = the_note; if(the_pad == 4) note4 = the_note; if(the_pad == 5) note5 = the_note; if(the_pad == 6) note6 = the_note; if(the_pad == 7) note7 = the_note; if(the_pad == 8) note8 = the_note; if(the_pad == 9) note9 = the_note; } } // if no specific velocity is set for that pad (ie set to 0), // then use the global velocity to play this pad sound. if(the_vel == 0) the_vel = velocity; // now play the drum sound! send_note_on(); // send it to MIDI } //----------------------------------------------------------------------------- //============================================================================= // MAIN //============================================================================= void main() { //------------------------------------------------- // Setup PIC registers etc // Setup for 16F876; //------------------------------------------------- // setup ADC for MIDI_Bash v2.0; // we use only one ADC input; AN0 on PORTA.F0 // which is used for a 0v-5v linear pot ("volume" pot) // we use left justified result, which means we only have to // read the hi byte; ADRESH (0v-5v = range 0-255) /* movlw b'10000001' ; 7 AD clock (2 bits); ; 6 (using 10 = 32Tosc; slowest for best conversion) ; 5 ADC channel select (3 bits); ; 4 using AN0 = 000 ; 3 " ; 2 conversion status bit ; 1 -not used ; 0 1=ADC on */ ADCON0 = 0b10000001; /* movlw b'00001110' ; 7 result right/left justified (0 = left just) ; 6 -not used ; 5 -not used ; 4 -not used ; 3 4bits, select ADC inputs/dig inputs setup ; 2 note! see datasheet, there are limited options... ; 1 ; 0 (using 1110 = AN0 plus 4 digital inputs) */ ADCON1 = 0b00001110; //------------------------------------------------- // port pin directions; PORTA = 0; TRISA = 0b00000001; // PORTA; AN0=ADC in, other 4 are dig out PORTB = 0; TRISB = 0b11111111; // PORTB all in (drum0-drum7) PORTC = 0; TRISC = 0b00001111; // PORTC; RC6 = serial out to MIDI) // RC0=down button in, RC1=up button in // RC2=drum8 in, RC3=drum9 in INTCON = 0; // clear INTCON //------------------------------------------------- // TMR0 setup /* ; OPTION_REG setup 16F876 movlw b'00000100' ; 7 portb pullups, 1=disabled, 0=enabled ; 6 RBO/INT pin edge select, 1= rising, 0=falling edge ; 5 TMR0 clock source, 1=ext RA4, 0=int clock ; 4 TMR0 source ext RA4 edge, 0=rising edge ; 3 PSA prescaler assign, 1=WDT, 0=TMR0 ; 2 these three are the 3 bit prescaler rate; ; 1 000-111 = 2-256 for TMR0, 1-128 for WDT ; 0 (using 100 = 32:1 prescale) */ OPTION_REG = 0b00000100; // PIC 8MHz = 2MHz ticks, so MIDI at 31250 baud = 64 timer ticks // using TMR0 prescaled at 32:1 so 31250 baud = 2 timer ticks // therefore whenever TMR0 bit1 changes = a baud // I think for different PIC clock speeds you can just // change the prescale value and leave the rest of the code as is. // PIC 4MHz use 16:1 // PIC 8MHz use 32:1 (this code) // PIC 16MHz use 64:1 //------------------------------------------------- // EECON1 (used for my v2.0 to use EEPROM flash) EECON1 = 0; //------------------------------------------------- // TMR1 setup /* ; timer1 control movlw b'00000000' ; 7------- na ; -6------ na ; --5----- TIMER1 prescaler... two bits (5,4) ; ---4---- 00=1, 01=2, 10=4, 11=8 prescale (using 00= 1:1) ; ----3--- T1OSCEN - timer1 osc enable, 1=en ; -----2-- T1SYNC - ext sync ; ------1- TMR1CS - ext/inter, 0=internal clock ; -------0 TMR1ON - 1=timer1 enabled */ T1CON = 0b00000000; // TMR1 not used //------------------------------------------------- // Initialise vars //------------------------------------------------- // set the MIDI output to off (HI) PORTC = 0; // safe; drum led off etc PORT_MIDI.F6 = 1; // MIDI output pin off (HI) // starting velocity (loudness) for drums, range 0-127 velocity = 100; // load the starting (default) note values for the 10 drums; // for MIDI_Bash v2 we load these drum values from internal // EEPROM to restore the same drum sounds to the pads as // when it was last used. It also restores the same velocity // data for each pad. // MIDI drum note 0-9 = EEPROM location 0 - 9 // MIDI velocity 0-9 = EEPROM location 32+0 - 32+9 flash_address = 0; read_flash(); // get the MIDI note for that pad note0 = flash_data; flash_address += 32; read_flash(); // get the MIDI velocity for that pad vel0 = flash_data; flash_address = 1; read_flash(); note1 = flash_data; flash_address += 32; read_flash(); vel1 = flash_data; flash_address = 2; read_flash(); note2 = flash_data; flash_address += 32; read_flash(); vel2 = flash_data; flash_address = 3; read_flash(); note3 = flash_data; flash_address += 32; read_flash(); vel3 = flash_data; flash_address = 4; read_flash(); note4 = flash_data; flash_address += 32; read_flash(); vel4 = flash_data; flash_address = 5; read_flash(); note5 = flash_data; flash_address += 32; read_flash(); vel5 = flash_data; flash_address = 6; read_flash(); note6 = flash_data; flash_address += 32; read_flash(); vel6 = flash_data; flash_address = 7; read_flash(); note7 = flash_data; flash_address += 32; read_flash(); vel7 = flash_data; flash_address = 8; read_flash(); note8 = flash_data; flash_address += 32; read_flash(); vel8 = flash_data; flash_address = 9; read_flash(); note9 = flash_data; flash_address += 32; read_flash(); vel9 = flash_data; // load the wait timers for each drum; // this gives a bootup delay before any drums can be // triggered, 200 gives about 0.8 seconds. // the drum led will also be on for this 0.8 secs, // so it acts like a "power on" led. wait_n0 = 200; wait_n1 = 200; wait_n2 = 200; wait_n3 = 200; wait_n4 = 200; wait_n5 = 200; wait_n6 = 200; wait_n7 = 200; wait_n8 = 200; wait_n9 = 200; //------------------------------------------------- // MAIN RUN MODE AFTER HERE //------------------------------------------------- // Operation; // * the 10 inputs are checked to see if button pressed (LO) // * if pressed, send 3 bytes to MIDI (make one drum sound) // * debounce inputs with a wait timer to stop retriggering drums! // // Details; // * test all inputs; only test an input if its wait timer==0 // * if a button is pressed; // * set its wait timer to a "debounce" value // * send 3 MIDI bytes, do nothing else until all 3 sent ok. // * every TMR0 overflow; // * if wait timer >1; dec wait timer // * if wait timer==1, dec only if button is released (see below) // // This is about the simplest system to sense 8 buttons then fire drum // sounds off to MIDI, then ensure a simple delay with a countdown timer // to stop a drum being retriggered too soon. The simplest debounce // is used so it just counts a time period after the button was first // pressed, after a set time it is tested to make sure it is released, // then resets ready to be retriggered again. So if a button is held // down it will only make the drum sound once. This gives a faster // max drumroll speed then a long delay which would be needed for // other debounce systems. //------------------------------------------------- TMR0 = 0; // reset timer0 INTCON.T0IF = 0; // clear TMR0 overflow flag // main run loop while(1) { //--------------------------------------- // this loop mainly just checks the 10 drum buttons. //--------------------------------------- // if any button has JUST been pressed; send drum note if(wait_n0==0 && PORTB.F0==0) // if debounce is reset && button pressed { // start debounce timer wait_n0 = DEB_COUNT; the_pad = 0; // which pad was just hit the_note = note0; the_vel = vel0; drum_was_hit(); // process that pad and make drum sound } if(wait_n1==0 && PORTB.F1==0) { wait_n1 = DEB_COUNT; the_pad = 1; the_note = note1; the_vel = vel1; drum_was_hit(); } if(wait_n2==0 && PORTB.F2==0) { wait_n2 = DEB_COUNT; the_pad = 2; the_note = note2; the_vel = vel2; drum_was_hit(); } if(wait_n3==0 && PORTB.F3==0) { wait_n3 = DEB_COUNT; the_pad = 3; the_note = note3; the_vel = vel3; drum_was_hit(); } if(wait_n4==0 && PORTB.F4==0) { wait_n4 = DEB_COUNT; the_pad = 4; the_note = note4; the_vel = vel4; drum_was_hit(); } if(wait_n5==0 && PORTB.F5==0) { wait_n5 = DEB_COUNT; the_pad = 5; the_note = note5; the_vel = vel5; drum_was_hit(); } if(wait_n6==0 && PORTB.F6==0) { wait_n6 = DEB_COUNT; the_pad = 6; the_note = note6; the_vel = vel6; drum_was_hit(); } if(wait_n7==0 && PORTB.F7==0) { wait_n7 = DEB_COUNT; the_pad = 7; the_note = note7; the_vel = vel7; drum_was_hit(); } if(wait_n8==0 && PIN_DRUM8==0) { wait_n8 = DEB_COUNT; the_pad = 8; the_note = note8; the_vel = vel8; drum_was_hit(); } if(wait_n9==0 && PIN_DRUM9==0) { wait_n9 = DEB_COUNT; the_pad = 9; the_note = note9; the_vel = vel9; drum_was_hit(); } //--------------------------------------- // Now check for TMR0 event! if so, dec the 8 wait timers // to produce debounce of the pad contacts. // v2.0; also process the ADC input here for the volume pot. // // PIC 8MHz needs TMR0 prescaled at 32:1 // so each overflow occurs at 2Mhz / 32 / 256 = 244Hz // 1/244 = 0.004096 so time between each overflow is 4mS // // To get good drum speed for drumroll etc we need to be able // to get about 12 drum hits per second. However to stop // double triggering with one hit (that's bad!) the debounce // needs to be as long as possible. So we use the max debounce; // ie use; 1 second /12 = 83mS. // as each overflow is 4mS, we use 21 overflows = 84mS // // That value 21 is set in the DEB_COUNT constant. // if using other PIC clock speeds just change TMR0 // prescale value - see timer0 setup. //--------------------------------------- // * every TMR0 overflow; // * if wait timer >1; dec wait timer // * if wait timer==1, dec only if button is released (see below) //--------------------------------------- // check for TMR0 event! if so, dec the 8 wait timers. if(INTCON.T0IF == 1) // if TMR0 overflowed { // first clear overflow flag INTCON.T0IF = 0; // set the drum led to off (LO) by default PIN_LED_DRUM = 0; // then process all 8 drum button timers if(wait_n0 > 0) { wait_n0--; // subtract another overflow period // if button is still pressed (LO), thats bad! // so add some more debounce time to allow for // any button release bounce to be past. if(wait_n0==0 && PORTB.F0==0) wait_n0=DEB_COUNTSAFE; // if any wait timer is >0 then set the drum led to on! // this makes the drum led give a quick flash // every time a drum button is hit. PIN_LED_DRUM = 1; // led on = HI } if(wait_n1 > 0) { wait_n1--; if(wait_n1==0 && PORTB.F1==0) wait_n1=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n2 > 0) { wait_n2--; if(wait_n2==0 && PORTB.F2==0) wait_n2=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n3 > 0) { wait_n3--; if(wait_n3==0 && PORTB.F3==0) wait_n3=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n4 > 0) { wait_n4--; if(wait_n4==0 && PORTB.F4==0) wait_n4=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n5 > 0) { wait_n5--; if(wait_n5==0 && PORTB.F5==0) wait_n5=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n6 > 0) { wait_n6--; if(wait_n6==0 && PORTB.F6==0) wait_n6=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n7 > 0) { wait_n7--; if(wait_n7==0 && PORTB.F7==0) wait_n7=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n8 > 0) { wait_n8--; if(wait_n8==0 && PIN_DRUM8==0) wait_n8=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } if(wait_n9 > 0) { wait_n9--; if(wait_n9==0 && PIN_DRUM9==0) wait_n9=DEB_COUNTSAFE; PIN_LED_DRUM = 1; } // now process the ADC input conversion... // MIDI_Bash v2.0 only using AN0 input (velocity "volume" pot) // 8MHz PIC we get here at 244 Hz (see above) // so do an ADC conversion about 25 times per second // (fast enough for good response, but slow enough // to save battery power) so we do a conversion // every 12 overflows; 244Hz /10 = 24.4Hz timer++; if(timer == 9) { // start ADC conversion ADCON0.GO = 1; } if(timer >= 10) { // get ADC result (must now be 4mS since starting conversion // so no need to check if conversion is done) velocity = ADRESH; // get pot position 0-255 velocity = (velocity / 2); // convert to MIDI 0-127 range if(velocity < 5) velocity = 0; // safe; make very quiet = silent timer = 0; } } //--------------------------------------- } } //----------------------------------------------------------------------------- //============================================================================= // BLANK //============================================================================= void blank(void) { //------------------------------------------------- //------------------------------------------------ } //-----------------------------------------------------------------------------