'**************************************************************************** '* -Parser * '* by * '* Godfried-Willem Raes * '* 07.11.2017 * ' *************************************************************************** '01.08.2016: Test and debug board designed, etched and soldered. ' Programming requires the PiCkit3 programmer. PicKit2 does not work! '11.08.2016: dedicated midi-mirror programmed. ' This is our piece 'mmMagic' to be premiered 17.08.2016 ' PCB made and soldered. ' Midi-channel selectable on cold boot with the jumpers. ' Midi out, using the circular buffer now working to perfection. '12.08.2016: Mirrored X up and working for the player piano. ' Latency is 1ms (the time for a complete 3-byte midi-message) ' ---------------------------------------------------------------------------------- '21.10.2017: Starting from the Mirrored-X code to port the 18F2525 code from parser V1.6 ' This code uses double circular buffering for MIDI ' No timer-events in this code '22.10.2017: min, max functions not implemented in the Proton24 compiler, so we ' had to recode these. ' All timer coding removed. Code cleanup performed. First tests on board and ' with Tektronix scope o.k. '23.10.2017? Leaving it on overnight, no crashes. ' First test on : only note 36 seems to work... ' Pacing of the midi out stream made it work again... ' apparently the dsPICs cannot handle neck to neck midi. '24.10.2017: all PWM code removed from this file, as we do not use these modules here. '07.11.2017: a resistor on the parser board was found defective. This explain why the ' trebble side yellow light was not working. '07.12.2020: checked for occurence of the TMR3 bug, but this timer is not used at all in this code. ''------------------------------------------------------------------------------------------------------------- ' START: Device = 24EP128MC202 ' this code should also work on 24EP32MC202, 24EP64MC202, 24EP256MC202, 24EP512MC202 ' and dsPIC33EP32MC202, dsPIC33EP64MC202, dsPIC33EP128MC202, dsPIC33EP256MC202, dsPIC33EP512MC202 ' and dsPIC33EP32MC502, dsPIC33EP64MC502, dsPIC33EP128MC502, dsPIC33EP256MC502, dsPIC33EP512MC502 Clear Config FPOR = ALTI2C1_OFF, ALTI2C2_OFF ' unsure about this Config FWDT = WDTPOST_PS256, WINDIS_OFF, PLLKEN_ON, FWDTEN_OFF ' FWDTEN_OFF disables the WDT (watchdog timer) RCON.5 = 0 ' clear the watchdog enable bit for reset = SWDTEN_OFF ' first configure the clock... ' select internal FRC at POR not using PLL: Config FOSCSEL = FNOSC_FRC, IESO_OFF DelayMS 10 ' make sure we assign the correct pins to use for the ICD (Pickit3) Config FICD = ICS_PGD1, JTAGEN_OFF ' this sets the pins used for the programmer ' enable clock switching and configure POSC for XT mode with 10MHz crystal Config FOSC = FCKSM_CSECMD, OSCIOFNC_OFF, POSCMD_XT Main_Setup: ' configure PLL prescaler, PLL postscaler, PLL divisor PLLFBD = 46 CLKDIV.7 = 0 'PLLPOST N2=2 CLKDIV.6 = 0 CLKDIV.0 = 0 'PLLPRE N1=2 CLKDIV.1 = 0 CLKDIV.2 = 0 CLKDIV.3 = 0 CLKDIV.4 = 0 Write_OSCCONH ($3) ' = __builtin_write_OSCCONH(0x03) Write_OSCCONL (OSCCON | %1) ' = __builtin_write_OSCCONL(OSCCON | 0x01) PLL_Setup(48, 2, 2, $0300) ' should set it to 120MHz operation with 10MHz X-tal ' Fosc = 10MHz * 48 / 2 * 2 = 120MHz ' now we get a 10MHz clock signal on pin OSC2, pin10... DelayMS 1000 ' wait for stability ' wait for the clock switch to occur: 'while OSCCON & %0111000000000000 = %0011000000000000 ' mask for COSC bits 14-12 'wend ' wait for pll to lock ' this is done in de PLL_setup macro 'while osccon.5 = 1 'wend Declare Xtal = 120 ' set to Fosc ' rem out the following according to the needs: '$define Enable_ADC12bit ' precompiler instructions '$define Enable_PWM ' precompiler instructions $define Enable_Timer1 ' precompiler instructions - 16 bit timer $define Enable_Timer23 ' 32-bit timer $define Enable_UART_RX $define Enable_UART_TX '$define enable_Timer45 ' 32-bit timer '$define Enable_Timer4 ' as 16 bit timer '$define Enable_Timer5 ' as 16 bit timer ' ------------------------------------------------------------------- ' as we do not use Proton basic HRSin and HRSout commands, we do not need these settings: ' Declare Hserial_Baud = 31250 ' USART1 baud rate - set to MIDI ' Declare Hrsout1_Pin = PORTB.8 ' RP40 ' Select the pin for TX with USART1 'Declare HRSin1_Pin = PORTB.9 ' RP41 ' HrsOut_Pace 320 PPS_Output(cOut_Pin_RP40, cOut_Fn_U1TX) ' Map UART1 TX pin to RP40 'RP35 PPS_Input(cIn_Pin_RP41, cIn_Fn_U1RX) ' Map UART1 RX pin to RP41 'RPI34 ' constant declarations and port-assignments for debugging: '*********************************************************** 'initialisations for the midi input parser: Symbol Midichannel = 1 ' Aeio_Channel Symbol NoteOff_Status = 128 + Midichannel ' 2 bytes follow Symbol NoteOn_Status = 144 + Midichannel Symbol Keypres_Status = 160 + Midichannel Symbol Control_Status = 176 + Midichannel Symbol ProgChange_Status = 192 + Midichannel ' 1 byte message Symbol Aftertouch_Status = 208 + Midichannel ' 1 byte follows Symbol Pitchbend_Status = 224 + Midichannel ' lsb msb follow ' Mapping defines for midi-events on pin outputs: $define midi_led PORTB.15 ' pin 26 $define debug_led PORTB.13 ' pin 24 $define loopcnt PORTB.11 ' pin 22 ' mapping for our new Aeio-parser board (21.10.2017) $define Note0 PORTB.14 ' Led light for string 36 $define Note1 PORTB.12 ' Led light for string 37 $define Note2 PORTB.10 ' 38 $define Note3 PORTB.7 ' 39 $define Note4 PORTB.6 ' 40 $define Note5 PORTB.5 ' 41 $define Note6 PORTA.4 ' 42 $define Note7 PORTB.4 ' 43 $define Note8 PORTB.1 ' 44 $define Note9 PORTB.0 ' 45 $define NoteA PORTA.1 ' 46 $define NoteB PORTA.0 ' 47 TRISA = %10000000 ' set to output 'TRISB = %0000000000000000 ' bits for the ICD must be input Output midi_led Output debug_led ' watchdog led Output loopcnt $ifdef Enable_Timer1 ' init timer1: ---------------------------------------------------- ' used as watchdog IFS0bits_T1IF = 0 ' clear Timer1 interrupt flag IPC0bits_T1IP0 = 0'1 ' set priority IPC0bits_T1IP1 = 0 '1 ' set to 4 IPC0bits_T1IP2 = 1 IEC0bits_T1IE = 1 ' Enable the Timer1 interrupt TMR1 = 0 ' clear the count PR1 = 65535 ' load Timer1 period T1CON.5 = 1 ' set prescaler to :256 T1CON.4 = 1 ' 1 T1CON.15 = 1 ' start 'T1CON = %1000000000110000 ' pre-scale 256. bit 15 is "start" $endif $ifdef Enable_Timer23 T2CONBITs_T32 = 1 ' 32- bit timer start T2CONbits_TCS = 0 ' internal clock T2CONbits_TON = 1 T2CONbits_TSIDL = 0 T2CON.5 = 1 ' pre-scale 256 T2CON.4 = 1 ' id. TMR2 = 0 TMR3HLD = 0 PR2 = 65535 PR3 = 65535 IPC2bits_T3IP0 = 0 ' set priority to 4 IPC2bits_T3IP1 = 0 IPC2bits_T3IP1 = 1 IFS0bits_T3IF = 0 ' clear IRQ flag IEC0bits_T3IE = 1 ' enable timer 3 interrupt $endif $ifdef enable_Timer45 T4CONBITs_T32 = 1 ' 32- bit timer start T4CONbits_TCS = 0 ' internal clock T4CONbits_TON = 1 T4CONbits_TSIDL = 0 T4CON.5 = 1 ' pre-scale 256 T4CON.4 = 1 TMR4 = 0 TMR5 = 0 PR4 = 65535 PR5 = 65535 IPC7bits_T5IP0 = 1 ' set priority to 3 IPC7bits_T5IP1 = 1 IPC7bits_T5IP2 = 0 IFS1bits_T5IF = 0 ' clear IRQ flag IEC1bits_T5IE = 1 ' enable timer 5 interrupt $endif $ifdef Enable_Timer4 T4CON.15 = 1 ' start timer in 16 bit mode T4CON.13 = 0 T4CON.6 = 0 T4CON.5 = 0 ' prescaler set to 8 T4CON.4 = 0 '1 T4CON.3 = 0 ' operate as 16 bit timer T4CON.1 = 0 ' internal clock TMR4 = 0 PR4 = 65535 Clear IFS1.11 ' clear interrupt flag Set IEC1.11 ' enable interrupt IPC6bits_T4IP0 = 1 ' set priority to 5 IPC6bits_T4IP1 = 0 IPC6bits_T4IP2 = 1 $endif $ifdef Enable_Timer5 T5CON.15 = 1 ' start timer in 16 bit mode T5CON.13 = 0 T5CON.6 = 0 T5CON.5 = 0 ' prescaler set to 8 T5CON.4 = 0'1 ' id. T5CON.1 = 0 ' internal clock TMR5 = 0 PR5 = 65535 ' preset counter IPC7bits_T5IP0 = 1 ' set priority to 5 IPC7bits_T5IP1 = 0 IPC7bits_T5IP2 = 1 IFS1bits_T5IF = 0 ' clear IRQ flag IEC1bits_T5IE = 1 ' enable timer 5 interrupt $endif $ifdef Enable_UART_RX ' init UART1-receiver: 31250 Baud ' should generate an interrupt for each byte received U1MODE.0 = 0 ' = U1MODEbits.STSEL = 0 ' 1 stop-bit U1MODE.1 = 0 ' U1MODEbits.PDSEL = 0 ' 8 bit no parity U1MODE.2 = 0 U1MODE.5 = 0 ' =U1MODE_bits.ABAUD = 0 ' no autobauding U1MODE.3 = 0 ' = U1MODEbits.BRGH =0 ' 0 = standard speed mode - 16 clocks per bit U1MODE.4 = 0 ' logic high is the idle state for the input serial data (default) U1MODE.7 = 0 ' wakeup disabled U1MODE.8 = 0 U1MODE.9 = 0 U1BRG = 119 ' 239 ' voor 120MHz 119 ' voor 60MHz ((60000000 / Hserial_baud) / 16) - 1 ' BRGVAL U1STA.5 = 0 ' no bit8 U1STA.6 = 0 ' U1STAbits.URXISEL = 0 ' receive interrupt mode selection bits U1STA.7 = 0 ' interrupt flag is set when a byte is received U1MODE.15 = 1 '=U1MODEbits.UARTEN = 1 U1MODE.12 = 0 ' disable IrDA IPC2.12 = 0 ' set priority level to 6 for receiver IPC2.13 = 1 IPC2.14 = 1 IEC0.11 = 1 ' enable IRQ for receiver IEC4.1 = 1 ' enable IRQ for error trapping on receiver ' --------------------------- $endif $ifdef Enable_UART_TX U1STA.15 = 0 'interrupt generated when character transferred to tx buffer and buffer is empty U1STA.13 = 0 U1STA.14 = 0 ' Transmit polarity inversion bit (0= idle state is high) U1STA.10 = 1 ' transmit enable bit U1STA.11 = 0 Clear IFS0.12 ' clear transmit interrupt flag Set IEC0.12 ' enable interrupt IPC3.0 = 0 IPC3.1 = 1 IPC3.2 = 1 ' set priority to 5 $endif $ifdef Enable_ADC12bit ' init for ADC system: try 12 bit ADC (500kS/s) 'SMPI1. ADDMAEN = 0 AD1CON1.15 = 1 ' adc module ON AD1CON1.10 = 1 ' select 12-bit mode AD1CON1.9 = 0 ' conversion to right alligned integer 0000 dddd dddd dddd AD1CON1.8 = 0 ' id. AD1CON1.7 = 1 ' auto-convert mode AD1CON1.6 = 1 ' id. AD1CON1.5 = 1 ' id AD1CON1.4 = 0 ' SSRCG AD1CON1.2 = 1 ' sampling immediately after last conversion. SAMP bit it autoset. AD1CON2.15 = 0 ' ref AvDD and AsSS AD1CON2.14 = 0 AD1CON2.13 = 0 AD1CON2.10 = 0 ' no scan ' bits 6-2 = 0 ==> generates interrupt after every sample conversion AD1CON2.1 = 0 ' always fill buffer from the start adres AD1CON2.0 = 0 'use channel input selects for sample MUXA AD1CON3.0 = 0 ' clock derived from system clock AD1CON3.12 = 1 ' 10000 = 16 Tad -autosample time bits AD1CON3.11 = 0 ' / AD1CON3.10 = 0 '/ AD1CON3.9 = 0 ' / AD1CON3.8 = 0 '/ AD1CON3.Byte0 = 16 ' ADCS ADC1 conversion clock select bits (sampling rate) AD1CON4.8 = 0 ' no DMA - results stored in ADC1BUF0 to ADC1BUFF registers AD1CHS0 = 0 ' clear complete register. AN0 is input channel ' now we have to enable the interrupt and find out how to transfer data to an array IEC0.13 = 1 ' enable IRQ 'IPC3 <6:4> set the priority level IFS0.13 = 0 ' clear interrupt flag ' --------------------------------------------------------------------------------- $endif Variables: ' variable declarations: ANSELA = 0 ' make A port digital Dim inByte As Byte Dim IndexIn As Byte ' Pointer to the next empty location in the buffer Dim IndexOut As Byte ' Pointer to the location of the oldest character in the buffer Dim Ringbuffer[256] As Byte ' Array for holding received characters in the uart Dim Outbuffer[265] As Byte ' buffer for midi-output UART Dim OutIdxIn As Byte Dim OutIdxOut As Byte Dim Bytein As Byte ' midi byte read from buffer Dim StBit As Bytein.7 ' highest bit of ByteIn ' midi variables Dim statusbyte As Byte Dim noteUit As Byte ' note off + release value Dim release As Byte Dim noteAan As Byte ' note on + release value Dim velo As Byte Dim notePres As Byte ' note pressure + pressure value Dim pres As Byte Dim Ctrl As Byte ' continuous controller + value Dim value As Byte Dim prog As Byte ' program change + program-byte Dim aft As Byte ' channel aftertouch Dim pblsb As Byte ' pitch bend lsb Dim pbmsb As Byte ' pitch bend msb Dim UseString As Byte ' var. to pass the string to be used for the requested note [0-11] Dim j As Byte Dim k As Byte ' general purpose variable Dim z As Byte Dim st As Byte Dim b1 As Byte Dim b2 As Byte Dim lim As Byte Dim i As Byte Dim CC3 As Byte Dim CC4 As Byte Dim CC7 As Byte ' received value for volume controller Dim CC64 As Byte ' sustain switch Dim CC65 As Byte ' noteoff with release enable controller Dim CC66 As Byte ' global on/off switch Dim Lut As Word ' the compiler does not allow aLUT[n].Highbyte etc... Dim LutSnaar As Lut.HighByte ' the low nibble of the highbyte holds the string to use (0-11) ' the high nibble can be used for transpositions Dim LutMulti As Lut.LowByte ' the lowbyte holds the multiplier setting required (1-64) Dim Tune As Byte Dim BaseNote As Byte ' for transposition required in the upper octave 'declare and dimension all scalars: Dim HammerIndex[128] As Byte ' 24-35 Dim SnaarX[12] As Byte ' if SnaarX[x] = 0 then the string is free ' else: SnaarX[x] = multiplier-value used for playing ' multiplier = CC22 Dim SnaarNote[12] As Byte ' indicates what note the string is sounding ' set to 255 if no note is sounding on that string Dim OldTune[12] As Byte ' last set value for string fine tuning with CC24 Dim cc3Old[12] As Byte ' pwm setting for cc3 Dim cc4Old[12] As Byte ' pwm setting for cc4 Dim CC20[12] As Byte ' basic tuning for the strings Dim CC23[12] As Byte ' drive symmetry controller Dim CC69[12] As Byte ' on/off flags for the string drivers Dim OldVelo[12] As Byte ' to check whether or not cc3 and cc4 have to be recalculated. Dim Multi[12] As Byte ' multiplier values for flageolets used with CC100-CC111 Dim pLUT[92] As Word ' shifted 36. 0-91 for notes 36 to 127 Dim aLUT[92] As Word ' alternative way of playing the note in the index ' HighByte, lownibble = snaarnummer , highnibble transposition ' Lowbyte = multiplier Dim pKOR[92] As Byte ' pitch correction to adapt to inharmonicity Dim aKOR[92] As Byte ' now 36 - 127, dsPIC 11.09.2010 Variable_Inits: Clear Ringbuffer Clear IndexIn ' Clear the buffer internal pointer Clear IndexOut ' Clear the buffer external pointer Clear Outbuffer Clear OutIdxIn Clear OutIdxOut Clear midi_led Clear debug_led Clear loopcnt Low Note0 Low Note1 Low Note2 Low Note3 Low Note4 Low Note5 Low Note6 Low Note7 Low Note8 Low Note9 Low NoteA Low NoteB GoSub Init_Aeio ' send all required initialisation to aeio DelayMS 500 ' added 23.10.2017 GoSub Init_Veloscales ' load lookup for the veloscalings for each output ' also resets all velo counters ' vellsb[x] = 0xFFFF ' velmsb[x] = 0x7FFF 0x7FFF because dwords are signed! ' sofar not used in aeio. All set to 0 GoTo Start_2 ' so we startup with the empiric setting Start_0: GoSub Lookup_Plato_Pitch ' pitch mapping on overtones - prog.0 GoTo MAIN Start_1: GoSub Lookup_Science_Pitch ' prog. 1 GoTo MAIN Start_2: GoSub Lookup_Empiric ' prog. 2 GoTo MAIN Start_3: GoSub Lookup_EQ ' prog. 3 GoTo MAIN ' jump over irq's Interrupt_handling: ' ------------------- Isr- T1Interrupt ' timer1 interrupt Clear IFS0bits_T1IF ' Reset the Timer1 interrupt flag Toggle debug_led ' watchdog EndIsr- ' exit the interrupt Isr- T3Interrupt IFS0bits_T3IF = 0 ' 32-bit value reached (T2/T3 combined) ' this is our main timer! EndIsr- Isr- T4Interrupt Clear IFS1bits_T4IF '16-bit value reached Clear TMR4 Set IEC1bits_T4IE ' re-enable irq EndIsr- Isr- T5Interrupt IFS1bits_T5IF = 0 ' 32-bit value reached if T4/T5 operation ib 32 bits ' 16-bit value reached if operated alone. Clear TMR5 Set IEC1bits_T5IE EndIsr- Isr- U1RXInterrupt ' UART receive IRQ - midi receiver Clear IFS0.11 ' reset UART1 receive irq flag Inc IndexIn ' Move up the buffer index (0-255) Ringbuffer[IndexIn] = U1RXREG ' deze buffer bevat dus alle inkomende midi EndIsr- Isr- U1ErrInterrupt ' this irq is generated on UART1 receive errors ' this interrupt is enabled by setting IEC4.1 ' error handling: Clear IFS4.1 ' clear interrupt flag If U1STA.2 = 1 Then 'Set framing_error_led ' no longer happening Clear U1STA.2 Else 'Clear framing_error_led EndIf If U1STA.1 = 1 Then ' = overrun error 'Set overrun_error_led ' not happening Clear U1STA.1 Else 'Clear overrun_error_led EndIf EndIsr- Isr- U1TXInterrupt ' UART send IRQ IFS0bits_U1TXIF = 0 ' reset UART1 transmit IRQ flag Toggle midi_led ' transmit monitor EndIsr- Isr- AD1Interrupt ' this irq happens after every ADC conversion Clear IFS0.13 ' clear interrupt flag ' Inc DataInIdx ' move up the buffer index ' DataBuffer[DataInIdx] = ADC1BUF0 ' loopt tot ADC1BUFF -so 16 words deep EndIsr- Isr- PWM1Interrupt Clear IFS5.14 EndIsr- Isr- PWM2Interrupt Clear IFS5.15 EndIsr Isr- PWM3Interrupt Clear IFS6.0 EndIsr- GetMidi: If IndexIn <> IndexOut Then Inc IndexOut Bytein = Ringbuffer[IndexOut] Else Set Bytein EndIf Return MAIN: While GoSub GetMidi ' Read data from the serial buffer ' Start the midi parser. Midi_Parse: If Bytein > ProgChange_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 EndIf GoTo Midi_Parse_done 'throw away... EndIf If StBit =1 Then 'should be faster than If Bytein > 127 Then 'status byte received, bit 7 is set Clear statusbyte 'if on another channel, the statusbyte needs a reset Select Bytein 'eqv to Select case ByteIn Case NoteOff_Status statusbyte = Bytein Set noteUit 'reset value. Cannot be 0 !!! Set release '0 is a valid midi note! Case NoteOn_Status statusbyte = Bytein Set noteAan '= 255 Set velo '= 255 Case Keypres_Status statusbyte = Bytein Set notePres Set pres Case Control_Status statusbyte = Bytein Set Ctrl Set value Case ProgChange_Status statusbyte = Bytein Set prog Case Aftertouch_Status statusbyte = Bytein Set aft Case Pitchbend_Status statusbyte = Bytein Set pblsb Set pbmsb EndSelect Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Midi_Parse_done Case NoteOff_Status If noteUit = 255 Then noteUit = Bytein Else release = Bytein 'message complete, so we can do the action... Select noteUit Case > 35 GoSub Aeio_NoteOff 'noteUit is passed to the proc. EndSelect Set noteUit 'reset GoTo Midi_Parse_done EndIf Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then 'here we have to lookup which string was playing the note... 'only then we can release the string and give it free. 'handle dampers If noteAan > 35 Then noteUit = noteAan release = CC65 ' was: velo, this must be a bug, as velo is 0 GoSub Aeio_NoteOff Set noteUit EndIf Set noteAan 'reset !!! GoTo Midi_Parse_done 'jump out Else Select noteAan Case < 24 ' do nothing Set noteAan GoTo Midi_Parse_done Case < 36 'beaters: - mapped on notes 24-35 - this should work already. On HammerIndex[noteAan] GoSub N24, N25, N26, N27, N28, N29, N30, N31, N32, N33, N34, N35 Set noteAan GoTo Midi_Parse_done 'seems required... Case < 127 'we use lookuptable here: for notes 36 to 127 i = noteAan - 36 'apply the offset If pLUT[i] > 0 Then 'check whether the string can play the note Lut = pLUT[i] UseString = LutSnaar & 0x0F 'pLUT.Highbyte[i] 'pLUT[i].Highbyte - syntax error!!! 'Lutsnaar is an alias for the highbyte of Lut 'we need only the low nibble of this highbyte, hence 'the mask If SnaarX[UseString] = 0 Then 'if the string is free SnaarX[UseString] = LutMulti 'pLUT[i].LowByte BaseNote = LutSnaar >> 4 'high nibble 'LutMulti is an alias for the lowbyte of Lut 'SnaarNote[UseString] = noteAan done in play procedure 'Check for pitch correction entry in the lookup: Tune = pKOR[i] Else If aLUT[i] > 0 Then Lut = aLUT[i] 'if it could be played on another string UseString = LutSnaar & 0x0F 'aLUT[i].Highbyte If SnaarX[UseString] = 0 Then 'if the string is free SnaarX[UseString] = LutMulti 'aLUT(i).Lowbyte 'SnaarNote[Usestring] = noteAan BaseNote = LutSnaar >> 4 'pitch correction entry: Tune = aKOR[i] Else noteAan = 255 'cannot be played GoTo Midi_Parse_done EndIf Else noteAan = 255 GoTo Midi_Parse_done 'note cannot be played EndIf EndIf EndIf EndSelect If UseString < 12 Then GoSub Aeio_Play_Note '>=12 should never happen... EndIf Set noteAan 'reset GoTo Midi_Parse_done EndIf Set noteAan EndIf Case Keypres_Status 'implemented on aeio!!! If notePres = 255 Then notePres = Bytein Else pres = Bytein GoSub KeyPres EndIf GoTo Midi_Parse_done 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 Midi_Parse_done Case ProgChange_Status If prog = 255 Then 'single byte message prog = Bytein 'weak coding... GoSub ProgChange EndIf Case Aftertouch_Status ' not implemented If aft = 255 Then aft = Bytein EndIf Case Pitchbend_Status ' not implemented If pblsb = 255 Then pblsb = Bytein Else pbmsb = Bytein EndIf EndSelect EndIf Midi_Parse_done: Midi_OutPut: If OutIdxOut <> OutIdxIn Then ' in dit geval is er een byte te versturen If IFS0bits_U1TXIF = 0 Then ' de TX interrupt moet afgehandeld zijn Inc OutIdxOut U1TXREG = Outbuffer[OutIdxOut] EndIf ' do some pacing: DelayUS 320 ' 320us is the time required to send a midi byte (10 bits) at 31250 Baud. ' apparently the dsPIC's cannot handle neck-to-neck midi. ' this instruction is translated into nop's in the assembler, thus it is not ' using a timer. EndIf ' alternative construction using HSROut: ' make sure HrsOut_Pace is set to 320 ' If OutIdxOut <> OutIdxIn then ' Inc OutIdxOut ' HrsOut OutBuffer[OutIdx] ' endif Toggle loopcnt ' for loopspeed measurement: 1us now ' 22.10.2018: 587kHz met alle taken aan, 588kHz onbelast (zonder pacing!) ' 24.10.2017: 666kHz - 570kHz, with glitches with pacing in serial out. Wend ' ************************************************************************************** ' procedures for midi receiver: KeyPres: 'the note to which the pressure should be applied is passed in NotePres, the value in Pres 'modulate the loudness of playing notes. 'first attempt: 'we have to find the string playing the note for which the volume has to be modulated: For i = 0 To 11 If notePres = SnaarNote[i] Then Break 'jump out of the loop Next If i > 11 Then Return 'error ' i contains now the string number (0-11) If SnaarX[i] > 0 Then 'check whether the string is still playing... 'lim = CC7 Min pres 'set the limit to the smallest of both lim = CC7 If lim > pres Then lim = pres k = CC23[i] << 1 'x 2 gives us 0-254 range z = 254 - k 'complimentary value 'CC3 = k Min lim CC3 = k If CC3 > lim Then CC3 = lim 'CC4 = z Min lim CC4 = z If CC4 > lim Then CC4 = lim 'Uitsturing: If CC3 <> cc3Old[i] Then st = 176 + i 'HRSOut st, 3, CC3 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 3 Inc OutIdxIn Outbuffer[OutIdxIn] = CC3 cc3Old[i] = CC3 EndIf If CC4 <> cc4Old[i] Then st = 176 + i 'HRSOut st, 4, CC4 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 4 Inc OutIdxIn Outbuffer[OutIdxIn] = CC4 cc4Old[i] = CC4 EndIf EndIf Set notePres Return ProgChange: 'used for changing the pitch lookup tables. 'prog. changes should not be send fast!!! ' to be implemented prog. changes: ' 0 = platonic overtone series (does not sound very well) [religionszwang] ' 1 = scientific overtone series, with inharmonicity correction for optimum resonance ' pitches will be out of tune [Scientia vincere tenebras] ' 2 = empirical overtone series, measured out by Kristof Lauwers [earthbound] ' 3 = optimum equal temperament scale tuning [pragmaticism] If prog > 3 Then prog = 3 On prog GoSub Lookup_Plato_Pitch, Lookup_Science_Pitch, Lookup_Empiric, Lookup_EQ Set prog Return Pitchbend: ' not implemented Set pblsb Set pbmsb Return Aftertouch: 'this is the channel aftertouch, affecting any playing note 'not implemented here. Set aft ' reset Return Aeio_NoteOff: 'if two strings are sounding a same note, we will run into a problem here. 'as coded now, always the first note encountered in SnaarNote[] will be released. For k = 0 To 11 If noteUit = SnaarNote[k] Then Break 'jump out of the loop Next 'what if the note is never found??? If k < 12 Then If noteUit < 115 Then st = 128 + k 'HRSOut st, 36, release 'release only if we implement it on the dsPic's 'the dsPIC's take the largest of CC65 and release 'to calculate the damping time. Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 36 ' all boards do as if they play note 36 Inc OutIdxIn Outbuffer[OutIdxIn] = release Else st = 176 + k 'HRSOut st, 123, 0 'in this case we send an all notes off command. Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 123 Inc OutIdxIn Outbuffer[OutIdxIn] = 0 EndIf Set SnaarNote[k] 'give the string free for other notes: Clear SnaarX[k] 'set multiplier to 0, string is free. 'do the LED's: On k GoSub NO0, NO1, NO2, NO3, NO4, NO5, NO6, NO7, NO8, NO9, NOA, NOB 'check sustain flag: if off, we should send the commands to the dampers ' Aeio dsPIC Version 1.1: This is now handled by the dsPICs EndIf Return Aeio_Play_Note: ' called on midinoteON command ' UseString is known, the multiplier is in SnaarX[UseString] ' usestring is 0-11, number of the string. 'following can be left out, to save some time... If CC69[UseString] = 0 Then 'make sure the ebow for that string is enabled... st = 176 + UseString 'HRSOut st, 69, 64 'switch ON of it was off Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 69 Inc OutIdxIn Outbuffer[OutIdxIn] = 64 CC69[UseString] = 64 EndIf '---------------------- 'HRSOut 144+ UseString , 36, velo ' velo not implemented here in dsPIC 'HRSOut 176+ UseString, 22, SnaarX[UseString] 'send multiplier 'try sending as one chunk: st = 144 + UseString 'this is the note-on command. b1 = 176 + UseString b2 = SnaarX[UseString] 'multiplier - CC22 'HRSOut st , 36, velo, (176+ UseString), 22, SnaarX[UseString] If BaseNote = 0 Then 'HRSOut st,36,velo,b1,22,b2 'always note 36, always send multiplier. 'note that the value for velo is irrelevant here, since nothing with it is done by the dsPIC Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 36 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Inc OutIdxIn Outbuffer[OutIdxIn] = b1 Inc OutIdxIn Outbuffer[OutIdxIn] = 22 Inc OutIdxIn Outbuffer[OutIdxIn] = b2 Else Select BaseNote ' values 1-7 transpose the base note an octave up [ implemented only 1-4 ] ' values 8-15 transpoee the base note octaves down [ implemented only 8-9 ] ' this will not be possible, since the dsPICs start at note 36, below this we have hammers... Case 1 'HRSOut st,48,velo,b1,22,b2 'always note 48, always send multiplier. Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 48 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Inc OutIdxIn Outbuffer[OutIdxIn] = b1 Inc OutIdxIn Outbuffer[OutIdxIn] = 22 Inc OutIdxIn Outbuffer[OutIdxIn] = b2 Case 2 'HRSOut st,60,velo,b1,22,b2 'always note 60, always send multiplier. Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 60 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Inc OutIdxIn Outbuffer[OutIdxIn] = b1 Inc OutIdxIn Outbuffer[OutIdxIn] = 22 Inc OutIdxIn Outbuffer[OutIdxIn] = b2 Case 3 'HRSOut st,72,velo,b1,22,b2 'always note 72, always send multiplier. Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 72 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Inc OutIdxIn Outbuffer[OutIdxIn] = b1 Inc OutIdxIn Outbuffer[OutIdxIn] = 22 Inc OutIdxIn Outbuffer[OutIdxIn] = b2 Case 4 'HRSOut st, 84, velo, b1, 22, b2 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 84 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Inc OutIdxIn Outbuffer[OutIdxIn] = b1 Inc OutIdxIn Outbuffer[OutIdxIn] = 22 Inc OutIdxIn Outbuffer[OutIdxIn] = b2 ' CASE 8 ' HRSOut st,24,velo,b1,22,b2 'always note 24, always send multiplier. ' CASE 9 ' HRSOut st,12,velo,b1,22,b2 'always note 12, always send multiplier. EndSelect EndIf If Tune <> OldTune[UseString] Then 'tune is read from lookup also!!! st = 176 + UseString 'HRSOut st, 24, Tune 'send fine tuning if required . controller 24 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = Tune OldTune[UseString] = Tune 'Tune[UseString] EndIf ' If velo <> OldVelo[UseString] Then ' ' velo control: - now symmetric PWM: ' ' calculate the required CC3 - cc4 settings form velo ' ' following tested ok in GMT, but should be recoded for integer math. ' ' CC3[0]= 64 * (velo/127) 'gaan op de PIC nooit echt naar 0 ' ' CC4[0]= (127- 64) * (velo/127) '64 gives us 12.5% duty cycle ' HRSOut (176+ UseString), 3, CC3[UseString] ' HRSOut (176+ usestring), 4, CC4[UseString] ' OldVelo[0] = velo ' EndIf ' ' calculation of the required settings for cc3 and cc4: [ first version] ' x = velo + CC7 'range becomes 0-254 ' k = x >> 1 'divide by 2, so now back to 0-126 ' 'apply symmetry controller cc23: ' 'when cc23 = 64 the drive will be symmetric ' 'when cc23 = 127 , cc3 will become 0 ' 'when cc23 = 0 , cc4 will become 0 ' CC3[UseString] = 127 - CC23[UseString] ' if cc23 = 64, cc3 will be 63 ' ' if cc23 = 127, cc3 will be 0 ' ' if cc23 = 0, cc3 will be 127 ' CC4[UseString] = 127 - CC3[UseString] ' if cc23 = 64, cc4 will be 64 ' ' if cc23 = 127, cc4 will be 127 ' ' if cc23 = 0, cc4 will be 0 ' 'cc3[UseString] = CC3[Usestring] * k 'not possible since cc3 is only a byte... ' 'cc4[Usestring] = CC4[usestring] * k ' 'quick and dirty: ' CC3[UseString] = CC3[UseString] Min k ' CC4[UseString] = CC4[UseString] Min k ' ' first version END '---------------------------------------------------------------------------- ' 'alternative code, whereby CC7 is the upperlimits for the values for CC3 and cc4 ' 'note that here, both coils can be at maximum drive. ' CC3[UseString] = CC7 ' CC4[UseString] = CC7 ' if CC23[Usestring] >= 64 then ' x = CC23[UseString] - 64 '0-63 ' if CC7 > x then ' CC3[Usestring] = CC3[Usestring] - x 'when CC23=64, and CC7= 127, CC3 will be 127 ' else 'when CC23=127, and CC7=127, CC3 will be 63 ' CC3 = 0 ' endif ' else ' x = CC23[UseString] '0-63 ' if CC7>= x then ' CC4[UseString] = CC4[UseString] - x ' else ' CC4 = 0 ' endif ' endif ' 'and now limit to the velo setting: ' CC3[Usestring] = CC3[Usestring] min velo ' CC4[UseString] = CC4[UseString] Min velo ' '-------------------------------------- 'new attempt: [07.09.2010] 'lim = CC7 Min velo 'set the limit to the smallest of both lim = CC7 If lim > velo Then lim = velo k = CC23[UseString] << 1 'x 2 gives us 0-254 range z = 254 - k 'complimentary value 'CC3 = k Min lim 'CC3[UseString] = k Min lim CC3 = k If CC3 > lim Then CC3 = lim 'CC4 = z Min lim 'CC4[UseString] = z Min lim CC4 = z If CC4 > lim Then CC4 = lim OldVelo[UseString] = velo 'Uitsturing: If CC3 <> cc3Old[UseString] Then st = 176 + UseString 'HRSOut st, 3, CC3 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 3 Inc OutIdxIn Outbuffer[OutIdxIn] = CC3 cc3Old[UseString] = CC3 EndIf If CC4 <> cc4Old[UseString] Then st = 176 + UseString 'HRSOut st, 4, CC4 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 4 Inc OutIdxIn Outbuffer[OutIdxIn] = CC4 cc4Old[UseString] = CC4 EndIf SnaarNote[UseString] = noteAan 'required to be able to switch it off 'to finish: light the LED to indicate to the user which string is active: On UseString GoSub NA0, NA1, NA2, NA3, NA4, NA5, NA6, NA7, NA8, NA9, NAA, NAB Set noteAan 'reset Return 'NOTE-OFF procedures, called with the On idx Gosub... construction: 'In Aeio this only controls the LED display on the parser PC board. NO0: Low Note0 Return NO1: Low Note1 Return NO2: Low Note2 Return NO3: Low Note3 Return NO4: Low Note4 Return NO5: Low Note5 Return NO6: Low Note6 Return NO7: Low Note7 Return NO8: Low Note8 Return NO9: Low Note9 Return NOA: Low NoteA Return NOB: Low NoteB Return '-------------------------------------- 'here we have all 16 note-ON procedures: 'in Aeio, this only switches on the LED's indicating string busyness. 'we need only 12 procs. NA0: ' called with On idx Gosub from the main loop. High Note0 'this should always happen... Return NA1: High Note1 Return NA2: High Note2 Return NA3: High Note3 Return NA4: High Note4 Return NA5: High Note5 Return NA6: High Note6 Return NA7: High Note7 Return NA8: High Note8 Return NA9: High Note9 Return NAA: High NoteA Return NAB: High NoteB Return Controller: ' adapted to buffered midi-out 22/10/2017 Select Ctrl Case 7 'master volume controller, sets max. energy to ebows. (ceil for velo) CC7 = value 'modulate the loudness of playing notes. 'first attempt: [ this contradicts the use of velo as a pulse exciter of course...] For i = 0 To 11 If SnaarX[i] > 0 Then 'check whether the string is playing... 'lim = CC7 Min OldVelo[i] 'set the limit to the smallest of both lim = CC7 If lim > OldVelo[i] Then lim = OldVelo[i] k = CC23[i] << 1 'x 2 gives us 0-254 range z = 254 - k 'complimentary value 'CC3 = k Min lim CC3 = k If CC3 > lim Then CC3 = lim 'CC4 = z Min lim CC4 = z If CC4 > lim Then CC4 = lim 'Uitsturing: If CC3 <> cc3Old[i] Then st = 176 + i 'HRSOut st, 3, CC3 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 3 Inc OutIdxIn Outbuffer[OutIdxIn] = CC3 cc3Old[i] = CC3 EndIf If CC4 <> cc4Old[i] Then st = 176 + i 'HRSOut st, 4, CC4 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 4 Inc OutIdxIn Outbuffer[OutIdxIn] = CC4 cc4Old[i] = CC4 EndIf EndIf Next i GoTo Ctrl_Parse_End Case 23 'this controller sets the symmetry for all the ebow drivers 'on start-up the values are preset to 64 'changes of this controller will only affect the next note playing! For i = 0 To 11 CC23[i] = value 'to set the values individually we need 12 separate controllers Next i GoTo Ctrl_Parse_End Case 30 To 41 CC23[Ctrl - 30] = value 'separate controllers for each string 'a change of these controllers should be applied whilst a note is playing. 'to be done. GoTo Ctrl_Parse_End Case 50 To 61 'can be used to shift the basic tuning of čach string 'or in fact, any interval, if users know what they are doing... CC20[Ctrl - 50] = value st = 176 + (Ctrl - 50) 'HRSOut st, 20, value Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 20 Inc OutIdxIn Outbuffer[OutIdxIn] = value GoTo Ctrl_Parse_End Case 64 'sustain on/off If value = 0 Then CC64 = 0 'damping is used Else CC64 = 64 'no damping after notes EndIf 'if sustain is > 0 we disable the dampers 'if sustain is = 0 we enable the dampers For k = 0 To 11 st = 176 + k 'HRSOut st, 64, CC64 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 64 Inc OutIdxIn Outbuffer[OutIdxIn] = CC64 Next k GoTo Ctrl_Parse_End Case 65 'enable or disable note-off with release 'if note off with release is not used, this controller is used 'to control the duration of the damping after a note off. 'This will only work if CC64 = 0 of course. CC65 = value For k = 0 To 11 st = 176 + k 'HRSOut st, 65, CC65 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 65 Inc OutIdxIn Outbuffer[OutIdxIn] = CC65 Next k GoTo Ctrl_Parse_End Case 66 'on/off for robot If value = 0 Then GoSub AllNotesOff Else For k = 0 To 11 st = 176 + k 'HRSOut st, 69, 64 'ebows enabled. Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 69 Inc OutIdxIn Outbuffer[OutIdxIn] = 64 CC69[k] = 64 Next k EndIf GoTo Ctrl_Parse_End Case 80 To 91 'can be used to fine tune the basic frequency 'OldTune[Ctrl - 80] = value st = 176 + (Ctrl - 80) 'HRSOut st, 24, value 'the dsPICs use CC24 for fine tuning 'now bipolar. 2 cent resolution, mid position = 64 'means no tuning change. Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = value OldTune[Ctrl-80] = value 'so it will be reset when the next note is played again! GoTo Ctrl_Parse_End Case 100 To 111 'can be used to manually set the multiplier value for a sounding note k = Ctrl - 100 'string number If SnaarX[k] > 0 Then 'the string must be playing!!! If value > 0 Then If value < 65 Then Multi[k] = value 'must be 1-64 st = 176 + k 'HRSOut st, 22, value 'CC22 is the multiplier controller Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 22 Inc OutIdxIn Outbuffer[OutIdxIn] = value SnaarX[k] = value 'could be dangerous. GoTo Ctrl_Parse_End EndIf EndIf EndIf GoTo Ctrl_Parse_End Case 123 GoSub AllNotesOff EndSelect Ctrl_Parse_End: Ctrl = 255 'mandatory reset Return AllNotesOff: ' send as a single chunk: ' could it be that this also resets the tuning with CC20??? ' HRSOut 176, 69,0 , 177, 69, 0, 178, 69, 0 , 179, 69, 0, 180, 69, 0, 181, 69,0, 182, 69, 0, 183, 69, 0, 184, 69, 0, 185, 69, 0, 186, 69, 0, 187, 69, 0 ' HRSOut 176, 123,0 , 177, 123, 0, 178, 123, 0 , 179, 123, 0, 180, 123, 0, 181, 123,0, 182, 123, 0, 183, 123, 0, 184, 123, 0, 185, 123, 0, 186, 123, 0, 187, 123, 0 For k = 176 To 187 Inc OutIdxIn Outbuffer[OutIdxIn] = k Inc OutIdxIn Outbuffer[OutIdxIn] = 123 Inc OutIdxIn Outbuffer[OutIdxIn] = 0 Next k Low Note0 Low Note1 Low Note2 Low Note3 Low Note4 Low Note5 Low Note6 Low Note7 Low Note8 Low Note9 Low NoteA Low NoteB For k = 0 To 11 SnaarX[k] = 0 'make all strings free ' CC69[k] = 0 'not required Set SnaarNote[k] Next k Return Init_Veloscales: For i = 0 To 127 Set HammerIndex[i] Next i For i = 24 To 35 HammerIndex[i] = i - 24 'these notes are hammers - 0-11 Next i Return Init_Aeio: 'this will take about 144 ms For k = 0 To 11 st = 176 + k 'HRSOut st, 69, 64 'on/off controller CC69[k] = 64 'switch all strings ON CC23[k] = 64 'set bow symmetry drive controllers to 50/50 'this controller should not be sent to the dsPICs ' b2 = 52 + k 'HRSOut st, 20, b2, 22, 1 'set tuning right for 36-47 - CC20 'since it sounds better an octave higher, we changed this to: b2 = 64 + k 'it should be 64 + k, to get the tuning right for notes 36 ... CC20[k] = b2 'basic tuning 'updated 11.09.2010 in the dsPICS 'set flag. multiplier to 1 - CC22 OldTune[k] = 64 'HRSOut st, 24, 0 'set fine tune to center - CC24 cc3Old[k] = 64 'HRSOut st, 3, 64 '12.5% PWM A - CC3 cc4Old[k] = 64 'HRSOut st , 4, 64 '12.5% PWM B - CC4 SnaarX[k] = 0 'make string free for use ' sending all in one chunk: (midi running mode) 'HRSOut st, 69, 64, 20, b2, 22, 1, 24, 64, 3, 64 , 4, 64 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 69 Inc OutIdxIn Outbuffer[OutIdxIn] = 64 Inc OutIdxIn Outbuffer[OutIdxIn] = 20 ' CC20 - tuning Inc OutIdxIn Outbuffer[OutIdxIn] = b2 Inc OutIdxIn Outbuffer[OutIdxIn] = 22 ' CC22 Inc OutIdxIn Outbuffer[OutIdxIn] = 1 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 ' CC24 Inc OutIdxIn Outbuffer[OutIdxIn] = 64 Inc OutIdxIn Outbuffer[OutIdxIn] = 3 ' CC3 Inc OutIdxIn Outbuffer[OutIdxIn] = 64 CC3 = 64 Inc OutIdxIn Outbuffer[OutIdxIn] = 4 ' CC4 Inc OutIdxIn Outbuffer[OutIdxIn] = 64 CC4 = 64 CC64 = 0 '0 = enable the damper mechanism (sustain = OFF) CC65 = 15 'release value for the damping. 'should also be send to the dsPIC's on init!!! 'with value 127, the damper will stay against the string as long as 'the string is not playing. 'with value 126 it will release after some 2 seconds 'HRSOut st, 64, CC64, 65, CC65 Inc OutIdxIn Outbuffer[OutIdxIn] = st Inc OutIdxIn Outbuffer[OutIdxIn] = 64 ' CC64 Inc OutIdxIn Outbuffer[OutIdxIn] = CC64 Inc OutIdxIn Outbuffer[OutIdxIn] = 65 ' CC65 Inc OutIdxIn Outbuffer[OutIdxIn] = CC65 Next k CC7 = 64 'default volume (not yet individualized) Return ' midi commands for the hammer=exciters: - this works fine. N24: 'HRSOut 144, 24, velo 'send pulse command to the excitation hammers string0 Inc OutIdxIn Outbuffer[OutIdxIn] = 144 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N25: 'HRSOut 145, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 145 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N26: 'HRSOut 146, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 146 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N27: 'HRSOut 147, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 147 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N28: 'HRSOut 148, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 148 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N29: 'HRSOut 149, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 149 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N30: 'HRSOut 150,24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 150 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N31: 'HRSOut 151, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 151 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N32: 'HRSOut 152, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 152 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N33: 'HRSOut 153, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 153 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N34: 'HRSOut 154, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 154 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return N35: 'HRSOut 155, 24, velo Inc OutIdxIn Outbuffer[OutIdxIn] = 155 Inc OutIdxIn Outbuffer[OutIdxIn] = 24 Inc OutIdxIn Outbuffer[OutIdxIn] = velo Return Lookup_Plato_Pitch: 'alternate lookups according to physical reality to be worked out. 'selection of lookups can happen with program change commands 'offset 36 !!! 'pLUT[0] = 0-91 for notes 36 to 127 For k = 0 To 91 pKOR[k] = 64 'default to no pitch correction, or center value for CC24 aKOR[k] = 64 Next For k = 0 To 18 : aLUT[k] = 0 : Next pLUT[0] = 0x0001 'highbyte = string number, lowbyte= multiplier pLUT[1] = 0x0101 pLUT[2] = 0x0201 pLUT[3] = 0x0301 pLUT[4] = 0x0401 pLUT[5] = 0x0501 pLUT[6] = 0x0601 pLUT[7] = 0x0701 pLUT[8] = 0x0801 pLUT[9] = 0x0901 pLUT[10] = 0x0A01 pLUT[11] = 0x0B01 pLUT[12] = 0x0002 'note 48 pLUT[13] = 0x0102 pLUT[14] = 0x0202 'note 50 pLUT[15] = 0x0302 '51 pLUT[16] = 0x0402 '52 pLUT[17] = 0x0502 '53 pLUT[18] = 0x0602 '54 pLUT[19] = 0x0702 '55 first note that can be played two ways aLUT[19] = 0x0003 pLUT[20] = 0x0802 : aLUT[20] = 0x0103 pLUT[21] = 0x0902 : aLUT[21] = 0x0203 pLUT[22] = 0x0A02 : aLUT[22] = 0x0303 pLUT[23] = 0x0B02 : aLUT[23] = 0x0403 pLUT[24] = 0x0004 : aLUT[24] = 0x0503 'note 60 pLUT[25] = 0x0104 : aLUT[25] = 0x0603 pLUT[26] = 0x0204 : aLUT[26] = 0x0703 pLUT[27] = 0x0304 : aLUT[27] = 0x0803 pLUT[28] = 0x0404 : aLUT[28] = 0x0903 pLUT[29] = 0x0504 : aLUT[29] = 0x0A03 pLUT[30] = 0x0604 : aLUT[30] = 0x0B03 'note 66 pLUT[31] = 0x0704 : aLUT[31] = 0x0006 pLUT[32] = 0x0804 : aLUT[32] = 0x0106 'note 68 pLUT[33] = 0x0904 : aLUT[33] = 0x0206 pLUT[34] = 0x0A04 : aLUT[34] = 0x0306 'note 70 pLUT[35] = 0x0B04 : aLUT[35] = 0x0406 pLUT[36] = 0x0008 : aLUT[36] = 0x0506 'note 72 pLUT[37] = 0x0108 : aLUT[37] = 0x0606 pLUT[38] = 0x0208 : aLUT[38] = 0x0706 pLUT[39] = 0x0308 : aLUT[39] = 0x0806 pLUT[40] = 0x0408 : aLUT[40] = 0x0906 'note 76 pLUT[41] = 0x0508 : aLUT[41] = 0x0A06 pLUT[42] = 0x0608 : aLUT[42] = 0x0B06 pLUT[43] = 0x0708 : aLUT[43] = 0x000C 'note 79 pLUT[44] = 0x0808 : aLUT[44] = 0x010C pLUT[45] = 0x0908 : aLUT[45] = 0x020C '81 pLUT[46] = 0x0A08 : aLUT[46] = 0x030C '82 pLUT[47] = 0x0B08 : aLUT[47] = 0x040C pLUT[48] = 0x0010 : aLUT[48] = 0x050C '84 pLUT[49] = 0x0110 : aLUT[49] = 0x060C pLUT[50] = 0x0210 : aLUT[50] = 0x070C pLUT[51] = 0x0310 : aLUT[51] = 0x080C pLUT[52] = 0x0410 : aLUT[52] = 0x090C pLUT[53] = 0x0510 : aLUT[53] = 0x0A0C '89 pLUT[54] = 0x0610 : aLUT[54] = 0x0B0C pLUT[55] = 0x0710 : aLUT[55] = 0x0018 '91 - multiplier = 24 = 0x18 pLUT[56] = 0x0810 : aLUT[56] = 0x0118 pLUT[57] = 0x0910 : aLUT[57] = 0x0218 pLUT[58] = 0x0A10 : aLUT[58] = 0x0318 pLUT[59] = 0x0B10 : aLUT[59] = 0x0418 '95 pLUT[60] = 0x0020 : aLUT[60] = 0x0518 '0x20 = 32,the max. value for the multiplier now pLUT[61] = 0x0120 : aLUT[61] = 0x0618 pLUT[62] = 0x0220 : aLUT[62] = 0x0718 pLUT[63] = 0x0320 : aLUT[63] = 0x0818 '99 pLUT[64] = 0x0420 : aLUT[64] = 0x0918 '100 pLUT[65] = 0x0520 : aLUT[65] = 0x0A18 pLUT[66] = 0x0620 : aLUT[66] = 0x0B18 '102 pLUT[67] = 0x0720 : aLUT[67] = 0x0030 ' exceeding multiplier 32 !!!0x0530 (x48 required) pLUT[68] = 0x0820 : aLUT[68] = 0x0130 'to be checked with new ds firmware pLUT[69] = 0x0920 : aLUT[69] = 0x0230 pLUT[70] = 0x0A20 : aLUT[70] = 0x0330 '106 pLUT[71] = 0x0B20 : aLUT[71] = 0x0430 '107 - highest possible note in dsPIC version 1 pLUT[72] = 0x0040 : aLUT[72] = 0x0530 pLUT[73] = 0x0140 : aLUT[73] = 0x0630 pLUT[74] = 0x0240 : aLUT[74] = 0x0730 pLUT[75] = 0x0340 : aLUT[75] = 0x0830 pLUT[76] = 0x0440 : aLUT[76] = 0x0930 '112 pLUT[77] = 0x0540 : aLUT[77] = 0x0A30 pLUT[78] = 0x0640 : aLUT[78] = 0x0B30 '114 pLUT[79] = 0x0740 : aLUT[79] = 0x1030 '115 alut with fundamental an octave up (high nibble = 1) pLUT[80] = 0x0840 : aLUT[80] = 0x1130 pLUT[81] = 0x0940 : aLUT[81] = 0x1230 pLUT[82] = 0x0A40 : aLUT[82] = 0x1330 pLUT[83] = 0x0B40 : aLUT[83] = 0x1430 '119 'for the range up to 127 we have to tune the fundamental an octave up. 'so, we set the highest nibble to 1 pLUT[84] = 0x1040 : aLUT[84] = 0x1530 '120 pLUT[85] = 0x1140 : aLUT[85] = 0x1630 pLUT[86] = 0x1240 : aLUT[86] = 0x1730 pLUT[87] = 0x1340 : aLUT[87] = 0x1830 '123 pLUT[88] = 0x1440 : aLUT[88] = 0x1930 pLUT[89] = 0x1540 : aLUT[89] = 0x1A30 pLUT[90] = 0x1640 : aLUT[90] = 0x1B30 '126 pLUT[91] = 0x1740 : aLUT[91] = 0x2030 '127 - this is the absolute upper limit for Midi 'note: to implement an octave upwards, we use the high nibble of the pLUT[] values ' to get the string we have to mask out the high nibble with AND 0x0F ' to get the new fundamental tuning we mask with 0xF0 Return Lookup_Science_Pitch: 'This is the loopup table after mathematical analysis based on the 2nd degree equation 'pLUT[0] = 0-91 for notes 36 to 127 For k = 0 To 91 pKOR[k] = 64 'default to no correction or CC24 in central position aKOR[k] = 64 Next For k = 0 To 18 aLUT[k] = 0 Next pLUT[0] = 0x0001 : pKOR[0] = 64 'pLUT: highbyte, lownibble = string number, lowbyte= multiplier (cc22) ' highbyte, highnibble = basenote transposition: ' 1 = octave up, 2= 2 octaves up, 3= 3 octaves up ' 8 = octave down, 9 = 2 octaves down. 'pKOR: pitch correction required (64 = no correction), range 0-127 pLUT[1] = 0x0101 : pKOR[1] = 64 pLUT[2] = 0x0201 : pKOR[2] = 64 pLUT[3] = 0x0301 : pKOR[3] = 64 pLUT[4] = 0x0401 : pKOR[4] = 64 pLUT[5] = 0x0501 : pKOR[5] = 64 pLUT[6] = 0x0601 : pKOR[6] = 64 pLUT[7] = 0x0701 : pKOR[7] = 64 pLUT[8] = 0x0801 : pKOR[8] = 64 pLUT[9] = 0x0901 : pKOR[9] = 64 pLUT[10] = 0x0A01 : pKOR[10] = 64 pLUT[11] = 0x0B01 : pKOR[11] = 64 pLUT[12] = 0x0002 : pKOR[12] = 62 '48 x pLUT[13] = 0x0102 : pKOR[13] = 64 '49 x pLUT[14] = 0x0202 : pKOR[14] = 64 '50 x pLUT[15] = 0x0302 : pKOR[15] = 60 '51 x pLUT[16] = 0x0402 : pKOR[16] = 65 '52 x pLUT[17] = 0x0502 : pKOR[17] = 67 '53 x pLUT[18] = 0x0602 : pKOR[18] = 66 '54 x pLUT[19] = 0x0702 : pKOR[19] = 63 : aLUT[19] = 0x0003 : aKOR[19] = 66 '55 x x pLUT[20] = 0x0802 : pKOR[20] = 66 : aLUT[20] = 0x0103 : aKOR[20] = 70 '56 x x pLUT[21] = 0x0902 : pKOR[21] = 65 : aLUT[21] = 0x0203 : aKOR[21] = 70 '57 x x pLUT[22] = 0x0A02 : pKOR[22] = 71 : aLUT[22] = 0x0303 : aKOR[22] = 67 '58 x x pLUT[23] = 0x0B02 : pKOR[23] = 73 : aLUT[23] = 0x0403 : aKOR[23] = 73 '59 x x pLUT[24] = 0x0004 : pKOR[24] = 65 : aLUT[24] = 0x0503 : aKOR[24] = 76 '60 x x pLUT[25] = 0x0104 : pKOR[25] = 76 : aLUT[25] = 0x0603 : aKOR[25] = 76 '61 x x pLUT[26] = 0x0204 : pKOR[26] = 78 : aLUT[26] = 0x0703 : aKOR[26] = 74 '62 x x pLUT[27] = 0x0304 : pKOR[27] = 75 : aLUT[27] = 0 : aKOR[27] = 64 '63 x pLUT[28] = 0x0404 : pKOR[28] = 83 : aLUT[28] = 0 : aKOR[28] = 64 '64 x pLUT[29] = 0x0504 : pKOR[29] = 85 : aLUT[29] = 0 : aKOR[29] = 64 '65 x pLUT[30] = 0x0604 : pKOR[30] = 88 : aLUT[30] = 0 : aKOR[30] = 64 '66 x pLUT[31] = 0x0704 : pKOR[31] = 86 : aLUT[31] = 0 : aKOR[31] = 64 '67 x pLUT[32] = 0x0804 : pKOR[32] = 92 : aLUT[32] = 0 : aKOR[32] = 64 '68 x pLUT[33] = 0x0904 : pKOR[33] = 93 : aLUT[33] = 0 : aKOR[33] = 64 '69 x pLUT[34] = 0x0007 : pKOR[34] = 85 : aLUT[34] = 0 : aKOR[34] = 64 '70 x pLUT[35] = 0x0A04 : pKOR[35] = 44 : aLUT[35] = 0x0605 : aKOR[35] = 45 '71 x x pLUT[36] = 0x0B04 : pKOR[36] = 59 : aLUT[36] = 0 : aKOR[36] = 59 '72 x pLUT[37] = 0x0506 : pKOR[37] = 65 : aLUT[37] = 0x0008 : aKOR[37] = 63 '73 x x pLUT[38] = 0x0905 : pKOR[38] = 66 : aLUT[38] = 0x0606 : aKOR[38] = 70 '74 x x pLUT[39] = 0x0A05 : pKOR[39] = 69 : aLUT[39] = 0x0009 : aKOR[39] = 78 '75 x x pLUT[40] = 0x0507 : pKOR[40] = 67 : aLUT[40] = 0x0906 : aKOR[40] = 64 '76 x pLUT[41] = 0x0508 : pKOR[41] = 64 : aLUT[41] = 0x0A06 : aKOR[41] = 64 pLUT[42] = 0x0608 : pKOR[42] = 64 : aLUT[42] = 0x0B06 : aKOR[42] = 64 pLUT[43] = 0x0708 : pKOR[43] = 64 : aLUT[43] = 0x000C : aKOR[43] = 64 'note 79 pLUT[44] = 0x0409 : pKOR[44] = 64 : aLUT[44] = 0x010C : aKOR[44] = 64 '80 x pLUT[45] = 0x0708 : pKOR[45] = 68 : aLUT[45] = 0x030A : aKOR[45] = 60 '81 x x pLUT[46] = 0x0A07 : pKOR[46] = 65 : aLUT[46] = 0x030C : aKOR[46] = 64 '82 x pLUT[47] = 0x000D : pKOR[47] = 60 : aLUT[47] = 0x030B : aKOR[47] = 63 '83 x x pLUT[48] = 0x0010 : pKOR[48] = 64 : aLUT[48] = 0x050C : aKOR[48] = 64 '84 pLUT[49] = 0x0809 : pKOR[49] = 63 : aLUT[49] = 0x030C : aKOR[49] = 60 '85 x x pLUT[50] = 0x0710 : pKOR[50] = 64 : aLUT[50] = 0x070C : aKOR[50] = 64 '86 x pLUT[51] = 0x0310 : pKOR[51] = 64 : aLUT[51] = 0x080C : aKOR[51] = 64 pLUT[52] = 0x0410 : pKOR[52] = 64 : aLUT[52] = 0x090C : aKOR[52] = 64 pLUT[53] = 0x0011 : pKOR[53] = 63 : aLUT[53] = 0x060C : aKOR[53] = 64 '89 x x kan ook op snaar 1 pLUT[54] = 0x040E : pKOR[54] = 61 : aLUT[54] = 0x030F : aKOR[54] = 70 '90 x x pLUT[55] = 0x060D : pKOR[55] = 61 : aLUT[55] = 0x0018 : aKOR[55] = 64 '91 x pLUT[56] = 0x0810 : pKOR[56] = 64 : aLUT[56] = 0x0118 : aKOR[56] = 64 pLUT[57] = 0x050F : pKOR[57] = 68 : aLUT[57] = 0x0014 : aKOR[57] = 64 '93 x x pLUT[58] = 0x0A10 : pKOR[58] = 64 : aLUT[58] = 0x0318 : aKOR[58] = 64 pLUT[59] = 0x0B10 : pKOR[59] = 64 : aLUT[59] = 0x0418 : aKOR[59] = 64 '95 pLUT[60] = 0x070F : pKOR[60] = 60 : aLUT[60] = 0x0313 : aKOR[60] = 67 '96 x x kan ook op snaar 2 pLUT[61] = 0x0116 : pKOR[61] = 64 : aLUT[61] = 0x0618 : aKOR[61] = 64 '97 x pLUT[62] = 0x0117 : pKOR[62] = 73 : aLUT[62] = 0x0718 : aKOR[62] = 64 '98 x pLUT[63] = 0x0418 : pKOR[63] = 68 : aLUT[63] = 0x0818 : aKOR[63] = 64 '99 x x pLUT[64] = 0x0316 : pKOR[64] = 64 : aLUT[64] = 0x0018 : aKOR[64] = 60 '100 x x pLUT[65] = 0x001B : pKOR[65] = 62 : aLUT[65] = 0x0910 : aKOR[65] = 63 '101 x x kan op snaar 0 en 9 x x 'ook op 8 en 2 pLUT[66] = 0x0515 : pKOR[66] = 66 : aLUT[66] = 0x0219 : aKOR[66] = 65 '102 x x pLUT[67] = 0x0417 : pKOR[67] = 62 : aLUT[67] = 0x021A : aKOR[67] = 71 '103 x x pLUT[68] = 0x0813 : pKOR[68] = 65 : aLUT[68] = 0x001E : aKOR[68] = 60 '104 x x pLUT[69] = 0x0616 : pKOR[69] = 63 : aLUT[69] = 0x0230 : aKOR[69] = 64 '105 x pLUT[70] = 0x0A20 : pKOR[70] = 64 : aLUT[70] = 0x0330 : aKOR[70] = 64 '106 x pLUT[71] = 0x0815 : pKOR[71] = 62 : aLUT[71] = 0x0519 : aKOR[71] = 67 '107 x x pLUT[72] = 0x0040 : pKOR[72] = 64 : aLUT[72] = 0x0530 : aKOR[72] = 64 '108 pLUT[73] = 0x031E : pKOR[73] = 61 : aLUT[73] = 0x0630 : aKOR[73] = 64 '109 x pLUT[74] = 0x0916 : pKOR[74] = 74 : aLUT[74] = 0x061A : aKOR[74] = 60 '110 x x kan ook op snaar 3 pLUT[75] = 0x0818 : pKOR[75] = 64 : aLUT[75] = 0x061B : aKOR[75] = 65 '111 x x pLUT[76] = 0x0440 : pKOR[76] = 64 : aLUT[76] = 0x061C : aKOR[76] = 72 '112 - x pLUT[77] = 0x0540 : pKOR[77] = 64 : aLUT[77] = 0x0A30 : aKOR[77] = 64 pLUT[78] = 0x0919 : pKOR[78] = 69 : aLUT[78] = 0x0B30 : aKOR[78] = 64 '114 x pLUT[79] = 0x0B17 : pKOR[79] = 66 : aLUT[79] = 0x1030 : aKOR[79] = 64 '115 pLUT[80] = 0x071E : pKOR[80] = 64 : aLUT[80] = 0x1130 : aKOR[80] = 64 '116 x pLUT[81] = 0x0A1C : pKOR[81] = 66 : aLUT[81] = 0x071F : aKOR[81] = 65 '117 x x pLUT[82] = 0x081E : pKOR[82] = 64 : aLUT[82] = 0x0720 : aKOR[82] = 65 '118 x x pLUT[83] = 0x0B40 : pKOR[83] = 59 : aLUT[83] = 0x1430 : aKOR[83] = 64 '119 x 'for the range up to 127 we may have to tune the fundamental an octave up. pLUT[84] = 0x0B4D : pKOR[84] = 71 : aLUT[84] = 0x1530 : aKOR[84] = 64 '120 pLUT[85] = 0x1140 : pKOR[85] = 64 : aLUT[85] = 0x1630 : aKOR[85] = 64 pLUT[86] = 0x0920 : pKOR[86] = 59 : aLUT[86] = 0x1730 : aKOR[86] = 64 '122 x pLUT[87] = 0x1340 : pKOR[87] = 64 : aLUT[87] = 0x1830 : aKOR[87] = 64 '123 pLUT[88] = 0x1440 : pKOR[88] = 64 : aLUT[88] = 0x1930 : aKOR[88] = 64 pLUT[89] = 0x1540 : pKOR[89] = 64 : aLUT[89] = 0x1A30 : aKOR[89] = 64 pLUT[90] = 0x1640 : pKOR[90] = 64 : aLUT[90] = 0x1B30 : aKOR[90] = 64 '126 pLUT[91] = 0x1740 : pKOR[91] = 64 : aLUT[91] = 0x2030 : aKOR[91] = 64 '127 - this is the absolute upper limit. ' add here pKor and aKOR , with the values for the frequency corrector to apply Return Lookup_Empiric: ' data filled in after empirical measurement by Kristof Lauwers ' lookup table for Aeio based on empirical data ' overtones that are too weak as well as pitches deviating more then 25 cent of the wanted pitch are discarded ' (which means a lot of notes can only be played in one way - we might consider using a bigger tolerance) ' from note 95 (pLUT[59]) on we use theoretical values, as our measurements didn't go that high ' (and pitches that high, generally don't sound good anymore) ' ' pLUT[0] = 0-91 for notes 36 to 127 For k = 0 To 91 pKOR[k] = 64 'default to no correction or CC24 in central position aKOR[k] = 64 aLUT[k] = 0 'delete previous entries if we do prog.change. pLUT[k] = 0 Next pLUT[0] = 0x0001 : pKOR[0] = 64 pLUT[1] = 0x0101 : pKOR[1] = 64 pLUT[2] = 0x0201 : pKOR[2] = 64 pLUT[3] = 0x0301 : pKOR[3] = 64 pLUT[4] = 0x0401 : pKOR[4] = 64 pLUT[5] = 0x0501 : pKOR[5] = 64 pLUT[6] = 0x0601 : pKOR[6] = 64 pLUT[7] = 0x0701 : pKOR[7] = 64 pLUT[8] = 0x0801 : pKOR[8] = 64 pLUT[9] = 0x0901 : pKOR[9] = 64 pLUT[10] = 0x0A01 : pKOR[10] = 64 pLUT[11] = 0x0B01 : pKOR[11] = 64 pLUT[12] = 0x0002 : pKOR[12] = 66 ' 48 - actual pitches 48.04 pLUT[13] = 0x0102 : pKOR[13] = 68 ' 49 - actual pitches 49.08 pLUT[14] = 0x0202 : pKOR[14] = 63 ' 50 - actual pitches 49.98 pLUT[15] = 0x0302 : pKOR[15] = 67 ' 51 - actual pitches 51.06 pLUT[16] = 0x0402 : pKOR[16] = 30 ' 52 - actual pitches 51.32 pLUT[17] = 0x0502 : pKOR[17] = 54 ' 53 - actual pitches 52.8 pLUT[18] = 0x0602 : pKOR[18] = 49 ' 54 - actual pitches 53.7 pLUT[19] = 0x0702 : pKOR[19] = 66 : aLUT[19] = 0x0003 : aKOR[19] = 72 ' 55 - actual pitches 55.04 55.1796 pLUT[20] = 0x0802 : pKOR[20] = 62 : aLUT[20] = 0x0103 : aKOR[20] = 74 ' 56 - actual pitches 55.96 56.2196 pLUT[21] = 0x0902 : pKOR[21] = 60 ' 57 - actual pitches 56.92 pLUT[22] = 0x0A02 : pKOR[22] = 66 : aLUT[22] = 0x0303 : aKOR[22] = 53 ' 58 - actual pitches 58.04 57.7996 pLUT[23] = 0x0B02 : pKOR[23] = 72 ' 59 - actual pitches 59.16 pLUT[24] = 0x0503 : pKOR[24] = 69 : aLUT[24] = 0x0004 : aKOR[24] = 71 ' 60 - actual pitches 60.1196 60.14 pLUT[25] = 0x0104 : pKOR[25] = 76 ' 61 - actual pitches 61.24 pLUT[26] = 0x0703 : pKOR[26] = 75 ' 62 - actual pitches 62.2396 pLUT[27] = 0x0803 : pKOR[27] = 64 : aLUT[27] = 0x0304 : aKOR[27] = 68 ' 63 - actual pitches 63.0196 63.08 pLUT[28] = 0x0903 : pKOR[28] = 60 : aLUT[28] = 0x0005 : aKOR[28] = 78 ' 64 - actual pitches 63.9395 64.1431 pLUT[29] = 0x0105 : pKOR[29] = 74 ' 65 - actual pitches 65.0631 pLUT[30] = 0x0B03 : pKOR[30] = 66 : aLUT[30] = 0x0604 : aKOR[30] = 76 ' 66 - actual pitches 66.0595 66.24 pLUT[31] = 0x0305 : pKOR[31] = 72 ' 67 - actual pitches 67.0231 pLUT[32] = 0x0804 : pKOR[32] = 74 ' 68 - actual pitches 68.2 pLUT[33] = 0x0206 : pKOR[33] = 55 ' 69 - actual pitches 68.8395 pLUT[34] = 0x0605 : pKOR[34] = 82 ' 70 - actual pitches 70.2231 pLUT[35] = 0x0406 : pKOR[35] = 71 ' 71 - actual pitches 71.1596 pLUT[36] = 0x0008 : pKOR[36] = 70 ' 72 - actual pitches 72.12 pLUT[37] = 0x0108 : pKOR[37] = 58 : aLUT[37] = 0x0009 : aKOR[37] = 21 ' 73 - actual pitches 72.88 73.1791 pLUT[38] = 0x0407 : pKOR[38] = 86 ' 74 - actual pitches 74.1283 pLUT[39] = 0x0806 : pKOR[39] = 52 ' 75 - actual pitches 74.7795 pLUT[40] = 0x0508 : pKOR[40] = 9 : aLUT[40] = 0x0308 : aKOR[40] = 107 ' 76 - actual pitches 75.9 75.86 pLUT[41] = 0x0408 : pKOR[41] = 113 : aLUT[41] = 0x020A : aKOR[41] = 33 ' 77 - actual pitches 76.98 77.2431 pLUT[42] = 0x0A06 : pKOR[42] = 92 ' 78 - actual pitches 77.5795 pLUT[43] = 0x040A : pKOR[43] = 27 : aLUT[43] = 0x020B : aKOR[43] = 46 ' 79 - actual pitches 79.1231 79.1532 pLUT[44] = 0x0B07 : pKOR[44] = 32 ' 80 - actual pitches 80.0483 pLUT[45] = 0x050A : pKOR[45] = 70 : aLUT[45] = 0x020C : aKOR[45] = 68 ' 81 - actual pitches 80.9831 81.0995 pLUT[46] = 0x040C : pKOR[46] = 13 : aLUT[46] = 0x040B : aKOR[46] = 85 ' 82 - actual pitches 81.9996 81.9332 pLUT[47] = 0x0B08 : pKOR[47] = 63 : aLUT[47] = 0x080A : aKOR[47] = 19 ' 83 - actual pitches 82.98 82.9631 pLUT[48] = 0x0110 : pKOR[48] = 26 : aLUT[48] = 0x010F : aKOR[48] = 82 ' 84 - actual pitches 84.24 84.2427 pLUT[49] = 0x0210 : pKOR[49] = 10 : aLUT[49] = 0x020F : aKOR[49] = 65 ' 85 - actual pitches 84.92 84.9027 pLUT[50] = 0x040F : pKOR[50] = 19 : aLUT[50] = 0x040E : aKOR[50] = 75 ' 86 - actual pitches 85.9827 85.9083 pLUT[51] = 0x060D : pKOR[51] = 86 ' 87 - actual pitches 86.8453 pLUT[52] = 0x0311 : pKOR[52] = 52 ' 88 - actual pitches 87.8096 pLUT[53] = 0x0B0C : pKOR[53] = 9 : aLUT[53] = 0x0B0B : aKOR[53] = 84 ' 89 - actual pitches 88.9195 88.9132 pLUT[54] = 0x0A0D : pKOR[54] = 45 ' 90 - actual pitches 90.0253 pLUT[55] = 0x0611 : pKOR[55] = 63 ' 91 - actual pitches 91.0296 pLUT[56] = 0x0A0F : pKOR[56] = 28 : aLUT[56] = 0x0A0E : aKOR[56] = 88 ' 92 - actual pitches 92.1627 92.1683 pLUT[57] = 0x0911 : pKOR[57] = 10 : aLUT[57] = 0x0910 : aKOR[57] = 66 ' 93 - actual pitches 92.9696 93.04 pLUT[58] = 0x0B10 : pKOR[58] = 7 : aLUT[58] = 0x0B0F : aKOR[58] = 58 ' 94 - actual pitches 93.86 93.7627 '!!! from here on theoretical mapping is used.. pLUT[59] = 0x0B10 : pKOR[59] = 64 : aLUT[59] = 0x0418 : aKOR[59] = 64 '95 pLUT[60] = 0x070F : pKOR[60] = 60 : aLUT[60] = 0x0313 : aKOR[60] = 67 '96 x x kan ook op snaar 2 pLUT[61] = 0x0116 : pKOR[61] = 64 : aLUT[61] = 0x0618 : aKOR[61] = 64 '97 x pLUT[62] = 0x0117 : pKOR[62] = 73 : aLUT[62] = 0x0718 : aKOR[62] = 64 '98 x pLUT[63] = 0x0418 : pKOR[63] = 68 : aLUT[63] = 0x0818 : aKOR[63] = 64 '99 x x pLUT[64] = 0x0316 : pKOR[64] = 64 : aLUT[64] = 0x0018 : aKOR[64] = 60 '100 x x pLUT[65] = 0x001B : pKOR[65] = 62 : aLUT[65] = 0x0910 : aKOR[65] = 63 '101 x x kan op snaar 0 en 9 x x 'ook op 8 en 2 pLUT[66] = 0x0515 : pKOR[66] = 66 : aLUT[66] = 0x0219 : aKOR[66] = 65 '102 x x pLUT[67] = 0x0417 : pKOR[67] = 62 : aLUT[67] = 0x021A : aKOR[67] = 71 '103 x x pLUT[68] = 0x0813 : pKOR[68] = 65 : aLUT[68] = 0x001E : aKOR[68] = 60 '104 x x pLUT[69] = 0x0616 : pKOR[69] = 63 : aLUT[69] = 0x0230 : aKOR[69] = 64 '105 x pLUT[70] = 0x0A20 : pKOR[70] = 64 : aLUT[70] = 0x0330 : aKOR[70] = 64 '106 x pLUT[71] = 0x0815 : pKOR[71] = 62 : aLUT[71] = 0x0519 : aKOR[71] = 67 '107 x x pLUT[72] = 0x0040 : pKOR[72] = 64 : aLUT[72] = 0x0530 : aKOR[72] = 64 '108 pLUT[73] = 0x031E : pKOR[73] = 61 : aLUT[73] = 0x0630 : aKOR[73] = 64 '109 x pLUT[74] = 0x0916 : pKOR[74] = 74 : aLUT[74] = 0x061A : aKOR[74] = 60 '110 x x kan ook op snaar 3 pLUT[75] = 0x0818 : pKOR[75] = 64 : aLUT[75] = 0x061B : aKOR[75] = 65 '111 x x pLUT[76] = 0x0440 : pKOR[76] = 64 : aLUT[76] = 0x061C : aKOR[76] = 72 '112 - x pLUT[77] = 0x0540 : pKOR[77] = 64 : aLUT[77] = 0x0A30 : aKOR[77] = 64 pLUT[78] = 0x0919 : pKOR[78] = 69 : aLUT[78] = 0x0B30 : aKOR[78] = 64 '114 x pLUT[79] = 0x0B17 : pKOR[79] = 66 : aLUT[79] = 0x1030 : aKOR[79] = 64 '115 pLUT[80] = 0x071E : pKOR[80] = 64 : aLUT[80] = 0x1130 : aKOR[80] = 64 '116 x pLUT[81] = 0x0A1C : pKOR[81] = 66 : aLUT[81] = 0x071F : aKOR[81] = 65 '117 x x pLUT[82] = 0x081E : pKOR[82] = 64 : aLUT[82] = 0x0720 : aKOR[82] = 65 '118 x x pLUT[83] = 0x0B40 : pKOR[83] = 59 : aLUT[83] = 0x1430 : aKOR[83] = 64 '119 x 'for the range up to 127 we may have to tune the fundamental an octave up. pLUT[84] = 0x0B4D : pKOR[84] = 71 : aLUT[84] = 0x1530 : aKOR[84] = 64 '120 pLUT[85] = 0x1140 : pKOR[85] = 64 : aLUT[85] = 0x1630 : aKOR[85] = 64 pLUT[86] = 0x0920 : pKOR[86] = 59 : aLUT[86] = 0x1730 : aKOR[86] = 64 '122 x pLUT[87] = 0x1340 : pKOR[87] = 64 : aLUT[87] = 0x1830 : aKOR[87] = 64 '123 pLUT[88] = 0x1440 : pKOR[88] = 64 : aLUT[88] = 0x1930 : aKOR[88] = 64 pLUT[89] = 0x1540 : pKOR[89] = 64 : aLUT[89] = 0x1A30 : aKOR[89] = 64 pLUT[90] = 0x1640 : pKOR[90] = 64 : aLUT[90] = 0x1B30 : aKOR[90] = 64 '126 pLUT[91] = 0x1740 : pKOR[91] = 64 : aLUT[91] = 0x2030 : aKOR[91] = 64 '127 - this is the absolute upper limit. Return Lookup_EQ: 'This is the loopup table for best possible equal temperament playing 'to be done!!! 'pLUT[0] = 0-91 for notes 36 to 127 For k = 0 To 91 pKOR[k] = 64 'default to no correction or CC24 in central position aKOR[k] = 64 Next For k = 0 To 18 aLUT[k] = 0 ' aKOR[k] = 64 Next pLUT[0] = 0x0001 : pKOR[0] = 64 'pLUT: highbyte, lownibble = string number, lowbyte= multiplier (cc22) ' highbyte, highnibble = basenote transposition: ' 1 = octave up, 2= 2 octaves up, 3= 3 octaves up ' 8 = octave down, 9 = 2 octaves down. 'pKOR: pitch correction required (64 = no correction), range 0-127 pLUT[1] = 0x0101 : pKOR[1] = 64 pLUT[2] = 0x0201 : pKOR[2] = 64 pLUT[3] = 0x0301 : pKOR[3] = 64 pLUT[4] = 0x0401 : pKOR[4] = 64 pLUT[5] = 0x0501 : pKOR[5] = 64 pLUT[6] = 0x0601 : pKOR[6] = 64 pLUT[7] = 0x0701 : pKOR[7] = 64 pLUT[8] = 0x0801 : pKOR[8] = 64 pLUT[9] = 0x0901 : pKOR[9] = 64 pLUT[10] = 0x0A01 : pKOR[10] = 64 pLUT[11] = 0x0B01 : pKOR[11] = 64 pLUT[12] = 0x0002 : pKOR[12] = 62 '48 x pLUT[13] = 0x0102 : pKOR[13] = 64 '49 x pLUT[14] = 0x0202 : pKOR[14] = 64 '50 x pLUT[15] = 0x0302 : pKOR[15] = 60 '51 x pLUT[16] = 0x0402 : pKOR[16] = 65 '52 x pLUT[17] = 0x0502 : pKOR[17] = 67 '53 x pLUT[18] = 0x0602 : pKOR[18] = 66 '54 x pLUT[19] = 0x0702 : pKOR[19] = 63 : aLUT[19] = 0x0003 : aKOR[19] = 66 '55 x x pLUT[20] = 0x0802 : pKOR[20] = 66 : aLUT[20] = 0x0103 : aKOR[20] = 70 '56 x x pLUT[21] = 0x0902 : pKOR[21] = 65 : aLUT[21] = 0x0203 : aKOR[21] = 70 '57 x x pLUT[22] = 0x0A02 : pKOR[22] = 71 : aLUT[22] = 0x0303 : aKOR[22] = 67 '58 x x pLUT[23] = 0x0B02 : pKOR[23] = 73 : aLUT[23] = 0x0403 : aKOR[23] = 73 '59 x x pLUT[24] = 0x0004 : pKOR[24] = 65 : aLUT[24] = 0x0503 : aKOR[24] = 76 '60 x x pLUT[25] = 0x0104 : pKOR[25] = 76 : aLUT[25] = 0x0603 : aKOR[25] = 76 '61 x x pLUT[26] = 0x0204 : pKOR[26] = 78 : aLUT[26] = 0x0703 : aKOR[26] = 74 '62 x x pLUT[27] = 0x0304 : pKOR[27] = 75 : aLUT[27] = 0 : aKOR[27] = 64 '63 x pLUT[28] = 0x0404 : pKOR[28] = 83 : aLUT[28] = 0 : aKOR[28] = 64 '64 x pLUT[29] = 0x0504 : pKOR[29] = 85 : aLUT[29] = 0 : aKOR[29] = 64 '65 x pLUT[30] = 0x0604 : pKOR[30] = 88 : aLUT[30] = 0 : aKOR[30] = 64 '66 x pLUT[31] = 0x0704 : pKOR[31] = 86 : aLUT[31] = 0 : aKOR[31] = 64 '67 x pLUT[32] = 0x0804 : pKOR[32] = 92 : aLUT[32] = 0 : aKOR[32] = 64 '68 x pLUT[33] = 0x0904 : pKOR[33] = 93 : aLUT[33] = 0 : aKOR[33] = 64 '69 x pLUT[34] = 0x0007 : pKOR[34] = 85 : aLUT[34] = 0 : aKOR[34] = 64 '70 x pLUT[35] = 0x0A04 : pKOR[35] = 44 : aLUT[35] = 0x0605 : aKOR[35] = 45 '71 x x pLUT[36] = 0x0B04 : pKOR[36] = 59 : aLUT[36] = 0 : aKOR[36] = 59 '72 x pLUT[37] = 0x0506 : pKOR[37] = 65 : aLUT[37] = 0x0008 : aKOR[37] = 63 '73 x x pLUT[38] = 0x0905 : pKOR[38] = 66 : aLUT[38] = 0x0606 : aKOR[38] = 70 '74 x x pLUT[39] = 0x0A05 : pKOR[39] = 69 : aLUT[39] = 0x0009 : aKOR[39] = 78 '75 x x pLUT[40] = 0x0507 : pKOR[40] = 67 : aLUT[40] = 0x0906 : aKOR[40] = 64 '76 x pLUT[41] = 0x0508 : pKOR[41] = 64 : aLUT[41] = 0x0A06 : aKOR[41] = 64 pLUT[42] = 0x0608 : pKOR[42] = 64 : aLUT[42] = 0x0B06 : aKOR[42] = 64 pLUT[43] = 0x0708 : pKOR[43] = 64 : aLUT[43] = 0x000C : aKOR[43] = 64 'note 79 pLUT[44] = 0x0409 : pKOR[44] = 64 : aLUT[44] = 0x010C : aKOR[44] = 64 '80 x pLUT[45] = 0x0708 : pKOR[45] = 68 : aLUT[45] = 0x030A : aKOR[45] = 60 '81 x x pLUT[46] = 0x0A07 : pKOR[46] = 65 : aLUT[46] = 0x030C : aKOR[46] = 64 '82 x pLUT[47] = 0x000D : pKOR[47] = 60 : aLUT[47] = 0x030B : aKOR[47] = 63 '83 x x pLUT[48] = 0x0010 : pKOR[48] = 64 : aLUT[48] = 0x050C : aKOR[48] = 64 '84 pLUT[49] = 0x0809 : pKOR[49] = 63 : aLUT[49] = 0x030C : aKOR[49] = 60 '85 x x pLUT[50] = 0x0710 : pKOR[50] = 64 : aLUT[50] = 0x070C : aKOR[50] = 64 '86 x pLUT[51] = 0x0310 : pKOR[51] = 64 : aLUT[51] = 0x080C : aKOR[51] = 64 pLUT[52] = 0x0410 : pKOR[52] = 64 : aLUT[52] = 0x090C : aKOR[52] = 64 pLUT[53] = 0x0011 : pKOR[53] = 63 : aLUT[53] = 0x060C : aKOR[53] = 64 '89 x x kan ook op snaar 1 pLUT[54] = 0x040E : pKOR[54] = 61 : aLUT[54] = 0x030F : aKOR[54] = 70 '90 x x pLUT[55] = 0x060D : pKOR[55] = 61 : aLUT[55] = 0x0018 : aKOR[55] = 64 '91 x pLUT[56] = 0x0810 : pKOR[56] = 64 : aLUT[56] = 0x0118 : aKOR[56] = 64 pLUT[57] = 0x050F : pKOR[57] = 68 : aLUT[57] = 0x0014 : aKOR[57] = 64 '93 x x pLUT[58] = 0x0A10 : pKOR[58] = 64 : aLUT[58] = 0x0318 : aKOR[58] = 64 pLUT[59] = 0x0B10 : pKOR[59] = 64 : aLUT[59] = 0x0418 : aKOR[59] = 64 '95 pLUT[60] = 0x070F : pKOR[60] = 60 : aLUT[60] = 0x0313 : aKOR[60] = 67 '96 x x kan ook op snaar 2 pLUT[61] = 0x0116 : pKOR[61] = 64 : aLUT[61] = 0x0618 : aKOR[61] = 64 '97 x pLUT[62] = 0x0117 : pKOR[62] = 73 : aLUT[62] = 0x0718 : aKOR[62] = 64 '98 x pLUT[63] = 0x0418 : pKOR[63] = 68 : aLUT[63] = 0x0818 : aKOR[63] = 64 '99 x x pLUT[64] = 0x0316 : pKOR[64] = 64 : aLUT[64] = 0x0018 : aKOR[64] = 60 '100 x x pLUT[65] = 0x001B : pKOR[65] = 62 : aLUT[65] = 0x0910 : aKOR[65] = 63 '101 x x kan op snaar 0 en 9 x x 'ook op 8 en 2 pLUT[66] = 0x0515 : pKOR[66] = 66 : aLUT[66] = 0x0219 : aKOR[66] = 65 '102 x x pLUT[67] = 0x0417 : pKOR[67] = 62 : aLUT[67] = 0x021A : aKOR[67] = 71 '103 x x pLUT[68] = 0x0813 : pKOR[68] = 65 : aLUT[68] = 0x001E : aKOR[68] = 60 '104 x x pLUT[69] = 0x0616 : pKOR[69] = 63 : aLUT[69] = 0x0230 : aKOR[69] = 64 '105 x pLUT[70] = 0x0A20 : pKOR[70] = 64 : aLUT[70] = 0x0330 : aKOR[70] = 64 '106 x pLUT[71] = 0x0815 : pKOR[71] = 62 : aLUT[71] = 0x0519 : aKOR[71] = 67 '107 x x pLUT[72] = 0x0040 : pKOR[72] = 64 : aLUT[72] = 0x0530 : aKOR[72] = 64 '108 pLUT[73] = 0x031E : pKOR[73] = 61 : aLUT[73] = 0x0630 : aKOR[73] = 64 '109 x pLUT[74] = 0x0916 : pKOR[74] = 74 : aLUT[74] = 0x061A : aKOR[74] = 60 '110 x x kan ook op snaar 3 pLUT[75] = 0x0818 : pKOR[75] = 64 : aLUT[75] = 0x061B : aKOR[75] = 65 '111 x x pLUT[76] = 0x0440 : pKOR[76] = 64 : aLUT[76] = 0x061C : aKOR[76] = 72 '112 - x pLUT[77] = 0x0540 : pKOR[77] = 64 : aLUT[77] = 0x0A30 : aKOR[77] = 64 pLUT[78] = 0x0919 : pKOR[78] = 69 : aLUT[78] = 0x0B30 : aKOR[78] = 64 '114 x pLUT[79] = 0x0B17 : pKOR[79] = 66 : aLUT[79] = 0x1030 : aKOR[79] = 64 '115 pLUT[80] = 0x071E : pKOR[80] = 64 : aLUT[80] = 0x1130 : aKOR[80] = 64 '116 x pLUT[81] = 0x0A1C : pKOR[81] = 66 : aLUT[81] = 0x071F : aKOR[81] = 65 '117 x x pLUT[82] = 0x081E : pKOR[82] = 64 : aLUT[82] = 0x0720 : aKOR[82] = 65 '118 x x pLUT[83] = 0x0B40 : pKOR[83] = 59 : aLUT[83] = 0x1430 : aKOR[83] = 64 '119 x 'for the range up to 127 we may have to tune the fundamental an octave up. pLUT[84] = 0x0B4D : pKOR[84] = 71 : aLUT[84] = 0x1530 : aKOR[84] = 64 '120 pLUT[85] = 0x1140 : pKOR[85] = 64 : aLUT[85] = 0x1630 : aKOR[85] = 64 pLUT[86] = 0x0920 : pKOR[86] = 59 : aLUT[86] = 0x1730 : aKOR[86] = 64 '122 x pLUT[87] = 0x1340 : pKOR[87] = 64 : aLUT[87] = 0x1830 : aKOR[87] = 64 '123 pLUT[88] = 0x1440 : pKOR[88] = 64 : aLUT[88] = 0x1930 : aKOR[88] = 64 pLUT[89] = 0x1540 : pKOR[89] = 64 : aLUT[89] = 0x1A30 : aKOR[89] = 64 pLUT[90] = 0x1640 : pKOR[90] = 64 : aLUT[90] = 0x1B30 : aKOR[90] = 64 '126 pLUT[91] = 0x1740 : pKOR[91] = 64 : aLUT[91] = 0x2030 : aKOR[91] = 64 '127 - this is the absolute upper limit. Return '[EOF]