'**************************************************************** '* Name : PSCH.BAS * '* Author : Godfried-Willem RAES * '* Notice : Copyleft (c) 2015 Logosoft Public Domain * '* Date : 19.11.2015 * '* Version : 2.1 * '* Notes : using priority timers and loopcounter * '**************************************************************** '18.11.2015 This coding starting from the Bello code. ' preserving the original mapping in the version from 2006. ' BUG: stuck solenoid on PortA.1, out3 note 75 '19.11.2015 Bug found. We had a typo... ' Velo scaling changed for compatibility with Psch V1.0 code. ' Tests performed with existing code. Everything seems to work fine. 'Include "18F2525.inc" 'version for the Bello board. (40MHz) Include "18F2620.inc" 'also possible, more memory available 'Include "18F2520.inc" 'not possible as it has too little user ram (40MHz) 'Include "18F25K20.inc" 'for test & debug on an Amicus board. (64MHz) Declare Bootloader = 0 Declare Watchdog = 0 'Declare Label_Bank_Resets = 1 'Declare Icd_Req = 0 ' Mapping defines for midi-events on pin outputs and inputs: $define Out0 PORTA.0 'PORTA.2 ' 72 $define Out1 PORTA.3 'PORTA.1 ' 73 $define Out2 PORTB.3 'PORTA.0 ' 74 $define Out3 PORTA.1 'PORTA.3 ' 75 $define Out4 PORTA.2 'PORTA.4 ' 76 $define Out5 PORTB.7 'PORTA.5 ' 77 $define Out6 PORTA.4 'PORTB.7 ' 78 $define Out7 PORTB.6 'PORTB.6 ' 79 $define Out8 PORTB.4 'PORTB.5 ' 80 $define Out9 PORTB.2 'PORTB.4 ' 81 $define Out10 PORTA.5 'PORTB.3 ' 82 $define Out11 PORTB.5 'PORTB.2 ' 83 $define Lite1 PORTB.1 $define Lite2 PORTB.0 $define Lite3 PORTC.5 $define Lite4 PORTC.4 $define Debug_Led PORTC.0 ' for testing - blue led - watchdog Symbol CntLw = TMR0L.Word0 ' 16 bit timer 0 alias ' configure the input and output pins: Clear SSPCON1.5 'RC3 must be available for I/O TRISA = %11000000 'bits set to 0 are output, 1 = input TRISB = %00000000 ' we use all bits, thus disabling the ICD changed 19.11.2015 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 = 5 ' Psch 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 fPWM = PWMminF * 4 ' in avoidance of audible artifacts ' not used in this code Symbol note0 = 72 Symbol note1 = 73 Symbol note2 = 74 Symbol note3 = 75 Symbol note4 = 76 Symbol note5 = 77 Symbol note6 = 78 Symbol note7 = 79 Symbol note8 = 80 Symbol note9 = 81 Symbol note10 = 82 Symbol note11 = 83 Symbol note12 = 84 Symbol note13 = 85 Symbol note14 = 86 Symbol note15 = 87 ' 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 ' Declare Hserial_Clear = On ' should clear on errors. Bytes get lost of course... ' Create variables ' Dim Cnt As Dword System ' 32bit counter ' 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 as a single 16 bit value 'it makes Cntlw the low word of cnt 'We still have to copy the contents of CntLw to Cnt, as CntLw is not Cnt.word0 ! ' by doing Cnt.Byte1 = TMR0H : Cnt.Byte0 = TMR0L before using the timer value in cnt ' or Cnt.word0 = CntLw ' macro definition: '$define Gettime Cnt.Word0 = CntLw ' time = Cnt Dim Tim3 As TMR3L.Word ' used in the low interrupt '----------------------------------------------------------------------------------------- ' Load the USART Interrupt handler And buffer read subroutines into memory Include "psch_Irq.inc" ' our own version for UART And Timer0/3 Interrupt 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 VelFlags As Word System ' bits 0 - 15 used as flags for active timers Dim Notes As Word System ' bits used as flags Notes.0 to Notes.11 for the repeats Dim CC66 As Byte System ' global on/off switch Dim time As Dword System ' 32-bit, incremented in low IRQ ' or 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 overflow As tog.7 ' bit gets set when time.31 gets set 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 velo8 As Word System Dim velo9 As Word System Dim velo10 As Word System Dim velo11 As Word System Dim Rate0 As Word System Dim Rate1 As Word System ' set with keypressure 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 Rate8 As Word System Dim Rate9 As Word System Dim Rate10 As Word System Dim Rate11 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 Pres8 As Byte 'System Dim Pres9 As Byte 'System Dim Pres10 As Byte 'System Dim Pres11 As Byte 'System Dim TimVals[12] 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 ' lookup-tables: ' velocity lookup tables: ' the first lookup gets cluttered ' so we dim two arrays that we do not use first... ' so on purpose, we waste 512 bytes of variable space Dim notused[256] As Word ' dummy must be at this place! Dim Vels[128] As Word ' lookup for note repetitions: Dim Dur[128] As Word MAIN: 'make sure we initialize the used pins on start up: Low Out0 Low Out1 Low Out2 Low Out3 Low Out4 Low Out5 Low Out6 Low Out7 Low Out8 Low Out9 Low Out10 Low Out11 Low Lite1 Low Lite2 Low Lite3 Low Lite4 Low PORTC.1 ' not used Low PORTC.2 ' not used 'DelayMS 50 ' wait for stability 'Clear ' clears all RAM 'Low Debug_Led Clear Rate0 Clear Rate1 Clear Rate2 Clear Rate3 Clear Rate4 Clear Rate5 Clear Rate6 Clear Rate7 Clear Rate8 Clear Rate9 Clear Rate10 Clear Rate11 Clear Pres0 Clear Pres1 Clear Pres2 Clear Pres3 Clear Pres4 Clear Pres5 Clear Pres6 Clear Pres7 Clear Pres8 Clear Pres9 Clear Pres10 Clear Pres11 Clear CC66 GoSub Dur_Lookup ' note repetition periods GoSub Vels_Lookup ' velocity scalings Clear Notes Clear VelFlags Low PORTB Init_Usart_Interrupt ' Initiate the USART serial buffer interrupt ' this procedure is in the IRQ include file Clear_Serial_Buffer ' Clear the serial buffer and reset its pointers ' in the IRQ 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 timer1 flags Clear IntConBits_T0IF ' clear interrupt flag Set INTCONBITS_T0IE ' enable interrupt on overflow T0CON = %10000111 ' bit 7 = enable/disable ' bit 6 = 1=8 bit, 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 and start timer3 for counting: Clear T3CON Clear PIR2BITS_TMR3IF ' clear IRQ flag ' Set PIE2BITS_TMR3IE ' irq on 'Clear Tim3 ' Clear TMR3L And TMR3H registers Tim3 = 65506 ' 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 , 0= 8 bit mode : only affect the way it's written ' 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 ' reset all timers on startup: Set TimVals Set idx Set Nxt.31 Clear time ' so we start from 0 ' start the main program loop: --------------------------------------------------------- LOOP: Inc t ' byte If t.1 = tg Then Btg tg Inc time ' dword EndIf ' = time = t >> 2 not working: compiler bug! ' 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 < 254 Then Clear statusbyte GoTo Check_Timers ' we do not need to re-sort existing timers in this case 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 !!! Case NoteOn_Status statusbyte = Bytein Set noteAan Case Keypres_Status ' used for note repetition speed statusbyte = Bytein Set notePres Case Control_Status ' only 66 and 123 statusbyte = Bytein Set Ctrl '= 255 ' Case ProgChange_Status ' statusbyte = Bytein ' prog = 255 ' Case Aftertouch_Status ' statusbyte = Bytein ' aft = 255 ' Case Pitchbend_Status ' statusbyte = Bytein ' pblsb = 255 ' pbmsb = 255 EndSelect GoTo Check_Timers ' no re-sorting of timers required Else ' midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Check_Timers 'disregard - no resort required Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein GoTo Check_Timers Else 'release = Bytein 'message complete, so we can do the action... Select noteUit Case note0 Clear Out0 Clear VelFlags.0 Clear Notes.0 Set TimVals[0] ' set all bits Case note1 Clear Out1 Clear VelFlags.1 Clear Notes.1 Set TimVals[1] Case note2 Clear Out2 Clear VelFlags.2 Clear Notes.2 Set TimVals[2] Case note3 Clear Out3 Clear VelFlags.3 Clear Notes.3 Set TimVals[3] Case note4 Clear VelFlags.4 Clear Out4 Clear Notes.4 Set TimVals[4] Case note5 Clear VelFlags.5 Clear Out5 Clear Notes.5 Set TimVals[5] Case note6 Clear VelFlags.6 Clear Out6 Clear Notes.6 Set TimVals[6] Case note7 Clear VelFlags.7 Clear Out7 Clear Notes.7 Set TimVals[7] Case note8 Clear VelFlags.8 Clear Out8 Clear Notes.8 Set TimVals[8] Case note9 Clear VelFlags.9 Clear Out9 Clear Notes.9 Set TimVals[9] Case note10 Clear VelFlags.10 Clear Out10 Clear Notes.10 Set TimVals[10] Case note11 Clear VelFlags.11 Clear Out11 Clear Notes.11 Set TimVals[11] Case note12, 120 ' lite Clear Lite1 Set noteUit GoTo Check_Timers Case note13, 121 ' lite Clear Lite2 Set noteUit GoTo Check_Timers Case note14, 122 ' lite Clear Lite3 Set noteUit GoTo Check_Timers Case note15, 123 ' lite Clear Lite4 Set noteUit GoTo Check_Timers Case Else Set noteUit GoTo Check_Timers ' no re-sorting EndSelect Set noteUit '= 255 reset GoTo resort ' note-off happened, so resort! EndIf Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then Select noteAan Case note0 Clear Out0 Clear VelFlags.0 Clear Notes.0 Set TimVals[0] Case note1 Clear Out1 Clear VelFlags.1 Clear Notes.1 Set TimVals[1] Case note2 Clear Out2 Clear VelFlags.2 Clear Notes.2 Set TimVals[2] Case note3 Clear Out3 Clear VelFlags.3 Clear Notes.3 Set TimVals[3] Case note4 Clear VelFlags.4 Clear Out4 Clear Notes.4 Set TimVals[4] Case note5 Clear VelFlags.5 Clear Out5 Clear Notes.5 Set TimVals[5] Case note6 Clear VelFlags.6 Clear Out6 Clear Notes.6 Set TimVals[6] Case note7 Clear VelFlags.7 Clear Out7 Clear Notes.7 Set TimVals[7] Case note8 Clear VelFlags.8 Clear Out8 Clear Notes.8 Set TimVals[8] Case note9 Clear VelFlags.9 Clear Out9 Clear Notes.9 Set TimVals[9] Case note10 Clear VelFlags.10 Clear Out10 Clear Notes.10 Set TimVals[10] Case note11 Clear VelFlags.11 Clear Out11 Clear Notes.11 Set TimVals[11] Case note12, 120 ' lite Clear Lite1 Set noteAan GoTo Check_Timers Case note13 , 121 ' lite Clear Lite2 Set noteAan GoTo Check_Timers Case note14, 122 ' lite Clear Lite3 Set noteAan GoTo Check_Timers Case note15, 123 ' lite Clear Lite4 Set noteAan GoTo Check_Timers Case Else Set noteAan 'not a note for this board GoTo Check_Timers 'no resort required EndSelect ' here we need a resort! Set noteAan GoTo resort EndIf ' If CC66 > 0 Then ' so power ON must have been set! Select noteAan & CC66 Case note0 'hier moeten we een pulse timer starten, duur evenredig met velo 'na afloop van de puls moet een wachttimer ingeschakeld worden 'voor zover een repeat speed is ingesteld met keypressure ' na de wachttijd moet een nieuwe puls gegeven worden met de bestaande velo ' note off schakelt de repeats uiteraard uit. Set Out0 ' stroom aan velo0 = Vels[velo] ' word var's Set VelFlags.0 TimVals[0] = time + velo0 If Pres0 > 0 Then Set Notes.0 ' hier moeten we Rate0 herberekenen in funktie van velo0 ' in elk geval mag Rate0 nooit kleiner zijn dan velo0. If Dur[Pres0] <= velo0 << 1 Then Rate0 = velo0 Else Rate0 = Dur[Pres0] - velo0 ' 3 word vars EndIf EndIf Case note1 Set Out1 velo1 = Vels[velo] Set VelFlags.1 TimVals[1] = time + velo1 If Pres1 > 0 Then Set Notes.1 If Dur[Pres1] <= velo1 << 1 Then Rate1 = velo1 Else Rate1 = Dur[Pres1] - velo1 EndIf EndIf Case note2 Set Out2 velo2 = Vels[velo] Set VelFlags.2 TimVals[2] = time + velo2 If Pres2 > 0 Then Set Notes.2 If Dur[Pres2] <= velo2 << 1 Then Rate2 = velo2 Else Rate2 = Dur[Pres2] - velo2 EndIf EndIf Case note3 Set Out3 velo3 = Vels[velo] Set VelFlags.3 TimVals[3] = time + velo3 If Pres3 > 0 Then Set Notes.3 If Dur[Pres3] <= velo3 << 1 Then Rate3 = velo3 Else Rate3 = Dur[Pres3] - velo3 EndIf EndIf Case note4 velo4 = Vels[velo] Set Out4 Set VelFlags.4 TimVals[4] = time + velo4 If Pres4 > 0 Then Set Notes.4 If Dur[Pres4] <= velo4 << 1 Then Rate4 = velo4 Else Rate4 = Dur[Pres4] - velo4 EndIf EndIf Case note5 velo5 = Vels[velo] Set Out5 Set VelFlags.5 TimVals[5] = time + velo5 If Pres5 > 0 Then Set Notes.5 If Dur[Pres5] <= velo5 << 1 Then Rate5 = velo5 Else Rate5 = Dur[Pres5] - velo5 EndIf EndIf Case note6 velo6 = Vels[velo] Set Out6 Set VelFlags.6 TimVals[6] = time + velo6 If Pres6 > 0 Then Set Notes.6 If Dur[Pres6] <= velo6 << 1 Then Rate6 = velo6 Else Rate6 = Dur[Pres6] - velo6 EndIf EndIf Case note7 velo7 = Vels[velo] Set Out7 Set VelFlags.7 TimVals[7] = time + velo7 If Pres7 > 0 Then Set Notes.7 If Dur[Pres7] <= velo7 << 1 Then Rate7 = velo7 Else Rate7 = Dur[Pres7] - velo7 EndIf EndIf Case note8 velo8 = Vels[velo] Set Out8 Set VelFlags.8 TimVals[8] = time + velo8 If Pres8 > 0 Then Set Notes.8 If Dur[Pres8] <= velo8 << 1 Then Rate8 = velo8 Else Rate8 = Dur[Pres8] - velo8 EndIf EndIf Case note9 velo9 = Vels[velo] Set Out9 Set VelFlags.9 TimVals[9] = time + velo9 If Pres9 > 0 Then Set Notes.9 If Dur[Pres9] <= velo9 << 1 Then Rate9 = velo9 Else Rate9 = Dur[Pres9] - velo9 EndIf EndIf Case note10 velo10 = Vels[velo] Set Out10 Set VelFlags.10 TimVals[10] = time + velo10 If Pres10 > 0 Then Set Notes.10 If Dur[Pres10] <= velo10 << 1 Then Rate10 = velo10 Else Rate10 = Dur[Pres10] - velo10 EndIf EndIf Case note11 velo11 = Vels[velo] Set Out11 Set VelFlags.11 TimVals[11] = time + velo11 If Pres11 > 0 Then Set Notes.11 If Dur[Pres11] <= velo11 << 1 Then Rate11 = velo11 Else Rate11 = Dur[Pres11] - velo11 EndIf EndIf Case note12, 120 ' lite Set Lite1 Set noteAan GoTo Check_Timers Case note13, 121 ' lite Set Lite2 Set noteAan GoTo Check_Timers Case note14, 122 ' lite Set Lite3 Set noteAan GoTo Check_Timers Case note15, 123 ' lite Set Lite4 Set noteAan GoTo Check_Timers Case Else Set noteAan GoTo Check_Timers ' no re-sorting required EndSelect ' Else ' power is OFF ' Set noteAan ' GoTo Check_Timers ' no re-sort ' EndIf ' CC66 endif Set noteAan GoTo resort EndIf Case Keypres_Status 'used for note repetition speed modulation If notePres = 255 Then notePres = Bytein GoTo Check_Timers Else Select notePres Case note0 Pres0 = Bytein 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 note1 Pres1 = Bytein If Pres1 > 0 Then Rate1 = Dur[Pres1] Else Clear Rate1 Clear Notes.1 EndIf Case note2 Pres2 = Bytein If Pres2 > 0 Then Rate2 = Dur[Pres2] Else Clear Rate2 Clear Notes.2 EndIf Case note3 Pres3 = Bytein If Pres3 > 0 Then Rate3 = Dur[Pres3] Else Clear Rate3 Clear Notes.3 EndIf Case note4 Pres4 = Bytein If Pres4 > 0 Then Rate4 = Dur[Pres4] Else Clear Rate4 Clear Notes.4 EndIf Case note5 Pres5 = Bytein If Pres5 > 0 Then Rate5 = Dur[Pres5] Else Clear Rate5 Clear Notes.5 EndIf Case note6 Pres6 = Bytein If Pres6 > 0 Then Rate6 = Dur[Pres6] Else Clear Rate6 Clear Notes.6 EndIf Case note7 Pres7 = Bytein If Pres7 > 0 Then Rate7 = Dur[Pres7] Else Clear Rate7 Clear Notes.7 EndIf Case note8 Pres8 = Bytein If Pres8 > 0 Then Rate8 = Dur[Pres8] Else Clear Rate8 Clear Notes.8 EndIf Case note9 Pres9 = Bytein If Pres9 > 0 Then Rate9 = Dur[Pres9] Else Clear Rate9 Clear Notes.9 EndIf Case note10 Pres10 = Bytein If Pres10 > 0 Then Rate10 = Dur[Pres10] Else Clear Rate10 Clear Notes.10 EndIf Case note11 Pres11 = Bytein If Pres11 > 0 Then Rate11 = Dur[Pres11] Else Clear Rate11 Clear Notes.11 EndIf 'Case Else ' Set notePres ' GoTo Check_Timers ' no sort required EndSelect Set notePres '= 255 GoTo Check_Timers ' no sort required EndIf Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein GoTo Check_Timers ' no sort required Else value = Bytein GoSub Controller ' this will be followed with a re-sort EndIf EndSelect EndIf resort: GoSub SortTimers ' so we resort only if an incoming midi command changed something Check_Timers: ' here we check the Task counters and compare them with the 32 bit cnt value ' copied in time using the TimVals[] dword variables: If idx < 12 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 If Notes.0 = 0 Then Clear VelFlags.0 Clear Out0 Set TimVals[0] Else If VelFlags.0 = 1 Then Clear Out0 TimVals[0] = time + Rate0 Clear VelFlags.0 Else Set Out0 TimVals[0] = time + velo0 Set VelFlags.0 EndIf EndIf Case 1 If Notes.1 = 0 Then Clear VelFlags.1 Clear Out1 Set TimVals[1] Else If VelFlags.1 = 1 Then Clear Out1 TimVals[1] = time + Rate1 Clear VelFlags.1 Else Set Out1 TimVals[1] = time + velo1 Set VelFlags.1 EndIf EndIf Case 2 If Notes.2 = 0 Then Clear VelFlags.2 Clear Out2 Set TimVals[2] Else If VelFlags.2 = 1 Then Clear Out2 TimVals[2] = time + Rate2 Clear VelFlags.2 Else Set Out2 TimVals[2] = time + velo2 Set VelFlags.2 EndIf EndIf Case 3 If Notes.3 = 0 Then Clear VelFlags.3 Clear Out3 Set TimVals[3] Else If VelFlags.3 = 1 Then Clear Out3 TimVals[3] = time + Rate3 Clear VelFlags.3 Else Set Out3 TimVals[3] = time + velo3 Set VelFlags.3 EndIf EndIf Case 4 If Notes.4 = 0 Then Clear VelFlags.4 Clear Out4 Set TimVals[4] Else If VelFlags.4 = 1 Then Clear Out4 TimVals[4] = time + Rate4 Clear VelFlags.4 Else Set Out4 TimVals[4] = time + velo4 Set VelFlags.4 EndIf EndIf Case 5 If Notes.5 = 0 Then Clear VelFlags.5 Clear Out5 Set TimVals[5] Else If VelFlags.5 = 1 Then Clear Out5 TimVals[5] = time + Rate5 Clear VelFlags.5 Else Set Out5 TimVals[5] = time + velo5 Set VelFlags.5 EndIf EndIf Case 6 If Notes.6 = 0 Then Clear VelFlags.6 Clear Out6 Set TimVals[6] Else If VelFlags.6 = 1 Then Clear Out6 TimVals[6] = time + Rate6 Clear VelFlags.6 Else Set Out6 TimVals[6] = time + velo6 Set VelFlags.6 EndIf EndIf Case 7 If Notes.7 = 0 Then Clear VelFlags.7 Clear Out7 Set TimVals[7] Else If VelFlags.7 = 1 Then Clear Out7 TimVals[7] = time + Rate7 Clear VelFlags.7 Else Set Out7 TimVals[7] = time + velo7 Set VelFlags.7 EndIf EndIf Case 8 If Notes.8 = 0 Then Clear VelFlags.8 Clear Out8 Set TimVals[8] Else If VelFlags.8 = 1 Then Clear Out8 TimVals[8] = time + Rate8 Clear VelFlags.8 Else Set Out8 TimVals[8] = time + velo8 Set VelFlags.8 EndIf EndIf Case 9 If Notes.9 = 0 Then Clear VelFlags.9 Clear Out9 Set TimVals[9] Else If VelFlags.9 = 1 Then Clear Out9 TimVals[9] = time + Rate9 Clear VelFlags.9 Else Set Out9 TimVals[9] = time + velo9 Set VelFlags.9 EndIf EndIf Case 10 If Notes.10 = 0 Then Clear VelFlags.10 Clear Out10 Set TimVals[10] Else If VelFlags.10 = 1 Then Clear Out10 TimVals[10] = time + Rate10 Clear VelFlags.10 Else Set Out10 TimVals[10] = time + velo10 Set VelFlags.10 EndIf EndIf Case 11 If Notes.11 = 0 Then Clear VelFlags.11 Clear Out11 Set TimVals[11] Else If VelFlags.11 = 1 Then Clear Out11 TimVals[11] = time + Rate11 Clear VelFlags.11 Else Set Out11 TimVals[11] = time + velo11 Set VelFlags.11 EndIf EndIf 'Case Else ' ' in dit geval is idx geset ' GoTo jumpout End Select GoSub SortTimers ' find a new nxt and idx 'If time >= Nxt Then GoTo Check_Timers ' this causes an endless loop! ' we could try this ' if idx < 11 then ' if time >= Nxt then goto Check_Timers ' endif EndIf ' beveiliging tegen overflow crashes... If maxtim = 1 Then Clear time Clear VelFlags Clear Notes Set TimVals Clear Out0 Clear Out1 Clear Out2 Clear Out3 Clear Out4 Clear Out5 Clear Out6 Clear Out7 Clear Out8 Clear Out9 Clear Out10 Clear Out11 Clear Lite1 Clear Lite2 Clear Lite3 Clear Lite4 EndIf Else ' idx > 11, no timers running, so to avoid overflows, we can reset the timer If maxtim = 1 Then Clear time ' 16.06.2015 EndIf Btg PORTC.3 ' average loop-speed: 5.9 microseconds. (Tektronix measurement) GoTo LOOP ' end of the main 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 11 If TimVals[i] < Nxt Then Nxt = TimVals[i] ' 12 dword comparisons idx = i EndIf Next i ' dit volstaat als bescherming tegen timer overflows: ' If idx > 11 Then ' indien geen enkele timer geladen is... ' Clear time.Byte3 ' reset ' EndIf 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 30 ' controller to set all repeat frequencies to one and the same value at once If value = 0 Then 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 Clear Rate8 Clear Pres8 Clear Rate9 Clear Pres9 Clear Rate10 Clear Pres10 Clear Rate11 Clear Pres11 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] Pres8 = value Rate8 = Dur[value] Pres9 = value Rate9 = Dur[value] Pres10 = value Rate10 = Dur[value] Pres11 = value Rate11 = Dur[value] EndIf Case 66 'on/off for the robot If value = 0 Then Clear VelFlags 'stop all running timers Clear Notes Set TimVals Set idx Clear Out0 Clear Out1 Clear Out2 Clear Out3 Clear Out4 Clear Out5 Clear Out6 Clear Out7 Clear Out8 Clear Out9 Clear Out10 Clear Out11 ' reset all repetition rates: Clear Rate0 Clear Rate1 Clear Rate2 Clear Rate3 Clear Rate4 Clear Rate5 Clear Rate6 Clear Rate7 Clear Rate8 Clear Rate9 Clear Rate10 Clear Rate11 Clear Pres0 Clear Pres1 Clear Pres2 Clear Pres3 Clear Pres4 Clear Pres5 Clear Pres6 Clear Pres7 Clear Pres8 Clear Pres9 Clear Pres10 Clear Pres11 Clear CC66 Clear time Clear Lite1 Clear Lite2 Clear Lite3 Clear Lite4 Else 'If CC66 = 0 Then ' only if switched from OFF to ON Set CC66 '= value 'EndIf EndIf Case 123 Clear VelFlags Clear Notes Clear Out0 Clear Out1 Clear Out2 Clear Out3 Clear Out4 Clear Out5 Clear Out6 Clear Out7 Clear Out8 Clear Out9 Clear Out10 Clear Out11 Clear time Set TimVals Set idx Clear Lite1 Clear Lite2 Clear Lite3 Clear Lite4 EndSelect Set Ctrl '= 255 mandatory reset 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! 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 ' in this firmware the time value of one unit is 13.16 microseconds. [tektronix measurement 19.11.2015] ' so 76 corresponds to 1 ms ' for compatibility with the code in version 1.0 from 2006 ' we should cover a range of 1ms to 30ms, so from 76 to 2280 ' range: 2280 -76 = 2204 ' increment per velo-step = 2204/127 = 17.35 ' so we can calculate it as follows: 'Vels[1] = 76 For i = 1 To 127 Vels[i] = 76 + (17.35 * (i-1)) Next i 'Vels[0] = 42 ' not used ' measurement after this change: ' velo 1 = 800 microseconds ' velo 2 = 1.2 ms ' velo 127 = 26 ms Return '[EOF]