'**************************************************************** '* Name : Horny_Hub.BAS * '* Author : Godfried-Willem RAES * '* Notice : Copyleft (c) 2013 Logosoft Public Domain * '* Date : 07-05-2013 * '* Version : 1.3 * '* Notes : Based On Klar-hub code model * '**************************************************************** '07.05.2013: PIC: 18F2525 On MidiHub board, bidirectional solenoid, valve solenoids, sensor, lites ' Analog tilt sensor design with Penny + Giles device. ' For -60 degree to + 60 degree we should read values between 102 and 922 from the ADC ' For -45 degree to + 45 degree we should read values between 205 and 819 from the ADC ' reduced to 7 bits, with 64 as center value we get 25 and 102 as extremes for 45 degrees '07.05.2013: Start code preparation for Horny. ' We have to implement a fingering table for both the F-horn and the Bb horn. ' First sketch. With release timer for the valves. '08.05.2013: Code for bidirectional solenoid added. ' Valve lookup tables implemented and filled in after consulting with Hans Denayer '21.05.2013: Hub board mounted. (board formerly used for '18.06.2013: New hub board (Version 4) soldered. ' Further refinement on the movement solenoid coding required. Done. ' No sensor used sofar. ' Version 1.0 upload in PIC. Ready for testing. '01.07.2013: First tests on the more or less finished instrument. ' PWM freq must be increased as we get audible artifacts... '02.07.2013: Trouble: valves 1 and 2 seem to not respond after a while. ' Bug found: lookup tables were shifted 1 bit!!! ' Valves must be in bits 3,4,5, we had them faulty in bits 2,3,4 ' bit masking for portC added in coding. ' Powering duration of solenoids reduced to ca. 7 seconds. ' This version uploaded in PIC. Version 1.1 '03.07.2013: Controller 100 added for fingering control. ' Bug: 1t valve (valve) switches together with lite mapped on note 122 ' Solved: was wiring error. ' Bug: prg. only runs well with the programmer connected... ' That bug solved, but problem on Horny was not there. '04.07.2013: Got fingers to work right by just using clear and set instructions in the code. ' Now it works, but there is still interference with the lights. Version 1.3 now. ' btg assembly instructions inserted whereever possible. '05.07.2013: Code cleanup. Now version 1.5 Include "18F2525.inc" 'version for the Horny board. (40MHz) 'Include "18F2520.inc" 'also possible. (40MHz) 'Include "18F25K20.inc" 'for test & debug on an Amicus board. (64MHz) ' Mapping defines for midi-events on pin outputs and inputs: ' valves: $define Valve1 PORTC.3 ' X15-2 - Valve 1. - 1/2 tone valve (central on the horn) $define Valve2 PORTC.4 ' X11-3 - Valve 2 - 1 tone valve (close to mouthpiece on the horn) $define Valve3 PORTC.5 ' X11-2 - Valve 3 - 1 1/2 tone valve $define Lite48V PORTC.0 ' X15-3 $define Lite1 PORTB.0 ' X12-2 Yellow LED spot on back $define Lite2 PORTB.1 ' X12-3 Yellow LED spot on front $define BlueLed PORTA.3 'position reached indicator. $define GreenLed PORTA.4 'for code monitoring and debug - movement upwards $define YellowLed PORTA.5 'for code monitoring and debug - movement downward $define Sensor PORTA.0 'input port - Penny& Giles tilt sensor - not mounted yet on Horny 'red LED for debug: $define Debug_Led PORTB.5 ' for testing - red led - watchdog ' configure the input and output pins: Clear SSPCON1.5 'RC3 must be available for I/O TRISA = %01000111 '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: 'initialisations for the midi input parser: Symbol Midichannel = 14 ' Horny_Channel Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel Symbol Keypres_Status = 160 + Midichannel ' 2 bytes follow 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 'application specific constants Symbol NrTasks = 6 ' maximum 16 'Symbol PWMFreq2 = PWMminF * 2 ' PWMminF is processor dependent. 'Symbol PWMFreq3 = PWMminF * 3 ' declared in the processor include Symbol PWMFreq4 = PWMminF * 4 Symbol F_lowtes = 35 Symbol Bb_lowtes = 40 Symbol F_Hightes = 98 '94 Symbol Bb_Hightes = 103 '99 ' 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 All_Digital = True ' is the case here, as long as we do not use a sensor!!! ' Declare Hserial_Clear = On ' should clear on errors. Bytes get lost of course... ' Create variables Dim Cnt As Dword System Dim CntHw As Cnt.Word1 'used in the timer0 interrupt, to create a 32 bit timer Dim CntLw As TMR0L.Word 'this is the trick to read both TMR0L and TMR0H 'it makes Cntlw the low word of cnt 'We still have to copy the contents of Lw to Cnt Dim Tim3 As TMR3L.Word ' 16 bit counter for sampler ' Dim Sr as TMR0L.7 '512 S/s ' 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 veltim3 As Dword System ' duration for the valve release timeout Dim newtim As Dword System Dim VelFlags As Word System ' bits 0 - 15 used as flags for active timers Dim VelFlags0 As VelFlags.Byte0 ' alias for bits 0-7 ' Dim VelFlags1 As VelFlags.Byte1 ' bits 8-15 - not used in this code. Dim CC22 As Byte System ' solenoid - midi value 64 = equilibrium Dim CC30 As Byte System ' valve release time Dim CC33 As Byte System ' F-horn or Bb Horn controller 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 Lites As Byte System ' bits used as flags Dim sBit As Byte System ' sampling rate bit toggle Dim pw1 As Byte System ' for the bidirectional solenoid. Dim pw2 As Byte System Dim Valves As Byte System Dim Playingnote As Byte System Dim Fingers[64] As Byte ' fingering Lookup table Dim Releasetime As Word System ' calculated from CC30 Dim Hightes As Byte System ' set with CC33 Dim Lowtes As Byte System Dim Idx As Byte System Dim HighPed As Byte System Dim LowPed As Byte System '----------------------------------------------------------------------------------------- ' Load the USART Interrupt handler And buffer read subroutines into memory Include "Horny_Hub_Irq.inc" ' our own version for UART And Timer0/3 Interrupt 'framework for a multitasker: Dim Task_rsi[NrTasks] As Word 'task reschedule interval (period), if 0 the task is not active 'max. value limited to 65535. For longer periods, it will have to 'become dword!!! Dim Velmsb[NrTasks] As Word 'the application for velo-timers, is in fact just a one-shot task Dim VelLsb[NrTasks] As Word 'make sure we initialize those pins on start up: 'fault?: there should be no executable statements outside the main program. Low Valve3 Low Valve2 Low Valve1 Low Lite1 Low Lite2 Low Lite48V Low Debug_Led HPWM 2, 0, PWMFreq4 'PWMminF ' movement bidirectional solenoid HPWM 1, 0, PWMFreq4 'PWMminF ' connected to RC2 Low GreenLED Low YellowLed Low BlueLED Clear CC66 CC22 = 64 ' assume mid position Clear CC33 ' assume F-horn on cold boot. Lowtes = F_lowtes LowPed = F_lowtes - 12 HighPed = F_lowtes - 6 Hightes = F_Hightes Idx = 6 CC30 = 30 ' release time controller , 7 bits Releasetime = CC30 << 9 ' so now it fits into a word variable Clear Valves GoSub F_Horn_Lookup '----------------------------------------------------------------------------------------- ' Main program starts here MAIN: High Debug_Led DelayMS 50 ' wait for stability Low Debug_Led Clear VelFlags0 Clear Lites 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 ' Opentimer0 (Timer_INT_On & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256) in macro file. 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 ' Open the ADC: ' 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) ' could be replaced with: ADCON2 = %10000010 ADCON1 = %00001110 ADCON0 = %00000001 'SensorVal = ReadADC 0 ' initialize with the value on startup - 10 bit resolution ' open and start timer3 for sampling: Clear T3CON Clear PIR2BITS_TMR3IF ' clear IRQ flag Set PIE2BITS_TMR3IE ' irq on 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, lowest freq.=19Hz ' 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 (?) GoTo Check_Timers 'throw away... Else Clear statusbyte 'reset the status byte GoTo Check_Timers 'throw away End If 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 '= 255 'reset value. Cannot be 0 !!! Set release '= 255 '0 is a valid midi note! Case NoteOn_Status statusbyte = Bytein Set noteAan '= 255 Set velo '= 255 Case Keypres_Status ' used for lights statusbyte = Bytein Set notePres '= 255 Set pres '= 255 Case Control_Status ' movement control, choice of valve lookup table statusbyte = Bytein Set Ctrl '= 255 Set value '= 255 ' Case ProgChange_Status ' statusbyte = Bytein ' prog = 255 ' Case Aftertouch_Status ' statusbyte = Bytein ' aft = 255 ' Case Pitchbend_Status ' 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 Lowtes To Hightes , LowPed To HighPed 'this does not work with the compiler, so we split: Case Lowtes To Hightes ' start valverelease timer, if a valve is depressed... 'If Fingers[Idx] > 0 Then ' idx is set on reception of a note-on If Valves > 0 Then Set VelFlags0.3 'set the timer Cnt.Word0 = CntLw veltim3 = Cnt + Releasetime 'add the timeout duration EndIf Clear Playingnote Case LowPed To HighPed 'If Fingers[Idx] > 0 Then If Valves > 0 Then Set VelFlags0.3 'set the timer Cnt.Word0 = CntLw veltim3 = Cnt + Releasetime 'add the timeout duration EndIf Clear Playingnote Case 120 Clear Lites.0 Clear VelFlags0.0 Clear Lite1 Case 121 Clear Lites.1 Clear VelFlags0.1 Clear Lite2 Case 122 Clear Lites.2 Clear VelFlags0.2 Clear Lite48V 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 ', LowPed to Highped ' if any valve is depressed, start valverelease timer 'If Fingers[Idx] > 0 Then If Valves > 0 Then Set VelFlags0.3 'set the timer Cnt.Word0 = CntLw veltim3 = Cnt + Releasetime 'add the timeout duration EndIf Clear Playingnote Case LowPed To HighPed 'If Fingers[Idx] > 0 Then If Valves > 0 Then Set VelFlags0.3 'set the timer Cnt.Word0 = CntLw veltim3 = Cnt + Releasetime 'add the timeout duration EndIf Clear Playingnote Case 120 Clear Lites.0 '= 0 Clear VelFlags0.0 Clear Lite1 Case 121 Clear Lites.1 '= 0 Clear VelFlags0.1 Clear Lite2 Case 122 Clear Lites.2 '= 0 Clear VelFlags0.2 Clear Lite48V End Select Set noteAan '= 255 'reset !!! GoTo Check_Timers 'jump out EndIf Select noteAan Case LowPed To HighPed ' pedal notes! Idx = noteAan + 12 - Lowtes ' Idx stays set, as we need it for noteoff ' with masking: ' i = PORTC & %11000111 ' i = i | Fingers[Idx] ' PORTC = i ' without masking: 'PORTC = Fingers[Idx] ' we could also do: Valves = Fingers[Idx] ' most efficient coding: If Valves.3 <> Valve1 Then btg Valve1 If Valves.4 <> Valve2 Then btg Valve2 If Valves.5 <> Valve3 Then btg Valve3 Playingnote = noteAan Clear VelFlags0.3 GoTo Check_Timers Case Lowtes To Hightes Idx = noteAan - Lowtes Valves = Fingers[Idx] ' more efficient coding: If Valves.3 <> Valve1 Then btg Valve1 If Valves.4 <> Valve2 Then btg Valve2 If Valves.5 <> Valve3 Then btg Valve3 Playingnote = noteAan Clear VelFlags0.3 GoTo Check_Timers Case 120 If velo < 127 Then 'omleiding van de kode naar keypres: notePres = 120 pres = velo GoSub KeyPres Else Set Lites.0 Clear VelFlags0.0 Set Lite1 EndIf Case 121 If velo < 127 Then 'omleiding van de kode naar keypres: notePres = 121 pres = velo GoSub KeyPres Else Set Lites.1 Clear VelFlags0.1 Set Lite2 EndIf Case 122 If velo < 127 Then 'omleiding van de kode naar keypres: notePres = 122 pres = velo GoSub KeyPres Else Set Lites.2 Clear VelFlags0.2 Set Lite48V EndIf End Select Set noteAan '= 255 'reset EndIf GoTo Check_Timers Case Keypres_Status 'used for lite flashing speed modulation 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 EndIf GoTo Check_Timers ' Case ProgChange_Status ' If prog = 255 Then 'single byte message ' prog = Bytein 'weak coding... ' GoSub ProgChange ' EndIf 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 Then 'if any bit is set here, there is a timer running If VelFlags0.0 = 1 Then veltim.Word1 = Velmsb[0] veltim.Word0 = VelLsb[0] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then GoSub Task0 'note 120 Lite1 EndIf If VelFlags0.1 = 1 Then veltim.Word1 = Velmsb[1] veltim.Word0 = VelLsb[1] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then GoSub Task1 'note 121 Lite2 EndIf If VelFlags0.2 = 1 Then veltim.Word1 = Velmsb[2] veltim.Word0 = VelLsb[2] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then GoSub Task2 'note 122 Lite48V EndIf If VelFlags0.3 = 1 Then ' valve release timer Cnt.Word0 = CntLw 'read counter If Cnt >= veltim3 Then Clear Valve1 Clear Valve2 Clear Valve3 Clear Valves Clear VelFlags0.3 ' one-shot End If EndIf 'Else ' If CntHw > 0xFF Then Clear CntHw EndIf ' solenoid drive for movement: Cnt.Word0 = CntLw ' read counter If Cnt.11 <> sBit Then ' Cnt.14 sets the refresh rate at 4 S/s ' Cnt.13 at 8 S/s ' Cnt.12 at 16 S/s was Cnt.12 in code version 2.0 On ' Cnt.11 at 32 S/s was Cnt.11 On ' Cnt.10 at 64 S/s ' with Cnt.14 it took about 120 seconds for the solenoid to build down power ' with Cnt.11 we should have about 7.5" time sBit = Cnt.11 If pw1 > 0 Then Set YellowLed Dec pw1 'solenoid action , upwards movement HPWM 1,pw1, PWMFreq4 ';PWMminF Else Clear YellowLed EndIf If pw2 > 0 Then Set BlueLed Dec pw2 ' downwards movement HPWM 2,pw2, PWMFreq4 'PWMminF Else Clear BlueLED EndIf If pw1 + pw2 > 0 Then Clear GreenLed Else Set GreenLED EndIf EndIf GoTo LOOP ' end of the main loop KeyPres: 'the note to which the pressure should be applied is passed in NotePres, the value in Pres 'here we use it for flashing lights on Horny. Select notePres Case 120 If Lites.0 = 1 Then Set VelFlags0.0 Cnt.Word0 = CntLw 'read timer Task_rsi[0] = (~pres & 127) << 9 veltim = Cnt + Task_rsi[0] 'add the period duration Velmsb[0] = veltim.Word1 VelLsb[0] = veltim.Word0 Else Clear VelFlags0.0 Clear Lite1 EndIf Case 121 If Lites.1 = 1 Then Set VelFlags0.1 Cnt.Word0 = CntLw 'read timer Task_rsi[1] = (~pres & 127) << 9 veltim = Cnt + Task_rsi[1] 'add the period duration Velmsb[1] = veltim.Word1 VelLsb[1] = veltim.Word0 Else Clear VelFlags0.1 Clear Lite2 EndIf Case 122 If Lites.2 = 1 Then Set VelFlags0.2 Cnt.Word0 = CntLw 'read timer Task_rsi[2] = (~pres & 127) << 9 veltim = Cnt + Task_rsi[2] 'add the period duration Velmsb[2] = veltim.Word1 VelLsb[2] = veltim.Word0 Else Clear VelFlags0.2 Clear Lite48V EndIf End Select Set notePres '= 255 Return ProgChange: Set prog '= 255 'this is not realy required Return Pitchbend: 'only implemented on dsPIC based robots Set pblsb '= 255 Return Aftertouch: 'this is the channel aftertouch, affecting all notes Set aft '= 255 'not mandatory Return Controller: Select Ctrl Case 22 ' this controller is the positioning command Select value Case 64 Clear pw1 Clear pw2 Set GreenLED Clear YellowLED Clear BlueLED Case < 64 ' naar onder If value = 0 Then value =1 pw2 = (64-value) <<2 Clear pw1 Set YellowLED Clear BlueLED Clear GreenLED ' now we should start a timer to let the pw value go down to 0 Case > 64 ' naar boven pw1 = (value - 64) << 2 Clear pw2 Set BlueLED Clear GreenLED Clear YellowLED End Select CC22 = value HPWM 1, pw1, PWMFreq4 'PWMminF HPWM 2, pw2, PWMFreq4 'PWMminF Case 30 ' valve release time controller CC30 = value If CC30 = 0 Then Clear VelFlags0.3 ' should we allow this mode of operation? Releasetime = 100 ' set to a very small value Else Releasetime = CC30 << 9 ' shift to the high word End If Case 33 i = value.6 ' check the highest midi bit only If i <> CC33 Then ' if value < 64 then the F-Horn is active, else the Bb Horn Clear Valve1 Clear Valve2 Clear Valve3 Clear VelFlags0.3 Clear Idx If i = 0 Then GoSub F_Horn_Lookup Lowtes = F_lowtes Hightes = F_Hightes LowPed = F_lowtes - 12 HighPed = F_lowtes - 6 Else GoSub Bb_Horn_Lookup Lowtes = Bb_lowtes Hightes = Bb_Hightes LowPed = Bb_lowtes - 12 HighPed = Bb_lowtes - 6 End If CC33 = i End If Case 66 'on/off for the robot If value = 0 Then Clear PowerOn 'CC66.0 GoSub PowerDown Else Set PowerOn 'CC66.0 EndIf Case 100 ' fingering controller ' bit 0 = valve 1 ' bit 1 = valve 2 ' bit 3 = valve 3 Clear VelFlags0.3 'stop the release timer If value.0 <> Valves.3 Then btg Valve1 If value.1 <> Valves.4 Then btg Valve2 If value.2 <> Valves.5 Then btg Valve3 Valves = value << 3 Case 123 GoSub AllNotesOff End Select Set Ctrl '= 255 'mandatory reset Return AllNotesOff: 'Clear VelFlags0 'would stop all running timers, also the motor clock... Clear VelFlags0.0 Clear VelFlags0.1 Clear VelFlags0.2 Clear VelFlags0.3 Clear Valve3 Clear Valve2 Clear Valve1 Clear Valves HPWM 1, 0, PWMFreq4 'minF ' connected to RC2 HPWM 2, 0, PWMFreq4 'minF ' connected to RC1 Clear pw1 Clear pw2 Clear Lites Return PowerDown: 'should return the motor to equilibrium position and than switch off Clear VelFlags0 'stop all running timers Clear Valve3 '= 0 Clear Valve2 '= 0 Clear Valve1 Clear Lite1 Clear Lite2 Clear Lite48V '= 0 'Low Debug_Led Clear Lites Clear pw1 Clear pw2 Clear Valves HPWM 1, 0, PWMFreq4 'minF ' connected to RC2 HPWM 2, 0, PWMFreq4 'minF ' connected to RC1 Return Task0: If Lites.0 = 0 Then Clear VelFlags0.0 'stop task, as lite is switched off Clear Lite1 '= 0 Else 'reload task0 - light 'Set VelFlags0.0 'can just stay set Cnt.Word0 = CntLw veltim = Cnt + Task_rsi[0] 'add the period duration Velmsb[0] = veltim.Word1 VelLsb[0] = veltim.Word0 btg Lite1 'Toggle EndIf Return Task1: If Lites.1 = 0 Then Clear VelFlags0.1 'stop task, as lite is switched off Clear Lite2 Else Cnt.Word0 = CntLw veltim = Cnt + Task_rsi[1] 'add the period duration in Task_rsi[1] Velmsb[1] = veltim.Word1 VelLsb[1] = veltim.Word0 btg Lite2 EndIf Return Task2: If Lites.2 = 0 Then Clear VelFlags0.2 'stop task, as lite is switched off Clear Lite48V Else Cnt.Word0 = CntLw veltim = Cnt + Task_rsi[2] 'add the period duration Velmsb[2] = veltim.Word1 VelLsb[2] = veltim.Word0 btg Lite48V EndIf Return F_Horn_Lookup: ' fingering table for all playable notes for the F-Horn ' the lowest note for the F-horn is 35 and we run up to note 98 ' so the lookup runs from 0 - 63 ' notes 23-29 are pedals and can be played with the same fingering as 35-41 Fingers[0] = %00111000 '35 ' portC only - we use the bits 3,4 and 5 only Fingers[1] = %00110000 '36 Fingers[2] = %00101000 '37 Fingers[3] = %00100000 '38 Fingers[4] = %00010000 '39 Fingers[5] = %00001000 '40 Fingers[6] = %00000000 '41 Fingers[7] = %00111000 '42 Fingers[8] = %00110000 '43 Fingers[9] = %00101000 '44 Fingers[10] = %00100000 ' 45 Fingers[11] = %00010000 ' 46 Fingers[12] = %00001000 ' 47 Fingers[13] = %00000000 ' 48 Fingers[14] = %00101000 Fingers[15] = %00100000 '50 Fingers[16] = %00010000 Fingers[17] = %00001000 Fingers[18] = %00000000 '53 Fingers[19] = %00011000 Fingers[20] = %00100000 '55 Fingers[21] = %00001000 Fingers[22] = %00000000 '57 Fingers[23] = %00010000 Fingers[24] = %00001000 Fingers[25] = %00000000 ' midi 60 Fingers[26] = %00010000 Fingers[27] = %00100000 '62 Fingers[28] = %00000000 '63 Fingers[29] = %00001000 Fingers[30] = %00000000 '65 Fingers[31] = %00011000 Fingers[32] = %00010000 '67 Fingers[33] = %00001000 Fingers[34] = %00000000 '69 Fingers[35] = %00010000 Fingers[36] = %00001000 Fingers[37] = %00000000 ' 72 Fingers[38] = %00110000 Fingers[39] = %00100000 Fingers[40] = %00011000 ' 75 Fingers[41] = %00001000 Fingers[42] = %00000000 ' 77 Fingers[43] = %00011000 Fingers[44] = %00100000 Fingers[45] = %00001000 ' 80 Fingers[46] = %00000000 ' 81 Fingers[47] = %00010000 Fingers[48] = %00001000 Fingers[49] = %00000000 ' 84 Fingers[50] = %00110000 Fingers[51] = %00100000 Fingers[52] = %00010000 Fingers[53] = %00001000 Fingers[54] = %00000000 ' 89 Fingers[55] = %00011000 Fingers[56] = %00010000 Fingers[57] = %00001000 '92 Fingers[58] = %00000000 Fingers[59] = %00010000 Fingers[60] = %00000000 Fingers[61] = %00000000 ' midi note 96 Fingers[62] = %00000000 Fingers[63] = %00000000 ' 98 Return Bb_Horn_Lookup: ' fingering table for all playable notes for the Bb-Horn ' the lowest note for the Bb-horn is 28 (pedal) to 34 ' from 40 we run up continuously to note 101 ' so the lookup runs from 0 - 63 Fingers[0] = %00111000 ' note 40 ' portC only - we use the bits 3,4 and 5 only Fingers[1] = %00110000 Fingers[2] = %00101000 Fingers[3] = %00011000 '43 Fingers[4] = %00010000 Fingers[5] = %00001000 Fingers[6] = %00000000 ' 46 Fingers[7] = %00111000 Fingers[8] = %00110000 Fingers[9] = %00101000 Fingers[10] = %00100000 ' 50 Fingers[11] = %00010000 Fingers[12] = %00001000 Fingers[13] = %00000000 '53 Fingers[14] = %00101000 Fingers[15] = %00100000 Fingers[16] = %00010000 Fingers[17] = %00001000 Fingers[18] = %00000000 '58 Fingers[19] = %00100000 Fingers[20] = %00010000 '60 Fingers[21] = %00001000 Fingers[22] = %00100000 Fingers[23] = %00010000 '63 Fingers[24] = %00001000 Fingers[25] = %00000000 '65 Fingers[26] = %00101000 Fingers[27] = %00100000 Fingers[28] = %00010000 Fingers[29] = %00001000 Fingers[30] = %00000000 '70 Fingers[31] = %00001000 Fingers[32] = %00000000 '72 Fingers[33] = %00001000 Fingers[34] = %00000000 '74 Fingers[35] = %00010000 Fingers[36] = %00001000 Fingers[37] = %00000000 '77 Fingers[38] = %00000000 Fingers[39] = %00000000 Fingers[40] = %00001000 '80 Fingers[41] = %00001000 Fingers[42] = %00000000 '82 Fingers[43] = %00001000 Fingers[44] = %00000000 '84 Fingers[45] = %00001000 Fingers[46] = %00000000 '86 Fingers[47] = %00010000 Fingers[48] = %00001000 Fingers[49] = %00000000 '89 Fingers[50] = %00000000 Fingers[51] = %00000000 '91 Fingers[52] = %00001000 Fingers[53] = %00001000 Fingers[54] = %00000000 '94 Fingers[55] = %00000000 Fingers[56] = %00000000 '96 Fingers[57] = %00000000 Fingers[58] = %00000000 Fingers[59] = %00000000 Fingers[60] = %00000000 '100 Fingers[61] = %00000000 Fingers[62] = %00000000 Fingers[63] = %00000000 '103 Return '[EOF]