' ******************************************************************** ' * 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.01.2012: Motor wiring and connectors finished. ' 24.01.2012: AC optorelais tested o.k. with a 5V steering signal. ' 2 1W red LED mounted, steered with a P-channel mosfet. ' This be version 1.1. ' Lights tested o.k. on robot. ' 26.01.2012: to do: add code for optor steering for ebow. Will need CC24 ' or else, just CC23 itself. ' logic mistake in EnableCounter and EnableEbow corrected. ' Frequency counter is badly implemented! (IRQ) ' 28.01.2012: further development work. ' CC80 implemented ' optor input diode bug solved on board ' This be version 1.2 ' 29.01.2012: Test and debug session after some hardware changes on the board. ' CC51 implemented for motor movement. ' strange interference between CC7 and CC51 observed... ' Start implementation of vibrato control (CC42 only). Version 1.3 now. 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 (1= active, 0=disabled) $define EnableEbow PORTA.5 'start the ebow feedback (1= active, 0=disabled) ' $define Voltage PORTC.1 'PWM sturing e-bow drive - via optor HPWM 2, RC1 $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 RedBackLED PORTA.2 ' 1W LED on board - back $define RedFrontLED PORTA.3 ' 1W LED on board - frontal 'analoge ingangen $define tacho_in PORTA.0 'tacho ingang - analog A0 'frekwentiemeetingang: - uses INT0, interrupt source $define fsensor PORTB.0 ' pic pin 21 '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 CC23 As Byte System ' enable ebow Dim CC7 As Byte System ' ebow amplitude ' 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 CC80 As Byte System ' midi-output controller Dim MoutFreq As CC80.0 ' 7 bits can be used as commands Dim MoutTacho As CC80.1 Dim CC51End As CC80.5 Dim TuneOK As CC80.6 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 ' set when we have an open string ' Dim Lite1flag As flags.1 ' not used Dim Lite2flag As flags.2 ' back RED LED Dim Lite3flag As flags.3 ' front RED LED '----------------------------------------------------------------------------------------- '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 Low EnableCounter 'off High EnableEbow ' on High Pitch_High ' high and low pitch LED's on during startup. Low Pitch_Ok ' led High Pitch_Low ' led High RedBackLED ' p-channel driver, hence the inversion! High RedFrontLED HPWM 1, 0, PWMFreq4 'HPWM channel 1(RC2), duty cycle, frequency - not used here. HPWM 2, 0, PWMFreq4 'HPWM channel 2(RC1) - voltage for the e-bow optor ' initialize variables and controllers: CC20 = 39 ' tuning SollFreq = 78 SollTacho = 798 ' calculated 10 bit value for 78Hz CC22 = 0 ' autotune off CC23 = 1 ' ebow on 'CC40 = 0 ' vibrato off 'CC41 = 64 ' vibrato speed CC42 = 0 ' vibrato CC51 = 64 ' motor U/D movement '----------------------------------------------------------------------------------------- ' 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 Set EnableCounter ' enable the incoming pulses Set EnableEbow ' set feedback ON CC7 = 255 HPWM 2, CC7, PWMFreq4 ' ebow volume on maximum DelayMS 1000 ' wait for the frequency to stabilise ' for first test: 'Gosub TUNE ' skip until hardware is reliable!!! ' Clear EnableEbow ' after tuning the ebow should be turned off again Clear CC7 ' reset volume zero HPWM 2, CC7, PWMFreq4 ' ebow volume on minimum ' the counter-input stays enabled. '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 (?) Else Clear statusbyte 'reset the status byte End If GoTo Check_Timers 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 126 Set RedBackLED Clear VelFlags0.2 Clear Lite2flag Case 127 Set RedFrontLED Clear VelFlags0.3 Clear Lite3flag Case 39,51,63,75,87 Set StringFree Clear EnableEbow Case 40 To 86 Clear EnableEbow 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 126 Set RedBackLED Clear VelFlags0.2 Clear Lite2flag Case 127 Set RedFrontLED Clear VelFlags0.3 Clear Lite3flag Case 39,51,63,75,87 'CC20, CC20 + 12, CC20 + 24 Set StringFree Clear EnableEbow Case 40 To 86 Clear EnableEbow End Select Set noteAan '= 255 'reset !!! GoTo Check_Timers 'jump out Else Select noteAan Case 39,51,63,75,87 ' CC20 , CC20 + 12 ' open string Set StringFree Set EnableEbow Case 40 To 86 ' CC20+1 To 87 Clear StringFree Set EnableEbow Case 126 Clear RedBackLED ' inverted 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 127 Clear RedFrontLED 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 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.2 = 1 Then ' red light 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 ' red light 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 ' timer for motor movement veltim.Word1 = Velmsb[4] veltim.Word0 = VelLsb[4] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then Clear RotCW ' stop motor Clear RotCCW ' stop motor Clear VelFlags0.4 ' stop timer. It's a one shot Select Freq Case SollFreq Set Pitch_OK Clear Pitch_High Clear Pitch_Low Case < SollFreq Clear Pitch_OK Set Pitch_Low Clear Pitch_High Case > SollFreq Clear Pitch_OK Set Pitch_High Clear Pitch_Low EndSelect CC51 = 64 If CC51End = 1 Then HRSOut Control_Status, 51, 64 ' if flag is set in ctrl 80, send a message. EndIf EndIf If VelFlags0.5 = 1 Then ' vibrato timer - CC42 veltim.Word1 = Velmsb[5] veltim.Word0 = VelLsb[5] Cnt.Word0 = CntLw 'read counter If Cnt >= veltim Then If RotCW=1 Then Clear RotCW Set RotCCW GoTo Task5 EndIf If RotCCW=1 Then Clear RotCCW Set RotCW EndIf Task5: ' reprogram the timer for periodic operation: If CC42 = 0 Then Clear VelFlags0.5 'stop task, as lite is switched off Clear RotCW Clear RotCCW Else 'reload task5 'Set VelFlags0.5 'can just stay set Cnt.Word0 = CntLw veltim = Cnt + Task_rsi[5] 'add the period duration Velmsb[5] = veltim.Word1 VelLsb[5] = veltim.Word0 EndIf End If End If 'Else ' If CntHw > 0xFF Then Clear CntHw EndIf GoTo LOOP ' this to skip following code, which is for autotuning ' to be worked out... Param_Check: ' multitasking code: If StringFree = 1 Then If CC22 > 0 Then ' trigger If Freq = SollFreq Then Clear CC22 Set Pitch_OK Clear Pitch_High Clear Pitch_Low Clear RotCW Clear RotCCW If CC23 = 0 Then Clear EnableEbow ' e-bow off EndIf If TuneOK=1 Then HRSOut Control_Status, 22, 127 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 EndIf EndIf EndIf If MoutFreq = 1 Then ' CC80 bit 0 must be set If Freq <> OldFreq Then i = Freq & 127 j = Freq >> 7 HRSOut Keypres_Status, j, i ' for debug OldFreq = Freq EndIf EndIf ' for debugging and alignment of coding: If MoutTacho = 1 Then ' CC80 bit 1 must be set 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 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 Set RedBackLED 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 RedBackLED EndIf Return Task3: If Lite3flag = 0 Then Clear VelFlags0.3 'stop task, as lite is switched off Set RedFrontLED 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 RedFrontLED EndIf Return KeyPres: 'implemented for light flashing speed modulation Select notePres Case 126 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 Set RedBackLED EndIf Case 127 If Lite3flag = 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 Set RedFrontLED 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 7 ' ebow volume controller CC7 = value << 1 If value > 0 Then Inc CC7 End If HPWM 2, CC7, PWMFreq4 Case 20 ' sets the fundamental openstring tuning. By design = 39 ' this controller is only for debug and development. If value > 35 And value < 46 Then CC20 = value 'HRSOut NoteOn_Status, Ctrl, value ' for debug Else CC20 = 39 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 Set EnableCounter Set EnableEbow HPWM 2, 255, PWMFreq4 ' volume on maximum for ebow ' 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 23 ' 32 would be in conflict with the finger board ' enables the ebow mechanism ' this controller may be obsolete, as e-bow is switched on note-offs and will ' only work when CC7 is set. CC23 = value If CC23 > 0 Then Set EnableEbow Else Clear 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 - not required ' CC41 = value ' 'HRSOut NoteOn_Status, Ctrl, value Case 42 ' vibrato depth controller - virbrato speed is a function of depth in this coding CC42 = value 'HRSOut NoteOn_Status, Ctrl, value If CC42 > 0 Then If RotCW + RotCCW = 0 Then Set RotCCW EndIf Set VelFlags0.5 Cnt.Word0 = CntLw 'read timer Task_rsi[5] = CC42 << 7 'scaling to be checked veltim = Cnt + Task_rsi[5] 'add the period duration Velmsb[5] = veltim.Word1 VelLsb[5] = veltim.Word0 Else Clear VelFlags0.5 Clear RotCW Clear RotCCW EndIf Case 51 ' midi motor up / down command ' values < 64 = motor down ' value = 64 = stop motor ' values > 64 = motor up CC51 = value Select CC51 Case 64 ' Set Pitch_OK ' clear Pitch_High ' Clear Pitch_Low Clear rotCW Clear rotCCW Clear VelFlags0.4 Case < 64 ' Clear Pitch_OK ' set Pitch_Low ' Clear Pitch_High 'If VelFlags0.4 = 0 Then ' previous movement command must have been completed ' lower pitch and set a timer value = 64 - value Clear rotCW Set VelFlags0.4 Cnt.Word0 = CntLw 'read timer Task_rsi[4] = CC51 << 7 'scaling to be checked veltim = Cnt + Task_rsi[4] 'add the period duration Velmsb[4] = veltim.Word1 VelLsb[4] = veltim.Word0 Set rotCCW 'EndIf Case > 64 ' Clear Pitch_OK ' Set Pitch_High ' Clear Pitch_Low 'If VelFlags0.4 = 0 Then ' higher pitch and set a timer value = value - 64 Clear rotCCW Set VelFlags0.4 Cnt.Word0 = CntLw 'read timer Task_rsi[4] = CC51 << 7 'scaling to be checked veltim = Cnt + Task_rsi[4] 'add the period duration Velmsb[4] = veltim.Word1 VelLsb[4] = veltim.Word0 Set rotCW 'EndIf EndSelect Case 66 'on/off for the robot If value = 0 Then GoSub PowerDown 'subroutine EndIf 'HRSOut NoteOn_Status, Ctrl, value Case 80 CC80 = value ' the effect of this is: 'if value.0 then set MoutFreq else clear Moutfreq 'IF value.1 Then Set MoutTacho Else Clear MoutTacho 'if value.5 then Set CC51End else clear CC51end 'if value.6 then set TuneOK else clear TuneOK Case 123 GoSub AllNotesOff 'subroutine 'HRSOut NoteOn_Status, Ctrl, value End Select Set Ctrl '= 255 'mandatory reset Return AllNotesOff: Low Debug_Led Clear EnableEbow Clear CC23 Set RedBackLED Set RedFrontLED Clear VelFlags HPWM 2, 0, PWMFreq4 Clear CC7 Return PowerDown: Low RotCW Low RotCCW Low Pitch_High Low Pitch_Low Low Pitch_OK Clear EnableEbow Clear CC23 Low Debug_Led Clear VelFlags HPWM 2, 0, PWMFreq4 Clear CC7 Clear CntHw ' reset 32-bit counter Set RedBackLED Set RedFrontLED Return TUNE: ' subroutine not using the interrupt timers 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 ' lsb j = Freq >> 7 ' msb 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 HRSOut Control_Status, 22, 127 Return ' GoTo MAIN End If If Freq > SollFreq Then Clear RotCW Set RotCCW ' start motor, pitch down 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 ' we have to add a loop-counter with an upper limit. Return '[EOF]