' ******************************************************************** ' * PIC firmware for * ' * bidirectional string pluckers * ' * coded by dr.Godfried-Willem Raes * ' * http://www.logosfoundation.org/instrum_gwr/zi/picworks * ' * source code development directory: * ' * Zi_5.bas * ' ******************************************************************** ' 04.10.2015: This firmware fits the single sided bidirectional solenoid ' driver boards using L298N bridge drivers. ' Each board drives 8 solenoids ' This be version 1.0 ' 05.10.2015: Midi mapping changed to 50 - 87 ' documentation adapted on the Logos site. ' Test code in GMT adapted as well. ' 09.11.2015: Recompiled, ready for testing. ' Firmware uploaded. ' 10.11.2015: firmware still had some shakyness... ' memory overlap bug with midibuffer solved. ' Firmware version 1.1 uploaded ' 11.11.2015: Plucker Reset procedure added. ' This is version 1.21 ' velocities rescaled * 2 ' pulse duration for plucker reset now set to 10ms ' soldering checked under binoculars. ' Upload Version 1.21 performed. Include "18F2525.inc" ' (40MHz) ' Mapping defines for midi-events on pin outputs and inputs: $define Dir0 PORTA.0 ' direction for coil 1 0=L , 1=R) $define Ena0 PORTA.2 ' bridge enable bit - strobe $define Dir1 PORTA.1 $define Ena1 PORTA.3 $define Dir2 PORTA.4 $define Ena2 PORTC.0 $define Dir3 PORTA.5 $define Ena3 PORTC.1 $define Dir4 PORTC.2 $define Ena4 PORTC.4 $define Dir5 PORTC.3 $define Ena5 PORTC.5 $define Dir6 PORTB.0 $define Ena6 PORTB.2 $define Dir7 PORTB.1 $define Ena7 PORTB.3 $define BlueLed PORTB.4 ' if repeats are programmed, this LED will go ON 'red LED for debug: $define Debug_Led PORTB.5 ' for testing - red led - watchdog Declare All_Digital = True ' makes all analog pins, digital for I/O ' configure the input and output pins: Clear SSPCON1.5 'RC3 must be available for I/O TRISA = %01000000 'bits set to 0 are output, 1 = input TRISB = %11100000 TRISC = %11000000 'RC1 en RC2 zijn pwm outputs and must be set to output 'RC6 en RC7 zijn USART I/O and must be set to input 'constant definitions: Symbol noot0 = 82 ' default Qanun tuning Symbol noot1 = 83 Symbol noot2 = 84 Symbol noot3 = 85 Symbol noot4 = 86 Symbol noot5 = 87 Symbol noot6 = 88 ' nc Symbol noot7 = 89 ' nc 'initialisations for the midi input parser: Symbol Midichannel = 4 ' Zi_Channel Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel Symbol Keypres_Status = 160 + Midichannel Symbol Control_Status = 176 + Midichannel Symbol ProgChange_Status = 192 + Midichannel ' 1 byte message Symbol Aftertouch_Status = 208 + Midichannel ' 1 byte follows Symbol Pitchbend_Status = 224 + Midichannel ' lsb msb follow ' Setup the USART Declare Hserial_Baud = 31250 ' Set baud rate for the USART to MIDI specs. Declare Hserial_TXSTA = 0x24 ' instead of the normal 0x20 - ?? 0x24 ' Declare Hserial_Clear = On ' should clear on errors. Bytes get lost of course... ' Create variables: ' Dim Cnt As Dword System '32 bit counter ' Dim CntHw As Cnt.Word1 ' Word System 'used in the timer0 interrupt, where it is incremented ' Dim CntLw As TMR0L.Word 'this is the trick to read both TMR0L and TMR0H 'it makes Cntlw the low word of cnt, when we use cnt.word0=CntLw ' Dim Tim1 As TMR1L.Word 'not used here ' Dim Tim2 As TMR2 'not used here ' Dim Cnt3 As Dword System ' Dim Cnt3Hw As Cnt3.Word1 ' Dim Tim3 As TMR3L.Word ' same trick for timer3 ' Dim Sr as TMR0L.7 '512 S/s - this works but these DO NOT WORK!!!: ' Dim Sr as CntLw.Byte1 does not ' Dim Sr As TMR0H.0 'sampling rate bit, 256 S/s ' DIM Sr as CntLw.8 ' As TMR0H.1 would be 128 S/s ' As TMR0H.2 would be 64 S/s ' As TMR0H.3 would be 32 S/s ' As TMR0H.4 would be 16 S/s Dim Bytein As Byte System ' midi byte read from buffer Dim StBit As Bytein.7 ' highest bit of ByteIn Dim i As Byte System ' general purpose counter ' midi variables Dim statusbyte As Byte System Dim noteUit As Byte System ' note off + release value Dim release As Byte System Dim noteAan As Byte System ' note on + release value Dim velo As Byte System Dim notePres As Byte System ' note pressure + pressure value Dim pres As Byte System Dim Ctrl As Byte System ' continuous controller + value Dim value As Byte System Dim prog As Byte System ' program change + program-byte Dim aft As Byte System ' channel aftertouch ' Dim pblsb As Byte System ' pitch bend lsb ' Dim pbmsb As Byte System ' pitch bend msb ' Dim veltim As Dword System ' 32 bit velo Dim veltim0 As Dword System ' faster, replaces the arrays Dim veltim1 As Dword System ' Dim veltim2 As Dword System ' velo pulse timer Dim veltim3 As Dword System Dim veltim4 As Dword System Dim veltim5 As Dword System Dim veltim6 As Dword System Dim veltim7 As Dword System Dim Velflags As Byte System ' so we can have only 8 tasks Dim CC66 As Byte System ' global on/off switch Dim PowerOn As CC66.0 ' handled on the hub board. Dim notes As Byte System Dim LRbyte As Byte Dim LR0 As LRbyte.0 ' 0= left, 1= right Dim LR1 As LRbyte.1 Dim LR2 As LRbyte.2 Dim LR3 As LRbyte.3 Dim LR4 As LRbyte.4 Dim LR5 As LRbyte.5 Dim LR6 As LRbyte.6 Dim LR7 As LRbyte.7 Dim Rate0 As Word System ' set with key pressure Dim Rate1 As Word System Dim Rate2 As Word System Dim Rate3 As Word System Dim Rate4 As Word System Dim Rate5 As Word System Dim Rate6 As Word System Dim Rate7 As Word System Dim velo0 As Word System Dim velo1 As Word System Dim velo2 As Word System Dim velo3 As Word System Dim velo4 As Word System Dim velo5 As Word System Dim velo6 As Word System Dim velo7 As Word System Dim Pres0 As Byte System 'indexes for durations lookup Dim Pres1 As Byte System Dim Pres2 As Byte System Dim Pres3 As Byte System Dim Pres4 As Byte System Dim Pres5 As Byte System Dim Pres6 As Byte System Dim Pres7 As Byte System Dim time As Dword System ' 32-bit, incremented in loopcounter Dim maxtim As time.31 ' overflow bit, will cause timer reset after 1h45 Dim t As Byte System ' loopcounter, running at 4 times time-clock Dim tog As Byte System Dim tg As tog.0 ' divide by 4 bit Dim TimVals[8] As Dword ' lijst met timer waarden - de kleinste is eerst aan de beurt Dim Nxt As Dword System ' waarde voor de eerstvolgende timer Dim idx As Byte System ' index voor de eerstvolgende timer '----------------------------------------------------------------------------------------- ' Load the USART Interrupt handler and buffer read subroutines into memory Include "Zi_Irq.inc" ' for UART,Timer0, Timer3 Interrupt 'Clear ' clear all RAM '----------------------------------------------------------------------------------------- Dim dummy[256] As Word ' unusable memory space ' must overlap with Dim Ringbuffer[256] As Byte At __Start_Of_Reserve_Ram ' in the interrupt handler Dim vels[128] As Word ' velocity lookup table Dim Dur[128] As Word ' duration lookup for repetitions ' Main program starts here MAIN: High Debug_Led DelayMS 10 ' wait for stability Low Debug_Led ' make sure all enable bits are low to disable the bridges Low Ena0 Low Ena1 Low Ena2 Low Ena3 Low Ena4 Low Ena5 Low Ena6 Low Ena7 ' set all dirs to a known value: Low Dir0 Low Dir1 Low Dir2 Low Dir3 Low Dir4 Low Dir5 Low Dir6 Low Dir7 Low BlueLed Clear LRbyte ' 0 = left (inwards) Clear notes Clear Velflags Set TimVals ' minvel = 0 '2048 '8 << 3 ' =2048 ' default value for controller 14 Clear CC66 Clear Pres0 Clear Pres1 Clear Pres2 Clear Pres3 Clear Pres4 Clear Pres5 Clear Pres6 Clear Pres7 Clear Rate0 Clear Rate1 Clear Rate2 Clear Rate3 Clear Rate4 Clear Rate5 Clear Rate6 Clear Rate7 Clear velo0 Clear velo1 Clear velo2 Clear velo3 Clear velo4 Clear velo5 Clear velo6 Clear velo7 GoSub Plucker_Reset ' reset pluckers on a cold boot Init_Usart_Interrupt ' Initiate the USART serial buffer interrupt ' this procedure is in the include file Clear_Serial_Buffer ' Clear the serial buffer and reset its pointers ' in the include as well ' Configure Timer0 for: ' Clear TMR0L and TMR0H registers ' Interrupt on Timer0 overflow ' 16-bit operation ' Internal clock source 40MHz ' 1:256 Prescaler : thus 40MHz / 256 = 156.250kHz ' 6.4 us per clock-tick ' Opentimer0 (Timer_INT_On & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256) ' replacing above macro with in-line coding: Clear T1CON Clear IntConBits_T0IF ' clear interrupt flag Set INTCONBITS_T0IE ' enable interrupt on overflow T0CON = %10000111 ' bit 7 = enable/disable ' bit 6 = 1=8 bot, 0=16 bit ' bit 5 = 1 pin input, 0= Internal Clk0 ' bit 4 = HL or LH transition when bit5 =1 ' bit 3 = 1= bypass prescaler, 0= input from prescaler ' bit 2-0 = prescaler select: 111= 1:256 ' Setup the High priorities for the interrupts ' TIMER1: if enabled, all midi-in is blocked, so it must interfere with the UART ' Configure Timer1 for: ' Clear TMR1L and TMR1H registers ' Interrupt on Timer1 overflow ' 16-bit read/write mode ' Internal clock source ' 1:8 Prescaler ' ' OpenTimer1(TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_8) ' dit kompileert o.k. ' TIMER2: if enabled, the UART stops working... ' Opentimer2 (Timer_Int_On & T2_POST_1_16 & T2_PS_1_16) ' dit lukt... maar de timer is nodig voor de UART... ' TIMER3: ' Configure Timer3 for: ' Interrupt on Timer3 overflow ' 16-bit read/write mode ' Internal clock source ' 1:8 Prescaler ' Don’t sync external clock input ' T3_OSC1En_On () ' macro ' OpenTimer3(TIMER_INT_ON & T3_16BIT_RW & T3_SOURCE_INT & T3_PS_1_8 & T3_SYNC_EXT_OFF) ' fout, but == voorbeeld??? ' Opentimer3 (Timer_Int_On & T3_16BIT_RW & T3_SOURCE_INT & T3_PS_1_8 & T3_SYNC_EXT_OFF & T3_SOURCE_CCP) ' fout ' OpenTimer3 (Timer_INT_ON & T3_16BIT_RW & T3_PS_1_8 & T3_SYNC_EXT_OFF) ' fout ' OpenTimer3 (0xFFFF & Timer_INT_On & T3_16BIT_RW) ' OpenTimer3(T3_8BIT_RW & T3_SOURCE_EXT & T3_PS_1_1 & T3_SYNC_EXT_OFF) ' copied from manual, fout!!! ' OpenTimer3(TIMER_INT_OFF & T3_16BIT_RW & T3_SOURCE_INT & T3_PS_1_8) ' doing it this way seems to work: Clear T3CON Clear PIR2BITS_TMR3IF ' clear IRQ flag Set PIE2BITS_TMR3IE ' irq on 'T3_OSC1En_On () ' macro - sets T3CON ' Clear Tim3 ' Clear TMR3L And TMR3H registers Set RCONbits_IPEN ' Enable priority interrupts Clear IPR2bits_TMR3IP ' Set Timer3 as a low priority interrupt source ' we can also set T3Con in one instruction as: T3CON = %10110001 ' oef, now it works... ' bit 7 = 16 bit mode ' bit 6,3 = 0, 0 ' bit 5,4 = 1:8 prescale ' bit 2 = 0 ' bit 1 = 0 Internal clock = Fosc/4 ' bit 0 : 1= enable timer 3, 0= disable ' maximum count = 52.42ms, 1 tick =0.8uS, freq.=19Hz ' Set up priority interrupts. ' IPR1bits_TMR1IP = 0 ' Set Timer1 as a low priority interrupt source ' INTCONbits_PEIE = 1 ' Enable peripheral interrupts ' INTCONbits_GIE = 1 ' Enable global interrupts ' Open the ADC: ' not used on this board. ' Fosc/32 ' Right justified for 10-bit operation ' Tad value of 0 ' Vref+ at Vcc : Vref- at Gnd ' Make AN0 an analogue input ' OpenADC(ADC_FOSC_32 & ADC_RIGHT_JUST & ADC_0_TAD, ADC_REF_VDD_VSS, ADC_1ANA) GoSub Dur_Lookup GoSub Vels_Lookup ' start the main program loop: LOOP: ' Create an infinite loop Inc t ' byte If t.1 = tg Then Btg tg Inc time ' dword EndIf Bytein = HRSIn ' Read data from the serial buffer, with no timeout ' Start the midi parser. Midi_Parse: If Bytein > Control_Status Then ' here higher statusses are not implemented. If Bytein > 253 Then '254 = midiclock, 255= reset 'midiclock can interrupt all other msg's... '255 had to be intercepted since thats what we 'get when no new byte flows in. Else Clear statusbyte 'reset the status byte End If GoTo Check_Timers 'throw away... EndIf If StBit =1 Then 'should be faster than If Bytein > 127 Then 'status byte received, bit 7 is set Clear statusbyte 'if on another channel, the statusbyte needs a reset Select Bytein 'eqv to Select case ByteIn Case NoteOff_Status statusbyte = Bytein Set noteUit 'reset value. Cannot be 0 !!! Set release '0 is a valid midi note! Case NoteOn_Status statusbyte = Bytein Set noteAan '= 255 Set velo '= 255 Case Keypres_Status 'not used here statusbyte = Bytein notePres = 255 pres = 255 Case Control_Status ' controllers and switches statusbyte = Bytein Set Ctrl Set value ' Case ProgChange_Status ' could be used for different lookup tables ' statusbyte = Bytein ' prog = 255 ' Case Aftertouch_Status ' for fingered vibrato, freq.changes during notes ' statusbyte = Bytein ' Set aft ' Case Pitchbend_Status ' not on this board. ' statusbyte = Bytein ' pblsb = 255 ' pbmsb = 255 End Select Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Check_Timers 'disregard Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein Else release = Bytein 'message complete, so we can do the action... Select noteUit Case noot0 Clear Velflags.0 ' cancel running timer Clear notes.0 Clear Ena0 ' should be cleared by timer already 'If LR0 = 0 Then ' staat naar links ' Clear Bel1VeloL ' Clear Bel1HoldL 'Else ' staat naar rechts ' Clear Bel1VeloR ' Clear Bel1HoldR 'EndIf Case noot1 Clear Velflags.1 ' cancel running timer Clear notes.1 Clear Ena1 Case noot2 Clear Velflags.2 ' cancel running timer Clear notes.2 Clear Ena2 Case noot3 Clear Velflags.3 ' cancel running timer Clear notes.3 Clear Ena3 Case noot4 Clear Velflags.4 ' cancel running timer Clear notes.4 Clear Ena4 Case noot5 Clear Velflags.5 Clear notes.5 Clear Ena5 Case noot6 Clear Velflags.6 Clear notes.6 Clear Ena6 Case noot7 Clear Velflags.7 Clear notes.7 Clear Ena7 End Select Set noteUit '= 255 'reset GoTo resort EndIf GoTo Check_Timers Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then Select noteAan Case noot0 Clear Velflags.0 ' cancel running timer Clear notes.0 Clear Ena0 Case noot1 Clear Velflags.1 ' cancel running timer Clear notes.1 Clear Ena1 Case noot2 Clear Velflags.2 ' cancel running timer Clear notes.2 Clear Ena2 Case noot3 Clear Velflags.3 ' cancel running timer Clear notes.3 Clear Ena3 Case noot4 Clear Velflags.4 ' cancel running timer Clear notes.4 Clear Ena4 Case noot5 Clear Velflags.5 Clear notes.5 Clear Ena5 Case noot6 Clear Velflags.6 Clear notes.6 Clear Ena6 Case noot7 Clear Velflags.7 Clear notes.7 Clear Ena7 Case Else GoTo Check_Timers End Select GoTo resort Else Select noteAan Case noot0 If LR0 = 0 Then Set Dir0 ' move outward Else Clear Dir0 ' move inwards EndIf Toggle LR0 ' reflects the position now Set Ena0 ' Current through bridge ON Set Velflags.0 velo0 = vels[velo] ' read lookup TimVals[0] = time + velo0 If Pres0 > 0 Then ' if note repeats are programmed... Set notes.0 Rate0 = Dur[Pres0] - velo0 ' dur's must be > velo Else Clear notes.0 EndIf Case noot1 If LR1 = 0 Then Set Dir1 ' move outward Else Clear Dir1 ' move inwards EndIf Toggle LR1 ' reflects the position now Set Ena1 ' Current through bridge ON Set Velflags.1 velo1 = vels[velo] ' read lookup TimVals[1] = time + velo1 If Pres1 > 0 Then ' if note repeats are programmed... Set notes.1 Rate1 = Dur[Pres1] - velo1 Else Clear notes.1 EndIf Case noot2 If LR2 = 0 Then Set Dir2 ' move outward Else Clear Dir2 ' move inwards EndIf Toggle LR2 ' reflects the position now Set Ena2 ' Current through bridge ON Set Velflags.2 velo2 = vels[velo] ' read lookup TimVals[2] = time + velo2 If Pres2 > 0 Then ' if note repeats are programmed... Set notes.2 Rate2 = Dur[Pres2] - velo2 Else Clear notes.2 EndIf Case noot3 If LR3 = 0 Then Set Dir3 ' move outward Else Clear Dir3 ' move inwards EndIf Toggle LR3 ' reflects the position now Set Ena3 ' Current through bridge ON Set Velflags.3 velo3 = vels[velo] ' read lookup TimVals[3] = time + velo3 If Pres3 > 0 Then ' if note repeats are programmed... Set notes.3 'If Dur[Pres3] <= velo3 Then ' Rate3 = velo3 ' stick to 50% duty cycle 'Else Rate3 = Dur[Pres3] - velo3 'EndIf Else Clear notes.3 EndIf Case noot4 If LR4 = 0 Then Set Dir4 ' move outward Else Clear Dir4 ' move inwards EndIf Toggle LR4 ' reflects the position now Set Ena4 ' Current through bridge ON Set Velflags.4 velo4 = vels[velo] ' read lookup TimVals[4] = time + velo4 If Pres4 > 0 Then ' if note repeats are programmed... Set notes.4 Rate4 = Dur[Pres4] - velo4 Else Clear notes.4 EndIf Case noot5 If LR5 = 0 Then Set Dir5 ' move outward Else Clear Dir5 ' move inwards EndIf Toggle LR5 ' reflects the position now Set Ena5 ' Current through bridge ON Set Velflags.5 velo5 = vels[velo] ' read lookup TimVals[5] = time + velo5 If Pres5 > 0 Then ' if note repeats are programmed... Set notes.5 Rate5 = Dur[Pres5] - velo5 Else Clear notes.5 EndIf Case noot6 If LR6 = 0 Then Set Dir6 ' move outward Else Clear Dir6 ' move inwards EndIf Toggle LR6 ' reflects the position now Set Ena6 ' Current through bridge ON Set Velflags.6 velo6 = vels[velo] ' read lookup TimVals[6] = time + velo6 If Pres6 > 0 Then ' if note repeats are programmed... Set notes.6 Rate6 = Dur[Pres6] - velo6 Else Clear notes.6 EndIf Case noot7 If LR7 = 0 Then Set Dir7 ' move outward Else Clear Dir7 ' move inwards EndIf Toggle LR7 ' reflects the position now Set Ena7 ' Current through bridge ON Set Velflags.7 velo7 = vels[velo] ' read lookup TimVals[7] = time + velo7 If Pres7 > 0 Then ' if note repeats are programmed... Set notes.7 Rate7 = Dur[Pres7] - velo7 Else Clear notes.7 EndIf Case Else Set noteAan GoTo Check_Timers End Select Set noteAan '= 255 'reset !!! GoTo resort EndIf EndIf GoTo Check_Timers Case Keypres_Status 'used for lite flashing on Fa-Hub 'in used by PIC2 for fingerings !!! 'here we could use it for fingered vibrato If notePres = 255 Then notePres = Bytein Else pres = Bytein GoSub KeyPres EndIf GoTo Check_Timers Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein Else value = Bytein GoSub Controller ' fingerings implemented here EndIf GoTo Check_Timers ' Case ProgChange_Status ' could be used to select alternative fingering lookups ' If prog = 255 Then 'single byte message ' prog = Bytein 'weak coding... ' GoSub ProgChange ' EndIf ' GoTo Check_Timers ' Case Aftertouch_Status ' for changing vibrato frequency during notes ' If aft = 255 Then ' aft = Bytein ' GoSub Aftertouch ' EndIf ' GoTo Check_Timers End Select EndIf resort: GoSub SortTimers ' so we resort only if an incoming midi command changed something Check_Timers: If idx < 8 Then ' we moeten alleen checken wanneer er een timer loopt If time >= Nxt Then ' nagaan of de eerstvolgende timer afgelopen is... ' in dit geval is de eerste timer afgelopen en moeten we de juiste aktie ondernemen: Set Nxt.31 ' timer reset, is immers afgelopen ' aan de hand van idx weten we welke timer dit is Select idx Case 0 ' noot0 Clear Ena0 ' cut current to bridge If notes.0 = 0 Then ' note off Set TimVals[0] ' cancel timer - no repeats Else ' note is active If Velflags.0 = 1 Then ' velo timer afgelopen TimVals[0] = time + Rate0 ' wachttijd gaat in Clear Velflags.0 Else ' wachttijd is afgelopen If LR0 = 0 Then ' staat links Set Dir0 ' naar rechts Else ' staat rechts Clear Dir0 ' ga naar links EndIf Set Ena0 ' bekrachtig de brug Toggle LR0 ' huidige positie TimVals[0] = time + velo0 ' stel een nieuwe velo-timer in Set Velflags.0 ' aktiveer hem ook EndIf EndIf Case 1 ' noot1 Clear Ena1 ' cut current to bridge If notes.1 = 0 Then ' note off Set TimVals[1] ' cancel timer - no repeats Else ' note is active If Velflags.1 = 1 Then ' velo timer afgelopen TimVals[1] = time + Rate1 ' wachttijd gaat in Clear Velflags.1 Else ' wachttijd is afgelopen If LR1 = 0 Then ' staat links Set Dir1 ' naar rechts Else ' staat rechts Clear Dir1 ' ga naar links EndIf Set Ena1 ' bekrachtig de brug Toggle LR1 ' huidige positie TimVals[1] = time + velo1 ' stel een nieuwe velo-timer in Set Velflags.1 ' aktiveer hem ook EndIf EndIf Case 2 ' noot2 Clear Ena2 ' cut current to bridge If notes.2 = 0 Then ' note off Set TimVals[2] ' cancel timer - no repeats Else ' note is active If Velflags.2 = 1 Then ' velo timer afgelopen TimVals[2] = time + Rate2 ' wachttijd gaat in Clear Velflags.2 Else ' wachttijd is afgelopen If LR2 = 0 Then ' staat links Set Dir2 ' naar rechts Else ' staat rechts Clear Dir2 ' ga naar links EndIf Set Ena2 ' bekrachtig de brug Toggle LR2 ' huidige positie TimVals[2] = time + velo2 ' stel een nieuwe velo-timer in Set Velflags.2 ' aktiveer hem ook EndIf EndIf Case 3 ' noot3 Clear Ena3 ' cut current to bridge If notes.3 = 0 Then ' note off Set TimVals[3] ' cancel timer - no repeats Else ' note is active If Velflags.3 = 1 Then ' velo timer afgelopen TimVals[3] = time + Rate3 ' wachttijd gaat in Clear Velflags.3 Else ' wachttijd is afgelopen If LR3 = 0 Then ' staat links Set Dir3 ' naar rechts Else ' staat rechts Clear Dir3 ' ga naar links EndIf Set Ena3 ' bekrachtig de brug Toggle LR3 ' huidige positie TimVals[3] = time + velo3 ' stel een nieuwe velo-timer in Set Velflags.3 ' aktiveer hem ook EndIf EndIf Case 4 ' noot4 Clear Ena4 ' cut current to bridge If notes.4 = 0 Then ' note off Set TimVals[4] ' cancel timer - no repeats Else ' note is active If Velflags.4 = 1 Then ' velo timer afgelopen TimVals[4] = time + Rate4 ' wachttijd gaat in Clear Velflags.4 Else ' wachttijd is afgelopen If LR4 = 0 Then ' staat links Set Dir4 ' naar rechts Else ' staat rechts Clear Dir4 ' ga naar links EndIf Set Ena4 ' bekrachtig de brug Toggle LR4 ' huidige positie TimVals[4] = time + velo4 ' stel een nieuwe velo-timer in Set Velflags.4 ' aktiveer hem ook EndIf EndIf Case 5 ' noot5 Clear Ena5 ' cut current to bridge If notes.5 = 0 Then ' note off Set TimVals[5] ' cancel timer - no repeats Else ' note is active If Velflags.5 = 1 Then ' velo timer afgelopen TimVals[5] = time + Rate5 ' wachttijd gaat in Clear Velflags.5 Else ' wachttijd is afgelopen If LR5 = 0 Then ' staat links Set Dir5 ' naar rechts Else ' staat rechts Clear Dir5 ' ga naar links EndIf Set Ena5 ' bekrachtig de brug Toggle LR5 ' huidige positie TimVals[5] = time + velo5 ' stel een nieuwe velo-timer in Set Velflags.5 ' aktiveer hem ook EndIf EndIf Case 6 ' noot6 Clear Ena6 ' cut current to bridge If notes.6 = 0 Then ' note off Set TimVals[6] ' cancel timer - no repeats Else ' note is active If Velflags.6 = 1 Then ' velo timer afgelopen TimVals[6] = time + Rate6 ' wachttijd gaat in Clear Velflags.6 Else ' wachttijd is afgelopen If LR6 = 0 Then ' staat links Set Dir6 ' naar rechts Else ' staat rechts Clear Dir6 ' ga naar links EndIf Set Ena6 ' bekrachtig de brug Toggle LR6 ' huidige positie TimVals[6] = time + velo6 ' stel een nieuwe velo-timer in Set Velflags.6 ' aktiveer hem ook EndIf EndIf Case 7 ' noot7 Clear Ena7 ' cut current to bridge If notes.7 = 0 Then ' note off Set TimVals[7] ' cancel timer - no repeats Else ' note is active If Velflags.7 = 1 Then ' velo timer afgelopen TimVals[7] = time + Rate7 ' wachttijd gaat in Clear Velflags.7 Else ' wachttijd is afgelopen If LR7 = 0 Then ' staat links Set Dir7 ' naar rechts Else ' staat rechts Clear Dir7 ' ga naar links EndIf Set Ena7 ' bekrachtig de brug Toggle LR7 ' huidige positie TimVals[7] = time + velo7 ' stel een nieuwe velo-timer in Set Velflags.7 ' aktiveer hem ook EndIf EndIf 'Case Else ' ' in dit geval is idx geset ' GoTo jumpout End Select GoSub SortTimers ' find a new nxt and idx EndIf ' beveiliging tegen overflow crashes... If maxtim = 1 Then Clear time Clear Velflags Clear notes Set TimVals EndIf Else ' idx > 7, no timers running, so to avoid overflows, we can reset the loop timer If maxtim = 1 Then Clear time ' 16.06.2015 EndIf ' Btg PORTB.2 ' average loop-speed: 4.5 microseconds, 5.45 us under full load. (Tektronix measurement) GoTo LOOP SortTimers: 'look up the next smallest timer value in the Timvals array ' zoek de de volgende kleinste timer waarde: Set idx ' makes it 255 Set Nxt.31 ' nxt is set on entry. - for speed, we just set the highest bit For i = 0 To 7 If TimVals[i] < Nxt Then Nxt = TimVals[i] ' 8 dword comparisons idx = i EndIf Next i Return KeyPres: ' used for auto-repeat in Select notePres Case noot0 Pres0 = pres If Pres0 > 0 Then Rate0 = Dur[Pres0] ' note that we set notes.0 only on reception of a note-on ' this way we can program the repeats prior to playing. Else Clear Rate0 Clear notes.0 EndIf Case noot1 Pres1 = pres If Pres1 > 0 Then Rate1 = Dur[Pres1] Else Clear Rate1 Clear notes.1 EndIf Case noot2 Pres2 = pres If Pres2 > 0 Then Rate2 = Dur[Pres2] Else Clear Rate2 Clear notes.2 EndIf Case noot3 Pres3 = pres If Pres3 > 0 Then Rate3 = Dur[Pres3] Else Clear Rate3 Clear notes.3 EndIf Case noot4 Pres4 = pres If Pres4 > 0 Then Rate4 = Dur[Pres4] Else Clear Rate4 Clear notes.4 EndIf Case noot5 Pres5 = pres If Pres5 > 0 Then Rate5 = Dur[Pres5] Else Clear Rate5 Clear notes.5 EndIf Case noot6 Pres6 = pres If Pres6 > 0 Then Rate6 = Dur[Pres6] Else Clear Rate6 Clear notes.6 EndIf Case noot7 Pres7 = pres If Pres7 > 0 Then Rate7 = Dur[Pres7] Else Clear Rate7 Clear notes.7 EndIf EndSelect ' we do not need to resort here Set notePres '= 255 Return 'ProgChange: ' Set prog '= 255 'this is not realy required 'Return 'Pitchbend: ' Set pblsb 'Return Aftertouch: ' 'this is the channel aftertouch, affecting any playing note ' 'used for fingered vibrato in instruments such as ' 'the value of aft is used to set or modify the vibrato speed. Minimum freq=19Hz/2 = 9.54Hz ' coding using timer3: ' If aft > 0 Then ' Clear T3CONBITS_TMR3ON ' stop timer ' CC31 = aft ' VibratoPeriod = CC31 << 9 '* CC31 ' Tim3 = VibratoPeriod ' Set T3CONBITS_TMR3ON ' restart timer ' Else ' Clear CC31 ' Clear VibratoPeriod ' Clear T3CONBITS_TMR3ON ' stop timer ' EndIf Set aft ' reset Return Controller: Select Ctrl ' Case 14 ' minvel = value '<< 8 ' sets minimum velocity for plucking the strings Case 30 ' can be used for global repeat frequency of the pluckers ' controller to set all repeat frequencies to one and the same value at once If value = 0 Then Clear BlueLed Clear notes Clear Rate0 Clear Pres0 Clear Rate1 Clear Pres1 Clear Rate2 Clear Pres2 Clear Rate3 Clear Pres3 Clear Rate4 Clear Pres4 Clear Rate5 Clear Pres5 Clear Rate6 Clear Pres6 Clear Rate7 Clear Pres7 Else Pres0 = value Rate0 = Dur[value] Pres1 = value Rate1 = Dur[value] Pres2 = value Rate2 = Dur[value] Pres3 = value Rate3 = Dur[value] Pres4 = value Rate4 = Dur[value] Pres5 = value Rate5 = Dur[value] Pres6 = value Rate6 = Dur[value] Pres7 = value Rate7 = Dur[value] Set BlueLed EndIf Case 66 'on/off for the robot If value = 0 Then Clear PowerOn 'CC66.0 =0 GoSub PowerDown Else Set PowerOn 'CC66.0 =1 EndIf Case 123 Clear Velflags Clear notes Clear Ena0 Clear Ena1 Clear Ena2 Clear Ena3 Clear Ena4 Clear Ena5 Clear Ena6 Clear Ena7 Case 127 ' causes a plucker reset GoSub Plucker_Reset End Select Set Ctrl 'mandatory reset Return PowerDown: Clear Velflags 'stop all running timers Clear notes Clear Ena0 Clear Ena1 Clear Ena2 Clear Ena3 Clear Ena4 Clear Ena5 Clear Ena6 Clear Ena7 ' keep the solenoid positions! Dir0 to Dir7 ' we should also reset all programmed repeat frequencies. Clear Rate0 Clear Pres0 Clear Rate1 Clear Pres1 Clear Rate2 Clear Pres2 Clear Rate3 Clear Pres3 Clear Rate4 Clear Pres4 Clear Rate5 Clear Pres5 Clear Rate6 Clear Pres6 Clear Rate7 Clear Pres7 Clear BlueLed Return Plucker_Reset: ' this procedure sets all pluckers inwards. ' it takes about 80ms and should not be interrupted. Clear LRbyte Clear Rate0 Clear Pres0 Clear Rate1 Clear Pres1 Clear Rate2 Clear Pres2 Clear Rate3 Clear Pres3 Clear Rate4 Clear Pres4 Clear Rate5 Clear Pres5 Clear Rate6 Clear Pres6 Clear Rate7 Clear Pres7 Clear velo0 Clear velo1 Clear velo2 Clear velo3 Clear velo4 Clear velo5 Clear velo6 Clear velo7 Set TimVals[0] Set TimVals[1] Set TimVals[2] Set TimVals[3] Set TimVals[4] Set TimVals[5] Set TimVals[6] Set TimVals[7] Set Nxt Set idx Clear Dir0 Set Ena0 DelayMS 10 Clear Ena0 Clear Dir1 Set Ena1 DelayMS 10 Clear Ena1 Clear Dir2 Set Ena2 DelayMS 10 Clear Ena2 Clear Dir3 Set Ena3 DelayMS 10 Clear Ena3 Clear Dir4 Set Ena4 DelayMS 10 Clear Ena4 Clear Dir5 Set Ena5 DelayMS 10 Clear Ena5 Clear Dir6 Set Ena6 DelayMS 10 Clear Ena6 Clear Dir7 Set Ena7 DelayMS 10 Clear Ena7 Clear BlueLed Return Dur_Lookup: '09.06.2015: for these bells a good range would be fastest = 30 Hz, slowest = 1 Hz ' this is a tempered distribution! ' same look-up as on the pulse boards in bello Set Dur[0] ' not used Dur[1]= 41667 ' freq= .999992000063999 Dur[2]= 39494 ' freq= 1.0550125757499 Dur[3]= 38450 ' freq= 1.08365843086259 Dur[4]= 37434 ' freq= 1.11307011451265 Dur[5]= 36445 ' freq= 1.14327525495038 Dur[6]= 35482 ' freq= 1.17430434210774 Dur[7]= 34544 ' freq= 1.20619113787247 Dur[8]= 33631 ' freq= 1.23893629885126 Dur[9]= 32743 ' freq= 1.27253662360403 Dur[10]= 31877 ' freq= 1.30710752789367 Dur[11]= 31035 ' freq= 1.34257021642232 Dur[12]= 30215 ' freq= 1.37900601246621 Dur[13]= 29416 ' freq= 1.41646269603844 Dur[14]= 28639 ' freq= 1.45489251254117 Dur[15]= 27882 ' freq= 1.49439303732396 Dur[16]= 27146 ' freq= 1.53490999287802 Dur[17]= 26428 ' freq= 1.57661066545583 Dur[18]= 25730 ' freq= 1.61938074880166 Dur[19]= 25050 ' freq= 1.66333998669328 Dur[20]= 24388 ' freq= 1.70849051446066 Dur[21]= 23743 ' freq= 1.75490319953951 Dur[22]= 23116 ' freq= 1.8025033166061 Dur[23]= 22505 ' freq= 1.85144042064726 Dur[24]= 21910 ' freq= 1.90171915411532 Dur[25]= 21331 ' freq= 1.95333864641445 Dur[26]= 20768 ' freq= 2.006291730868 Dur[27]= 20219 ' freq= 2.06076792455941 Dur[28]= 19685 ' freq= 2.11667090000847 Dur[29]= 19164 ' freq= 2.17421554303207 Dur[30]= 18658 ' freq= 2.23317969057062 Dur[31]= 18165 ' freq= 2.29378842095605 Dur[32]= 17685 ' freq= 2.35604561304307 Dur[33]= 17218 ' freq= 2.41994811631239 Dur[34]= 16763 ' freq= 2.48563304102289 Dur[35]= 16320 ' freq= 2.5531045751634 Dur[36]= 15888 ' freq= 2.62252433702585 Dur[37]= 15469 ' freq= 2.69355916133342 Dur[38]= 15060 ' freq= 2.76671093404161 Dur[39]= 14662 ' freq= 2.84181330423316 Dur[40]= 14274 ' freq= 2.91906029610948 Dur[41]= 13897 ' freq= 2.99824902257082 Dur[42]= 13530 ' freq= 3.07957625030796 Dur[43]= 13172 ' freq= 3.16327563518575 Dur[44]= 12824 ' freq= 3.24911624038262 Dur[45]= 12485 ' freq= 3.33733813910025 Dur[46]= 12155 ' freq= 3.42794460441519 Dur[47]= 11834 ' freq= 3.52092839840009 Dur[48]= 11522 ' freq= 3.61627032343922 Dur[49]= 11217 ' freq= 3.71459986330272 Dur[50]= 10921 ' freq= 3.81527943106553 Dur[51]= 10632 ' freq= 3.91898670679709 Dur[52]= 10351 ' freq= 4.02537597011561 Dur[53]= 10078 ' freq= 4.13441820467024 Dur[54]= 9811 ' freq= 4.24693371385859 Dur[55]= 9552 ' freq= 4.36208821887214 Dur[56]= 9300 ' freq= 4.48028673835125 Dur[57]= 9054 ' freq= 4.60201752448273 Dur[58]= 8815 ' freq= 4.72679145396105 Dur[59]= 8582 ' freq= 4.85512312592247 Dur[60]= 8355 ' freq= 4.9870337123479 Dur[61]= 8134 ' freq= 5.12253094008688 Dur[62]= 7919 ' freq= 5.26160710527423 Dur[63]= 7710 ' freq= 5.40423692174665 Dur[64]= 7506 ' freq= 5.5511146638245 Dur[65]= 7308 ' freq= 5.70151432220398 Dur[66]= 7115 ' freq= 5.85617240571562 Dur[67]= 6927 ' freq= 6.01510995621 Dur[68]= 6744 ' freq= 6.1783313562673 Dur[69]= 6565 ' freq= 6.34678852500635 Dur[70]= 6392 ' freq= 6.51856487275761 Dur[71]= 6223 ' freq= 6.69559162247576 Dur[72]= 6059 ' freq= 6.87682235792485 Dur[73]= 5898 ' freq= 7.06454165253758 Dur[74]= 5743 ' freq= 7.25520924023449 Dur[75]= 5591 ' freq= 7.45245334764204 Dur[76]= 5443 ' freq= 7.65509216730969 Dur[77]= 5299 ' freq= 7.86311882745172 Dur[78]= 5159 ' freq= 8.07650061381405 Dur[79]= 5023 ' freq= 8.29517552591413 Dur[80]= 4890 ' freq= 8.52079072937969 Dur[81]= 4761 ' freq= 8.75166281593503 Dur[82]= 4635 ' freq= 8.98957209636821 Dur[83]= 4513 ' freq= 9.23258734027624 Dur[84]= 4393 ' freq= 9.48478640261021 Dur[85]= 4277 ' freq= 9.74203101862676 Dur[86]= 4164 ' freq= 10.0064040986231 Dur[87]= 4054 ' freq= 10.277914816642 Dur[88]= 3947 ' freq= 10.5565408326999 Dur[89]= 3843 ' freq= 10.842223956978 Dur[90]= 3741 ' freq= 11.1378419317473 Dur[91]= 3642 ' freq= 11.4406004027091 Dur[92]= 3546 ' freq= 11.7503290092122 Dur[93]= 3452 ' freq= 12.0702974121282 Dur[94]= 3361 ' freq= 12.3971040364971 Dur[95]= 3272 ' freq= 12.7343113284434 Dur[96]= 3186 ' freq= 13.0780498012136 Dur[97]= 3102 ' freq= 13.4321942832581 Dur[98]= 3020 ' freq= 13.7969094922737 Dur[99]= 2940 ' freq= 14.172335600907 Dur[100]= 2862 ' freq= 14.5585837409737 Dur[101]= 2787 ' freq= 14.9503647889008 Dur[102]= 2713 ' freq= 15.3581521071385 Dur[103]= 2641 ' freq= 15.7768522024486 Dur[104]= 2571 ' freq= 16.2064047711656 Dur[105]= 2504 ' freq= 16.640042598509 Dur[106]= 2437 ' freq= 17.0975242784845 Dur[107]= 2373 ' freq= 17.5586458772299 Dur[108]= 2310 ' freq= 18.037518037518 Dur[109]= 2249 ' freq= 18.5267526307989 Dur[110]= 2190 ' freq= 19.0258751902588 Dur[111]= 2132 ' freq= 19.5434646654159 Dur[112]= 2076 ' freq= 20.0706486833654 Dur[113]= 2021 ' freq= 20.616856341745 Dur[114]= 1967 ' freq= 21.182850364345 Dur[115]= 1915 ' freq= 21.7580504786771 Dur[116]= 1865 ' freq= 22.3413762287757 Dur[117]= 1815 ' freq= 22.9568411386593 Dur[118]= 1767 ' freq= 23.5804565176382 Dur[119]= 1721 ' freq= 24.2107301956227 Dur[120]= 1675 ' freq= 24.8756218905473 Dur[121]= 1631 ' freq= 25.5466993664418 Dur[122]= 1588 ' freq= 26.2384550797649 Dur[123]= 1546 ' freq= 26.9512721000431 Dur[124]= 1505 ' freq= 27.6854928017719 Dur[125]= 1465 ' freq= 28.4414106939704 Dur[126]= 1427 ' freq= 29.1987853305302 Dur[127]= 1389 ' freq= 29.9976001919846 Return Vels_Lookup: ' lookup table for the velocity controlled pulse durations vels[1]= 47 vels[2]= 52 vels[3]= 57 vels[4]= 62 vels[5]= 66 vels[6]= 71 vels[7]= 76 vels[8]= 81 vels[9]= 86 vels[10]= 91 vels[11]= 96 vels[12]= 101 vels[13]= 105 vels[14]= 110 vels[15]= 115 vels[16]= 120 vels[17]= 125 vels[18]= 130 vels[19]= 135 vels[20]= 140 vels[21]= 144 vels[22]= 149 vels[23]= 154 vels[24]= 159 vels[25]= 164 vels[26]= 169 vels[27]= 174 vels[28]= 179 vels[29]= 183 vels[30]= 188 vels[31]= 193 vels[32]= 198 vels[33]= 203 vels[34]= 208 vels[35]= 213 vels[36]= 218 vels[37]= 222 vels[38]= 227 vels[39]= 232 vels[40]= 237 vels[41]= 242 vels[42]= 247 vels[43]= 252 vels[44]= 257 vels[45]= 261 vels[46]= 266 vels[47]= 271 vels[48]= 276 vels[49]= 281 vels[50]= 286 vels[51]= 291 vels[52]= 296 vels[53]= 300 vels[54]= 305 vels[55]= 310 vels[56]= 315 vels[57]= 320 vels[58]= 325 vels[59]= 330 vels[60]= 335 vels[61]= 339 vels[62]= 344 vels[63]= 349 vels[64]= 354 vels[65]= 359 vels[66]= 364 vels[67]= 369 vels[68]= 374 vels[69]= 378 vels[70]= 383 vels[71]= 388 vels[72]= 393 vels[73]= 398 vels[74]= 403 vels[75]= 408 vels[76]= 413 vels[77]= 417 vels[78]= 422 vels[79]= 427 vels[80]= 432 vels[81]= 437 vels[82]= 442 vels[83]= 447 vels[84]= 452 vels[85]= 456 vels[86]= 461 vels[87]= 466 vels[88]= 471 vels[89]= 476 vels[90]= 481 vels[91]= 486 vels[92]= 491 vels[93]= 495 vels[94]= 500 vels[95]= 505 vels[96]= 510 vels[97]= 515 vels[98]= 520 vels[99]= 525 vels[100]= 530 vels[101]= 534 vels[102]= 539 vels[103]= 544 vels[104]= 549 vels[105]= 554 vels[106]= 559 vels[107]= 564 vels[108]= 569 vels[109]= 573 vels[110]= 578 vels[111]= 583 vels[112]= 588 vels[113]= 593 vels[114]= 598 vels[115]= 603 vels[116]= 608 vels[117]= 612 vels[118]= 617 vels[119]= 622 vels[120]= 627 vels[121]= 632 vels[122]= 637 vels[123]= 642 vels[124]= 647 vels[125]= 651 vels[126]= 656 vels[127]= 661 ' rescale velocities: For i = 1 To 127 vels[i] = vels[i] * 2 Next i Return '[EOF]