' ******************************************************************** ' * PIC firmware for Synchrochord * ' * autotuner component * ' * coded by dr.Godfried-Willem Raes * ' * http://www.logosfoundation.org/instrum_gwr/synchrochord/picworks * ' * source code development directory: * ' * Syntuner.bas * ' ******************************************************************** ' 14.11.2011: always keep together with all referenced includes ' frequency counter implemented as a high interrupt source on INT0 ' sampler for tacho analog input implemented in the low interrupt code ' flashing lites implemented ' autotuning on init implemented. ' This be version 1.0 ' 23.11.2011: First version seems to work. ' 23.11.2011: Motor wiring and connectors finished. Include "18F2525.inc" 'version for the dedicated board (40MHz, 5V) 'Include "18F2520.inc" 'also possible. (40MHz, 5V) 'Include "18F25K20.inc" 'for test & debug on an Amicus board. (64MHz, 3V3) ' this include is not required with the Amicus IDE but is ' essential for the Proton Compiler. ' Initialize ports: 'uitgangen $define RotCW PORTC.5 'rotate motor clockwize- this tunes the string upwards - pic pin 16 $define RotCCW PORTC.4 'rotate motor counterclockwize - this loosens the string - pic pin 15 $define EnableCounter PORTA.4 'gate for frequency counter (0= active, 1=disabled) $define EnableEbow PORTA.5 'start the ebow feedback (0= active, 1=disabled) $define Voltage PORTC.1 'PWM sturing e-bow drive $define Debug_Led PORTB.5 'for testing - red led - watchdog $define Pitch_High PORTB.3 'led - red $define Pitch_ok PORTB.2 'led - green $define Pitch_Low PORTB.1 'led - yellow $define Lite1 PORTA.1 ' LED spot - as yet unmounted. $define Lite2 PORTA.2 ' LED spot $define Lite3 PORTA.3 ' LED spot 'analoge ingangen $define tacho_in PORTA.0 'tacho ingang - analog A0 'frekwentiemeetingang: - uses INT0, interrupt source $define fsensor PORTB.0 'midi seriele datalijnen (usart) $define MIDI_Out PORTC.6 'MIDI uit $define MIDI_In PORTC.7 'MIDI in Clear SSPCON1.5 'RC3 must be available for I/O TRISA = %10000001 'A0 = input / A4,A5 = output A6, A7 = clock! TRISB = %11000001 'BO = input / B1, B2, B3, B4, B5 = output / B6, B7 = input TRISC = %11000000 'C0, C1, C2, C3, C4, C5= output / C6, C7 = input '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 'CONSTANTS: 'initialisations for the midi input parser: Symbol Midichannel = 10 ' Midi kanaal 10 Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel ' 2 bytes follow Symbol Keypres_Status = 160 + Midichannel ' 2 bytes follow Symbol Control_Status = 176 + Midichannel ' 2 bytes follow 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 PWMminF = 3906 Symbol PWMFreq2 = PWMminF * 2 ' PWMminF is processor dependent. Symbol PWMFreq3 = PWMminF * 3 ' declared in the processor include Symbol PWMFreq4 = PWMminF * 4 'Setup the USART Declare Hserial_Baud = 31250 ' Set baud rate for the USART to MIDI specs. Declare Hserial_TXSTA = 0x24 ' Hserial_TXSTA, sets the respective hardware register, TXSTA, to the value ' in the Declare. See the PIC18F25K20 or PIC18F25K22 data sheet for the device ' used for more information regarding this register. The TXSTA register BRGH ' bit (bit 2) controls the high speed mode for the baud rate generator. ' Certain baud rates at certain oscillator speeds require this bit to be set ' to operate properly. To do this, set Hserial_TXSTA to a value of $24 ' instead of the default $20. Refer to the PIC18F25K20 or PIC18F25K22 data ' sheet for the hardware serial port baud rate tables and additional ' information. 'VARIABLES (also used in interrupt code) Dim Cnt As Dword System 'Dword type variables may hold a value from -2147483648 to +2147483647 'making this one of the largest of the variable family types. This comes at a price 'however, as Dword calculations and comparisons will use _ 'more code space within the microcontroller. Use this type of variable sparingly, 'and only when necessary. ' Cnt= CntHw + Cnt Lw Dim CntHw As Cnt.Word1 ' alias required in timer0 interrupt '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 'timer by stating Cnt.word0 = CntLw ' 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 Dim j As Byte System 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 newtim As Dword System ' var's for the core of the multitasker: Dim VelFlags As Word System 'bits 0 - 15 used as flags for active timers 'Velflags=Velflags0 and Velflags1 Dim VelFlags0 As VelFlags.Byte0 'alias for bits 0-7 Dim VelFlags1 As VelFlags.Byte1 'bits 8-15 - not used in this code. ' for midi steering of functional parameters: Dim CC20 As Byte System ' set fundamental tuning (normally 39) Dim CC22 As Byte System ' autotune command Dim CC32 As Byte System ' enable ebow Dim CC40 As Byte System ' vibrato on/off Dim CC41 As Byte System ' vibrato speed Dim CC42 As Byte System ' vibrato depth Dim CC51 As Byte System ' motor up/down under midi control Dim st As Byte System Dim b1 As Byte System Dim b2 As Byte System Dim Tacho As Word System ' for AD-input channel Dim Tacho_Oldval As Word System ' for reduction of midi data flow Dim SollTacho As Word System Dim Freq As Word System ' a byte could be enough... to be tested. Dim OldFreq As Word System Dim CsCnt As Byte System ' centisecond counter for Timer3 Dim FreqCnt As Word System ' frequency counter in the Hi-interrupt. Dim SollFreq As Byte System Dim flags As Byte System Dim StringFree As flags.0 Dim Lite1flag As flags.1 Dim Lite2flag As flags.2 Dim Lite3flag As flags.3 '----------------------------------------------------------------------------------------- 'Load the USART Interrupt handler And buffer read subroutines into memory 'Include "ADC.inc" ' Load the ADC macros into the program Include "SynTuner_Irq.inc" ' our own version for UART, INT0 and Timer0/3 Interrupt 'Include "Timers.inc" ' required for velo support with timed pulses and periods. 'Include "DwordArrays.inc" ' support for dword arrays. 'framework for a MULTITASKER 'ARRAYS 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 pins (enkel uitgangen, geen ingangen!) on start up: Low Debug_Led Low RotCW Low RotCCW High EnableCounter High EnableEbow High Pitch_High Low Pitch_Ok High Pitch_Low Low Lite1 Low Lite2 Low Lite3 HPWM 1, 0, PWMminF 'HPWM channel 1(RC2), duty cycle, frequency HPWM 2, 0, PWMminF 'HPWM channel 2(RC1) ' initialize variables and controllers: CC20 = 39 ' tuning SollFreq = 78 CC22 = 0 ' autotune off CC32 = 0 ' ebow off CC40 = 0 ' vibrato off CC41 = 64 ' vibrato speed CC42 = 3 ' vibrato depth '----------------------------------------------------------------------------------------- ' before entering the main loop, we code an autotune procedure: ' during this procedure, the processor ' will not have any interrupts enabled! INIT: ' something should excite the string on entry though ' A solution might be to have the dsPIC excite the rotator ' for about 250ms. DelayMS 250 ' wait till excitation is over Clear EnableCounter ' enable the incoming pulses Clear EnableEbow ' set feedback ON DelayMS 1000 ' wait for the frequency to stabilise ' for first test: GoTo MAIN TUNE: Freq = Counter fsensor, 1000 ' count incoming pulses for 1000ms - blocking call! If Freq = SollFreq Then Set Pitch_Ok Clear Pitch_High Clear Pitch_Low Clear RotCW Clear RotCCW i = Freq & 127 j = Freq >> 7 HRSOut Keypres_Status, j, i ' for debug OldFreq = Freq ' get a reference value for the tacho: Clear Tacho ' must be word! For i = 0 To 15 Tacho = Tacho + ADIn 0 ' do we need to insert a delay here? DelayMS 10 ' sampling rate 100 S/s Next i SollTacho = Tacho >> 4 ' bring back to 10 bits GoTo MAIN End If If Freq > SollFreq Then Set RotCCW ' start motor, pitch down Clear RotCW Set Pitch_High Clear Pitch_Low Clear Pitch_Ok DelayMS (Freq - SollFreq) << 8 Clear RotCCW ' stop motor Else Clear RotCCW ' start motor, pitch up Set RotCW Clear Pitch_High Set Pitch_Low Clear Pitch_Ok DelayMS (SollFreq - Freq) << 8 Clear RotCW ' stop motor EndIf GoTo TUNE ' will be an endless loop if anything goes wrong 'MAIN PROGRAM MAIN: High Debug_Led DelayMS 50 ' wait for stability Low Debug_Led Clear VelFlags 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 'OPEN TIMER: Opentimer0 (Timer_INT_On & T0_16BIT & T0_SOURCE_INT & T0_PS_1_256) in macro file. Clear T1CON ' timer1 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 ' Enable the hardware interrupt INT0 (always high priority): Clear IntConBits_INT0IF ' clear interrupt flag Set INTCONBITS_INT0IE ' enable the interrupt 'OPEN ADC ' Fosc/64 ' Right justified for 10-bit operation ' Tad value of 0 ' Vref+ at Vcc : Vref- at Gnd ' Make AN0 an analogue input Declare Adin_Res = 10 ' 10-bit result required Declare Adin_Tad = 64_Fosc 'ADC_FOSC_32 Declare Adin_Stime = 25 ' 50 ' following works in the Proton compiler but not in the Amicus version of it... ' OpenADC(ADC_FOSC_64 & ADC_LEFT_JUST & ADC_0_TAD, ADC_REF_VDD_VSS, ADC_5ANA) ' Note: 18F2520 has ADC_V5, whilst 18F25K20 has ADC_V8, channel selection bits are different!!! ADCON2 = %10001110 'bit 7: ADFM: A/D result format select bit / 1= right justified, 0=left justified 'bit 6= ongebruikt, dus 0 'bit 5-3: A/D acquisition Time select bits / 001= 2 TAD 'bit 2-0: A/D conversion clock select bits / 110= FOSC/64 ' This is the same for 18F2520 and 18F25K20 'ADCON1 = %00001010 'bit 7-6: ongebruikt, dus 0 'bit 5: Voltage reference configuration bit (VREF- source) / 0=VSS 'bit 4: Voltage reference configuration bit (VREF+ source) / 0=VDD 'bit 3-0: 1010: AN0-AN4 'AN5-AN12: digitaal (worden niet gebruikt) ' for 18F2520 1010 is o.k., for 18F25K20 it should be 00011111 in ANSEL instead ' voor Fa ADCON1 = %00001110 wat betekent AN0 analoog, An1-12: digitaal ' voor Korn ADCON1 = %00001101 dus, AN0 en AN1 analoog, rest, digitaal ADCON1 = %00001110 ' AN0 is used for reading the tacho ' voor de 18F25K20 is de implementatie anders!!! ADCON0 = %00000001 'bit 7-6: ongebruikt, dus 0 'bit 5-2: Analog Channel Select bits / 0000 = Channel O (AN0) ' 0001 = Channel 1 (AN1) ' 0010 = AN2 ' 0011 = AN3 ' 0100 = AN4 'bit 1 = A/D conversion status bit / bit 1 = 1 (A/D conversion in progress) / bit 1=0 (A/D idle) ' Setting this bit starts a conversion. 'bit 0 moet gelijk zijn aan 1 (A/D converter module is enabled) (ADON bit) 'OPEN TIMER: 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 multitasking program loop: LOOP: 'midi parser ' 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 - no longer. statusbyte = Bytein Set notePres '= 255 Set pres '= 255 Case Control_Status ' this is the main thing to listen to.... 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 120 Clear Lite1 Clear VelFlags0.1 'bit 1 of Velflags0 Clear Lite1flag Case 121 Clear Lite2 Clear VelFlags0.2 Clear Lite2flag Case 123 Clear Lite3 Clear VelFlags0.3 Clear Lite3flag Case CC20 Set StringFree Case CC20 + 12 Set StringFree 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 120 Clear Lite1 Clear VelFlags0.1 'bit 1 of Velflags0 Clear Lite1flag Case 121 Clear Lite2 Clear VelFlags0.2 Clear Lite2flag Case 122 Clear Lite3 Clear VelFlags0.3 Clear Lite3flag Case CC20 Set StringFree Case CC20 + 12 Set StringFree End Select Set noteAan '= 255 'reset !!! GoTo Check_Timers 'jump out Else Select noteAan Case CC20 ' open string Set StringFree Case CC20 + 12 Set StringFree Case 120 Set Lite1 Set Lite1flag If velo = 127 Then Clear VelFlags0.1 ' stop flashing Else ' velocity byte steers the period of the flashing notePres = noteAan pres = velo GoSub KeyPres EndIf Case 123 Set Lite2 Set Lite2flag If velo = 127 Then Clear VelFlags0.2 ' stop flashing Else ' velocity byte steers the period of the flashing notePres = noteAan pres = velo GoSub KeyPres EndIf Case 123 Set Lite3 Set Lite3flag If velo = 127 Then Clear VelFlags0.3 ' stop flashing Else ' velocity byte steers the period of the flashing notePres = noteAan pres = velo GoSub KeyPres EndIf Case Else Clear StringFree End Select EndIf 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 'subroutine ' EndIf End Select EndIf 'einde midi input parser 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 'als bit 0 of Velflags0 =1 veltim.Word1 = Velmsb[0] 'the high word of Dword veltim.Word0 = VelLsb[0] 'the low word of Dword Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then GoSub Task0 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 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 EndIf If VelFlags0.3 = 1 Then veltim.Word1 = Velmsb[3] veltim.Word0 = VelLsb[3] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then GoSub Task3 EndIf If VelFlags0.4 = 1 Then veltim.Word1 = Velmsb[4] veltim.Word0 = VelLsb[4] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then GoSub Task4 ' ' reload task1 to start a new drip: ' veltim = Task_rsi[1] ' veltim = veltim + Cnt ' Velmsb[1] = veltim.Word1 ' VelLsb[1] = veltim.Word0 ' Set VelFlags0.1 ' gets reset after each drip ' 'Clear Drup2 ' ' and now reprogram the dripping frequency ' veltim = Task_rsi[4] ' veltim = veltim + Cnt ' Velmsb[4] = veltim.Word1 ' VelLsb[4] = veltim.Word0 EndIf EndIf If VelFlags0.5 = 1 Then veltim.Word1 = Velmsb[5] veltim.Word0 = VelLsb[5] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then GoSub Task5 ' veltim = Task_rsi[2] ' veltim = veltim + Cnt ' Velmsb[2] = veltim.Word1 ' VelLsb[2] = veltim.Word0 ' Set VelFlags0.2 ' gets reset after each drip ' 'Clear Drup3 ' ' and now reprogram the dripping frequency in function of ' ' FSR2: ' veltim = Task_rsi[5] ' veltim = veltim + Cnt ' Velmsb[5] = veltim.Word1 ' VelLsb[5] = veltim.Word0 EndIf EndIf 'Else ' If CntHw > 0xFF Then Clear CntHw EndIf Param_Check: ' multitasking code: If CC20 > 0 Then If Freq = SollFreq Then Clear CC22 Set Pitch_OK Clear Pitch_High Clear Pitch_Low Clear RotCW Clear RotCCW If CC32 = 0 Then Set EnableEbow ' e-bow off (inverted logic!) EndIf EndIf If Freq > SollFreq Then Set Pitch_High Clear Pitch_OK Clear Pitch_Low Set RotCW ' start motor Clear RotCCW Else Clear Pitch_High Clear Pitch_OK Set Pitch_Low Clear RotCW Set RotCCW End If End If If Tacho <> Tacho_Oldval Then i = Tacho & 127 ' lowest 7 bits j = Tacho >> 7 ' highest 7 bits HRSOut Pitchbend_Status, j, i ' 14 bits, msb first, little endian Tacho_Oldval = Tacho EndIf If Freq <> OldFreq Then i = Freq & 127 j = Freq >> 7 HRSOut Keypres_Status, j, i ' for debug OldFreq = Freq EndIf GoTo LOOP ' end of the main loop ' ************************************************************************************ ' procedures: Task0: 'free Return Task1: If Lite1flag = 0 Then Clear VelFlags0.1 'stop task, as lite is switched off Clear Lite1 Else 'reload task1 - light 'Set VelFlags0.1 'can just stay set Cnt.Word0 = CntLw veltim = Cnt + Task_rsi[1] 'add the period duration Velmsb[1] = veltim.Word1 VelLsb[1] = veltim.Word0 btg Lite1 EndIf Return Task2: If Lite2flag = 0 Then Clear VelFlags0.2 'stop task, as lite is switched off Clear Lite1 Else 'reload task2 - light 'Set VelFlags0.2 'can just stay set Cnt.Word0 = CntLw veltim = Cnt + Task_rsi[2] 'add the period duration Velmsb[2] = veltim.Word1 VelLsb[2] = veltim.Word0 btg Lite2 EndIf Return Task3: If Lite3flag = 0 Then Clear VelFlags0.3 'stop task, as lite is switched off Clear Lite3 Else 'reload task1 - light 'Set VelFlags0.3 'can just stay set Cnt.Word0 = CntLw veltim = Cnt + Task_rsi[3] 'add the period duration Velmsb[3] = veltim.Word1 VelLsb[3] = veltim.Word0 btg Lite3 EndIf Return Task4: 'free Return Task5: 'free Return KeyPres: 'implemented for light flashing speed modulation Select notePres Case 120 If Lite1flag = 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 Lite1 EndIf Case 121 If Lite2flag = 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 Lite2 EndIf Case 122 If Lite1flag = 1 Then Set VelFlags0.3 Cnt.Word0 = CntLw 'read timer Task_rsi[3] = (~pres & 127) << 9 veltim = Cnt + Task_rsi[3] 'add the period duration Velmsb[3] = veltim.Word1 VelLsb[3] = veltim.Word0 Else Clear VelFlags0.3 Clear Lite3 EndIf EndSelect 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 20 ' sets the fundamental openstring tuning. By design = 39 If value > 35 And value < 46 Then CC20 = value HRSOut NoteOn_Status, Ctrl, value ' for debug End If Select CC20 Case 36 SollFreq = 65 Case 37 SollFreq = 69 Case 38 SollFreq = 73 Case 39 SollFreq = 78 Case 40 SollFreq = 82 Case 41 SollFreq = 87 Case 42 SollFreq = 93 Case 43 ' this is beyond the range of the tacho! SollFreq = 98 Case 44 SollFreq = 104 Case 45 SollFreq = 110 EndSelect ' here we have a lookup for the frequencies as well as for ' the corresponding tacho-voltages. (to add) Case 22 ' should start the autotune procedure. ' other pics should make sure we have an open string and no damping. CC22 = value Low EnableCounter Low EnableEbow HRSOut NoteOn_Status, Ctrl, value ' on completion of the procedure, the Pitch_Ok led will light up ' a midi out message will be sent and CC22 will be reset to 0. Case 32 ' enables the ebow mechanism CC32 = value If CC32 > 0 Then Low EnableEbow Else High EnableEbow EndIf HRSOut NoteOn_Status, Ctrl, value Case 40 ' vibrato on/off switch CC40 = value HRSOut NoteOn_Status, Ctrl, value Case 41 ' vibrato speed controller CC41 = value HRSOut NoteOn_Status, Ctrl, value Case 42 ' vibrato depth controller CC42 = value HRSOut NoteOn_Status, Ctrl, value Case 51 ' midi motor up / down command ' values < 64 = motor down ' value = 64 = stop motor ' values > 64 = motor up CC51 = value HRSOut NoteOn_Status, Ctrl, value Case 66 'on/off for the robot If value = 0 Then GoSub PowerDown 'subroutine EndIf HRSOut NoteOn_Status, Ctrl, value Case 123 GoSub AllNotesOff 'subroutine HRSOut NoteOn_Status, Ctrl, value End Select Set Ctrl '= 255 'mandatory reset Return AllNotesOff: Low Debug_Led High EnableEbow Clear VelFlags HPWM 2, 0, PWMFreq4 Return PowerDown: Low RotCW Low RotCCW Low Pitch_High Low Pitch_Low Low Pitch_OK High EnableEbow Low Debug_Led Clear VelFlags HPWM 2, 0, PWMFreq4 Clear CntHw ' reset 32-bit counter Return '[EOF]