' ******************************************************************** ' * PIC firmware for Synchrochord * ' * finger solenoid component * ' * coded by dr.Godfried-Willem Raes * ' * http://www.logosfoundation.org/instrum_gwr/synchrochord/picworks * ' * source code development directory: * ' * SynFingers.bas * ' ******************************************************************** ' 15.01.2012: start code setup ' starting point Fa_Valve code!!! ' 16.01.2012: Pin mapping checked. ' We can use the velo-pulses as vibrato mechanism. ' We need only a single velo-timer, since it's a monophonic instrument. ' First sketch ready. Compiles o.k. ' Version 1.0 ' Implemented features: ' legato playing: note-off will not cause the solenoid to loosen ' vibrato implemented ' 17.01.2012: Midi implementation documented. ' 18.01.2012: test run op LED board. Some bugs. ' 19.01.2012: some optimizing... nothing works anymore??? ' 20.01.2012: Further testing and debugging. Works again now. ' PortD seems to give problems. Something wrong with the initialisation? ' TrisE, bit 4 must be cleared !!! otherwize, port D works in PSP mode!!! Include "18F4620.inc" ' for the Synchrochord finger processor (40MHz) ' Mapping defines for midi-events on pin outputs and inputs: ' This is very specific for the Pulse/Hold board Rev.2,2006 ' Velo1, Velo2.... ' Hold1, Hold2.... $define Hold1 PORTD.0 ' pin 19 ' first solenoid, board output 14 $define Velo1 PORTD.1 ' pin 20 $define Hold2 PORTC.2 ' pin 17 $define Velo2 PORTC.3 ' pin 18 $define Hold3 PORTC.0 ' pin 15 $define Velo3 PORTC.1 ' pin 16 $define Hold4 PORTD.3 ' pin 22 $define Velo4 PORTD.2 ' pin 21 $define Hold5 PORTC.5 ' pin 24 $define Velo5 PORTC.4 ' pin 23 $define Hold6 PORTD.5 ' pin 28 $define Velo6 PORTD.4 ' pin 27 $define Hold7 PORTD.7 ' pin 30 $define Velo7 PORTD.6 ' pin 29 $define Hold8 PORTB.1 ' pin 34 $define Velo8 PORTB.0 ' pin 33 $define Hold9 PORTB.3 ' pin 36 $define Velo9 PORTB.2 ' pin 35 $define Hold10 PORTE.2 ' pin 10 $define Velo10 PORTB.4 ' pin 37 $define Hold11 PORTE.0 ' pin 8 $define Velo11 PORTE.1 ' pin 9 $define Hold12 PORTA.4 ' pin 6 $define Velo12 PORTA.5 ' pin 7 $define Hold13 PORTA.0 ' pin 2 ' not used for finger solenoids - can be used for damper $define Velo13 PORTA.3 ' pin 5 $define Hold14 PORTA.2 ' pin 4 ' can be used for light $define Velo14 PORTA.1 ' pin 3 '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 Clear SSPCON1.5 ' make sure RC3 is free for use. ' configure the input and output pins: TRISA = %11000000 'bits set to 0 are output, 1 = input - bits 6 and 7 are the clock! TRISB = %11100000 'bits 6 and 7 are for the ICP, bit 5 is the red LED TRISC = %11000000 'RC6 en RC7 zijn USART I/O and must be set to input TRISD = %00000000 'all bits can be used TRISE = %11101000 'low nibble only, bit3 (RE3) is MCLR 'bit 4 most be zero to disable PSP mode on port D - gwr 20.01.2012 'this was the bug we had! 'constant definitions: Symbol LowTes = 39 Symbol HighTes = 87 'initialisations for the midi input parser: Symbol Midichannel = 10 ' SynchroChord_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 ' VIBRATO TIMER - not used: we use Tim3 Dim veltim2 As Dword System ' velo pulse timer Dim VelFlags0 As Byte System ' so we can have only 8 tasks ' VelFlags0.0 = solenoid release timer ' VelFlags0.1 = vibrato timer using timer 3 ' VelFlags0.2 = pulse timer for note-on's ' in Synchrochord we need 12 tasks! ' Dim VelFlags1 As Byte System Dim CC66 As Byte System ' global on/off switch Dim PowerOn As CC66.0 ' Dim st As Byte System ' Dim b1 As Byte System ' Dim b2 As Byte System Dim Idx As Byte System Dim CC30 As Byte System ' valve hold down time, midi value Dim ReleaseTime As Word System ' calculated from CC30 Dim VibratoPeriod As Word System ' claculated from CC31 Dim CC31 As Byte System ' vibrato controller, midi value Dim CC32 As Byte System ' PulseTime controller Dim PulseTime As Word System ' calculated from CC32 Dim solenoid As Byte ' solenoid active at any moment (0= none, 1-12=solenoid number) Dim oldsolenoid As Byte ' previously active solenoid. Dim NoteSolenoid[49] As Byte ' lookup table 0-48, 4 octaves ' index = midinote - lowtes '----------------------------------------------------------------------------------------- ' Load the USART Interrupt handler and buffer read subroutines into memory Include "SynFingers_Midi_Irq.inc" ' for UART,Timer0, Timer3 Interrupt 'Clear ' clear all RAM '----------------------------------------------------------------------------------------- ' Main program starts here MAIN: High Debug_Led DelayMS 10 ' wait for stability Low Debug_Led GoSub PowerDown GoSub Solenoid_Lookup ' read the fingerings lookup table Clear CC66 CC30 = 120 ' default release time CC32 = 10 ' default velo for pulse ReleaseTime = CC30 <<9 PulseTime = CC32 <<9 Clear CC31 ' default: no vibrato 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) ' start the main program loop: LOOP: ' Create an infinite loop 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... ' we can leave the solenoid ON, provided the damper works! Select noteUit Case LowTes To HighTes ' here we should start a timer. ' when the timer runs out, we release the solenoid. If NoteSolenoid[noteUit- LowTes] = oldsolenoid Then If oldsolenoid > 0 Then ' switch off the velo bit! On oldsolenoid GoSub V0o, V1o, V2o, V3o, V4o,V5o, V6o, V7o, V8o, V9o, V10o, V11o, V12o ' velo off Clear T3CONBITS_TMR3ON 'stop timer 3 Clear VelFlags0.1 'no fingered vibrato Clear VelFlags0.2 'clear velo-timer Cnt.Word0 = CntLw 'read counter veltim0 = Cnt + ReleaseTime 'add the period duration (CC30) Set VelFlags0.0 'set the timer ' when the timer runs out, the hold's will be switched off. Else ' in dit geval was geen enkele spoel bekrachtigd. Clear VelFlags0.0 ' in this case we have the open string. Clear VelFlags0.1 Clear VelFlags0.2 EndIf Else ' something is going wrong ' a note off was received that was never switched on... ' do nothing , or safer: 'On NoteSolenoid[noteUit - LowTes] GoSub Sol0o, Sol1o, Sol2o, Sol3o, Sol4o,Sol5o, Sol6o, Sol7o, Sol8o, Sol9o, Sol10o, Sol11o, Sol12o ' velo & hold off Clear VelFlags0.0 Clear VelFlags0.1 Clear VelFlags0.2 EndIf End Select Set noteUit '= 255 'reset EndIf GoTo Check_Timers Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then Select noteAan Case LowTes To HighTes ' equivalent to noteoff ' so we start a timer for solenoid releases. If NoteSolenoid[noteAan- LowTes] = oldsolenoid Then If oldsolenoid > 0 Then On oldsolenoid GoSub V0o, V1o, V2o, V3o, V4o,V5o, V6o, V7o, V8o, V9o, V10o, V11o, V12o ' velo off Clear T3CONBITS_TMR3ON 'stop timer 3 Clear VelFlags0.1 'no fingered vibrato Clear VelFlags0.2 'clear velo-timer Cnt.Word0 = CntLw 'read counter veltim0 = Cnt + ReleaseTime 'add the period duration (CC30) Set VelFlags0.0 'set the timer Else Clear VelFlags0.0 Clear VelFlags0.1 Clear VelFlags0.2 EndIf Else ' a note off was received that was never switched on... ' do nothing, or, safer: 'On NoteSolenoid[noteUit - LowTes] GoSub Sol0o, Sol1o, Sol2o, Sol3o, Sol4o,Sol5o, Sol6o, Sol7o, Sol8o, Sol9o, Sol10o, Sol11o, Sol12o Clear VelFlags0.0 Clear VelFlags0.1 Clear VelFlags0.2 EndIf End Select Else Select noteAan Case LowTes To HighTes Idx = noteAan - LowTes solenoid = NoteSolenoid[Idx] If solenoid <> oldsolenoid Then ' do action... Clear VelFlags0.1 ' no vibrato yet ' both velo and hold bits are turned on here: On solenoid GoSub Sol0, Sol1, Sol2, Sol3, Sol4, Sol5, Sol6, Sol7, Sol8, Sol9, Sol10, Sol11, Sol12 ' all on ' start velo-puls timer Cnt.Word0 = CntLw veltim2 = Cnt + PulseTime Set VelFlags0.2 ' switch the previous solenoid off: On oldsolenoid GoSub Sol0o, Sol1o, Sol2o, Sol3o, Sol4o,Sol5o, Sol6o, Sol7o, Sol8o, Sol9o, Sol10o, Sol11o, Sol12o oldsolenoid = solenoid Else ' no action required, but following ought to be the case On solenoid GoSub H0, H1, H2, H3, H4, H5, H6, H7, H8, H9, H10, H11, H12 'oldsolenoid = solenoid ' trivial 'vibrato should stay on and continue if no note-off was received. If CC31 > 0 Then Set VelFlags0.1 Set T3CONBITS_TMR3ON ' start timer End If End If Clear VelFlags0.0 ' release timer only set on note-off End Select Set noteAan '= 255 'reset !!! 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 Case Aftertouch_Status ' for changing vibrato frequency during notes If aft = 255 Then aft = Bytein GoSub Aftertouch EndIf ' GoTo Check_Timers End Select EndIf Check_Timers: ' here we check the Task counters and compare them with the 32 bit cnt value ' using the Velflags dword variable: If VelFlags0.0 = 1 Then ' on this board we use this timer for automatic release Cnt.Word0 = CntLw ' read counter If Cnt >= veltim0 Then ' do we use oldsolenoid here or solenoid??? On oldsolenoid GoSub Sol0o, Sol1o, Sol2o, Sol3o, Sol4o, Sol5o, Sol6o, Sol7o, Sol8o, Sol9o, Sol10o, Sol11o, Sol12o ' hold & velo off Clear solenoid ' open string condition Clear oldsolenoid Clear VelFlags0.0 ' one shot EndIf EndIf ' Velflags0.1: used in low priority irq for vibrato support. If VelFlags0.2 = 1 Then ' attack pulse for the solenoid Cnt.Word0 = CntLw If Cnt >= veltim2 Then On solenoid GoSub V0o, V1o, V2o, V3o, V4o,V5o, V6o, V7o, V8o, V9o, V10o, V11o, V12o ' velo off 'On solenoid GoSub H0, H1, H2, H3, H4, H5, H6, H7, H8, H9, H10, H11, H12 ' hold on If CC31 > 0 Then Set VelFlags0.1 Set T3CONBITS_TMR3ON ' start timer Else Clear VelFlags0.1 Clear T3CONBITS_TMR3ON ' stop timer End If Clear VelFlags0.2 ' one shot EndIf End If GoTo LOOP ' end of the main loop 'note hold-off: H0o: 'If OldSolenoid > 0 Then Clear OldSolenoid ' open string Clear oldsolenoid ' no action required. Return H1o: Clear Hold1 Return H2o: Clear Hold2 Return H3o: Clear Hold3 Return H4o: Clear Hold4 Return H5o: Clear Hold5 Return H6o: Clear Hold6 Return H7o: Clear Hold7 Return H8o: Clear Hold8 Return H9o: Clear Hold9 Return H10o: Clear Hold10 Return H11o: Clear Hold11 Return H12o: Clear Hold12 Return 'solenoids complete off: Sol0o: ' Clear solenoid ' Clear oldsolenoid Return Sol1o: Clear Hold1 Clear Velo1 Return Sol2o: Clear Hold2 Clear Velo2 Return Sol3o: Clear Hold3 Clear Velo3 Return Sol4o: Clear Hold4 Clear Velo4 Return Sol5o: Clear Hold5 Clear Velo5 Return Sol6o: Clear Hold6 Clear Velo6 Return Sol7o: Clear Hold7 Clear Velo7 Return Sol8o: Clear Hold8 Clear Velo8 Return Sol9o: Clear Hold9 Clear Velo9 Return Sol10o: Clear Hold10 Clear Velo10 Return Sol11o: Clear Hold11 Clear Velo11 Return Sol12o: Clear Hold12 Clear Velo12 Return ' solenoid velo & hold ON Sol0: ' niks Return Sol1: Set Velo1 Set Hold1 Return Sol2: Set Velo2 Set Hold2 Return Sol3: Set Velo3 Set Hold3 Return Sol4: Set Velo4 Set Hold4 Return Sol5: Set Velo5 Set Hold5 Return Sol6: Set Velo6 Set Hold6 Return Sol7: Set Velo7 Set Hold7 Return Sol8: Set Velo8 Set Hold8 Return Sol9: Set Velo9 Set Hold9 Return Sol10: Set Velo10 Set Hold10 Return Sol11: Set Velo11 Set Hold11 Return Sol12: Set Velo12 Set Hold12 Return ' solenoid HOLD's: H0: 'If OldSolenoid > 0 Then Clear OldSolenoid ' open string 'Clear oldsolenoid Return H1: Set Hold1 Return H2: Set Hold2 Return H3: Set Hold3 Return H4: Set Hold4 Return H5: Set Hold5 Return H6: Set Hold6 Return H7: Set Hold7 Return H8: Set Hold8 Return H9: Set Hold9 Return H10: Set Hold10 Return H11: Set Hold11 Return H12: Set Hold12 Return ' Velo-pulse ON: V0: ' niks Return V1: Set Velo1 Return V2: Set Velo2 Return V3: Set Velo3 Return V4: Set Velo4 Return V5: Set Velo5 Return V6: Set Velo6 Return V7: Set Velo7 Return V8: Set Velo8 Return V9: Set Velo9 Return V10: Set Velo10 Return V11: Set Velo11 Return V12: Set Velo12 Return ' clear velo pulses: V0o: ' niks Return V1o: Clear Velo1 Return V2o: Clear Velo2 Return V3o: Clear Velo3 Return V4o: Clear Velo4 Return V5o: Clear Velo5 Return V6o: Clear Velo6 Return V7o: Clear Velo7 Return V8o: Clear Velo8 Return V9o: Clear Velo9 Return V10o: Clear Velo10 Return V11o: Clear Velo11 Return V12o: Clear Velo12 Return 'KeyPres: ' ' not implemented on this board for ' notePres = 255 'Return 'ProgChange: ' prog = 255 'this is not realy required 'Return 'Pitchbend: ' 'only implemented on dsPIC based robots, irrelevant here ' set pblsb '= 255 'Return Aftertouch: ' 'this is the channel aftertouch, affecting any playing note ' 'used for fingered vibrato ' '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 30 ' valve release time controller CC30 = value If CC30 = 0 Then Clear VelFlags0.0 Clear ReleaseTime Else ReleaseTime = CC30 << 9 ' shift to the high word End If Case 31 If value <> CC31 Then If value > 0 Then Clear T3CONBITS_TMR3ON ' stop timer CC31 = value ' used as vibrato switch for debugging VibratoPeriod = CC31 << 9 Tim3 = VibratoPeriod Set T3CONBITS_TMR3ON ' start timer Else Clear T3CONBITS_TMR3ON Clear CC31 Clear VibratoPeriod Clear VelFlags0.1 EndIf EndIf Case 32 If value <> CC32 Then CC32 = value PulseTime = CC32 << 9 ' velocity pulse. To be checked. 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 GoSub PowerDown End Select Set Ctrl 'mandatory reset Return PowerDown: 'should switch off all solenoids activated , writes zero to all ports on the board. Clear VelFlags0 'stop the all running timers Clear CntHw ' reset timer Clear Velo1 Clear Velo2 Clear Velo3 Clear Velo4 Clear Velo5 Clear Velo6 Clear Velo7 Clear Velo8 Clear Velo9 Clear Velo10 Clear Velo11 Clear Velo12 Clear Velo13 Clear Velo14 Clear Hold1 Clear Hold2 Clear Hold3 Clear Hold4 Clear Hold5 Clear Hold6 Clear Hold7 Clear Hold8 Clear Hold9 Clear Hold10 Clear Hold11 Clear Hold12 Clear Hold13 Clear Hold14 Clear solenoid Clear oldsolenoid Return Release_Fingers: ' only bits really connected to finger solenoids Clear Velo1 Clear Velo2 Clear Velo3 Clear Velo4 Clear Velo5 Clear Velo6 Clear Velo7 Clear Velo8 Clear Velo9 Clear Velo10 Clear Velo11 Clear Velo12 Clear Hold1 Clear Hold2 Clear Hold3 Clear Hold4 Clear Hold5 Clear Hold6 Clear Hold7 Clear Hold8 Clear Hold9 Clear Hold10 Clear Hold11 Clear Hold12 Clear solenoid Clear oldsolenoid Return Solenoid_Lookup: ' should contain the port-settings for each solenoid ? 'Idx[0] ' ... or the solenoid to be used for each note> ' index = midinoot - lowtes NoteSolenoid[0] = 0 ' note 39 - lowtes = 0 NoteSolenoid[1] = 1 NoteSolenoid[2] = 2 NoteSolenoid[3] = 3 NoteSolenoid[4] = 4 NoteSolenoid[5] = 5 NoteSolenoid[6] = 6 NoteSolenoid[7] = 7 NoteSolenoid[8] = 8 NoteSolenoid[9] = 9 NoteSolenoid[10] = 10 NoteSolenoid[11] = 11 NoteSolenoid[12] = 12 ' note 51 NoteSolenoid[13] = 1 NoteSolenoid[14] = 2 NoteSolenoid[15] = 3 NoteSolenoid[16] = 4 NoteSolenoid[17] = 5 NoteSolenoid[18] = 6 NoteSolenoid[19] = 7 NoteSolenoid[20] = 8 NoteSolenoid[21] = 9 NoteSolenoid[22] = 10 NoteSolenoid[23] = 11 NoteSolenoid[24] = 12 ' note 63 NoteSolenoid[25] = 1 NoteSolenoid[26] = 2 NoteSolenoid[27] = 3 NoteSolenoid[28] = 4 NoteSolenoid[29] = 5 NoteSolenoid[30] = 6 NoteSolenoid[31] = 7 NoteSolenoid[32] = 8 NoteSolenoid[33] = 9 NoteSolenoid[34] = 10 NoteSolenoid[35] = 11 NoteSolenoid[36] = 12 ' note 75 NoteSolenoid[37] = 1 NoteSolenoid[38] = 2 NoteSolenoid[39] = 3 NoteSolenoid[40] = 4 NoteSolenoid[41] = 5 NoteSolenoid[42] = 6 NoteSolenoid[43] = 7 NoteSolenoid[44] = 8 NoteSolenoid[45] = 9 NoteSolenoid[46] = 10 NoteSolenoid[47] = 11 NoteSolenoid[48] = 12 ' note 87 Return '[EOF]