'**************************************************************************** '* * '* 3 1/2 octave extreme high membrane driven organ * '* 3-notes per PIC with ADSR * '* Godfried-Willem Raes * '* 2017 * ' *************************************************************************** ' NOTE: Pickit3 must be used for programming these devices! ' Each interrupt has its own handler, simply write one handler for each interrupting ' device without having to work out which interrupt it is. ' Timers are more logical: specify the count going upwards that will trigger an ' interrupt rather than working out when the counter would underflow. ' COMMENTS made during development of HybrLo: '01.08.2016: Test and debug board designed, etched and soldered. ' Programming requires the PiCkit3 programmer. PicKit2 does not work! '02.08.2016: 1M resistor added over X-tal pins '03.08.2016: Finaly got the clock up and running on the X-tal ' Working out the MIDI UART now. ' Midi-in buffering implemented. ' Trying to use the pwm channels... we cannot use the HPWM commands... ' Implementing velocity control with timers ' Repeats working now. '04.08.2016: Adding 12 bit ADC on channel AN0 ' Midi out looks like working using the Basic command HSROut ' 1 midi packet (3 bytes) takes some 1ms, which conforms to the standard. ' adding initialisation for the PWM channels ' This is as yet not working... '05.08.2016: with 60Mhz clock the frequency range for PWM would be 60MHz --> 915Hz ' so, for audio use we need a prescale devider :64 ' Thus the frequency range would become 14Hz --> 937.5kHz '06.08.2016: pwm begint stilaan goed te werken. ' different modes of operation implemented for the pwm channels ' pwmmodus 0 fully debugged. ' pwmmodus 2 fully debugged (3-phase motor control) ' pwmmodus 1 fully debugged (3 independent PWM channels) ' pwmmodus 3 added: AC motor with capacitor phase shifter using 2 pwm channels ' PWM principieel werkend nu. ' eventueel kunnen nog dead times toegevoegd worden indien nodig voor een toepassing ' We kunnen overbodige pwm pinnen nog disablen en beschikbaar maken voor ' andere funkties. '07.08.2016: Lookup tables for frequencies in 12-tone equal temperament added. Ambitus= 22-127 ' looks like it's possible to implement a 3-voice midi synth on this platform. ' Just did it: the 3-channel synth is working! ' Studying the implementation of 32-bit timers ' timers 2/3 and 4/5 implemented as 32-bits timers ' trying to use timer23 instead of our loop counter. ' This now works fine ' We could use timer1 as a motor speed controller for a stepper ' Timer 45 could be used as a high resolution, extreme ambitus tone generator ' Timer 1,4,5 implemented as fast timers in 16 bits for ADSR implementation ' PWM lookups added for this. '09.08.2016: Further coding. adsr not yet operational. - version saved as 007 '10.08.2016: Different approach to adsr - simplified, using timers ' ADSR works now, but we will need a steep lowpass filter on the output ' with this code we are at the limit of what the PIC can handle. ' As it is now, we can have 6 independent PWM channels. ' For the 3-voice synth we need them all and we used up all available timers. ' The priority settings for the IRQ's are very important for this code to work well. ' This version saved as PIC24_008.bas '11-12.08.2016: application written for midi-invertor: Mirrored_X.bas. Tested o.k. ' PCB made for this app. '13.08.2016: metacompiler statements for UART-TX and UART-RX added. ' Buffered midi-out fully implemented. ' For some reason the ADSR pwm is no longer working now... ' Rearranging priority levels made it work again. ' ADSR timers must have a :8 divider setting. ' This version saved as PIC24_009 ' There is a lot of jitter on the main loop, so we must be operating close to ' the maximum performance for this chip. ' Working version saved as P14_synth1.bas '14.08.2016: To relax the interrupt density, we could also invert the pwm functions and ' use the timers 1,4,5 for frequency generation with waveform duty cycle whilst ' the 3 real PWM channel could do the ADRS at the highest possible frequency. ' This requires PWMmodus to be set to 0. ' Coding started. ' looks like PWM needs to be inverted now. Done. ' ADSR works fine now, but the load on the processor is still very high. ' we should try to get the divisions out of the main loop now. Done.\ ' Further improvements: decrease nr. of steps for ADSR, as 127 steps ' for an attack time of say 100ms seems largely overkill... '15.06.2016: ADSR coding restructured to make it more readible. ' Tests o.k. bit we still have glitches and seem to be working at the ' edge of what the processor can do. ' PCB dsign started for an evaluation board for this synth. '20.08.2016: This design could be used for '23.08.2016: Evaluation board finished. This works o.k. ' bug removed in the duty cycle control: cannot be zero! ' Start work on the coding for ' This file now saved as HybrLo_22_24.bas '-------------------------------------------------------------------------------------- '23.08.2016: Start delopment of specific HybrLo code. ' This code implements notes 22, 23 and 24 and their octaves. '29.08.2016: Two boards made with active filters. ' Hub board made as well: this should also filter midi for the note-boards. ' HybrLo channel decided to become 8 '31.08.2016: Recoding for the new controller implementation. ' The PCB's for all notes are ready now. '01.09.2016: GMT testcode adapted such that we can test this code... ' This firmware copied and renamed as HybrLo_25_27.bas for the second board. '07.09.2016: Mute logic inverted in the code for all boards. '11.09.2016: First tests on the assembled robot. ' Mute logic appears to be wrong... '12.09.2016: Seems working fine now, but we do have intermittent failures. '13.09.2016: Controller 15 added for global waveshape control. '20.09.2016: Looks like release is no longer working now... ' We could try to nake the 947 constant for scaling the ADSR smaller ' ADSR_scale constant introduced. ' release bug found: scale multiply forgotten in the noteoff proc. ' if we set ADSR_scale to 1024, we can avoid many multiplies in the code... ' done with the introduction of ADSR_shift = 10 ' Program Change command implemented now. Needs further investigations. ' 09.10.2016: All pipes mounted on the instrument... ' Further research into the origins of the glitches. ' PWM freq lowered to 29kHz ' try to give UART lower priority, to avoid glitches ' 10.10.2016: Recoding to avoid float's in the code. ' Now with 40dB scalings. ' Ommited ADSR flags reset on note-On command, was the first cause of the glitches. ' real time modulation of volume added using ctrl's 70-82 ' For the other boards, just change the $define Boardx_x compiler metacommand. ' 11.10.2016: Extending range with an octave... ' Programming under high fever conditions... ' extending with yet one more octave... ' Could we add pitch insecurity in a simple way? ' versie 002: 11.10.2016: 40dB dynamiek, maar werkend in de onderste 13 bits ' 12.10.2016: 40dB lookups herberekend voor bovenste bereik van de PWM ' dit zou de S/R verhouding moeten verbeteren. ' 60dB lookups added again. ' This version uploaded. Version 003. ' 13.10.2016: start implementation of ctrl#1 for frequency jitter. ' ADSR periods halved. ' Jitter controller (#1) added ' Release range reset to 512 ms. Attack and decay are now 256ms ' 14.10.2016: Presets modified. '------------------------------------------------------------------------------- ' 16.02.2017: Start from the framework of HybrLo to code for ' First thing: try to generate the required very high pitches. ' Prescalers for the timers set to :8, rather than :64 on Hybrlo ' Priorities set to 6 ' So far this works, if we shift the period lookups 2 octaves down. ' PTPER set to 512 - this works. We can even go higher it seems. ' First tests on note 84 passed. ' Test on note 126 (11660Hz measured) passed. ' 19.02.2017: Lookups for the 15 different compilations added. ' Four PIC's on board 1 programmed. ' 20.02.2017: First test with the pipes mounted. ' there are glitches in the ADRS..., the principle seems to work well. ' Problems with ports being high on init... try using portb.6 for ctrl.66 ' Required code changes: ' Velo should steer attack level ' Ctrl 7 should steer the sustain level ' 23.02.2017: Attack_time, decay_time, release_time changed to dword as they could overflow ' 28.02.2017: Code problems in boards 3 and 4. Ctrl66 does not seem to work. ' Problem solved: poling wrong on the Omron Relay. ' 03.03.2017: Code optimised. Shift in ADR reduced to 8. ' We have to check the tuning: the octaves are a bit wrong!!! ' Start implementing microtuning using ctrl's 72-116 ' Pitch-periods are now declared constants. ' ADSR range made consistent with PTPER : now 9 bits. ' 04.03.2017: Microtuning support added, ctrl's 72 to 117 ' all 15 processors reflashed. Version 1.1 now ' 05.03.2017: the microtuning implementation appears not to work... ' 07.03.2017: duty cycle controll is now pitch dependent. Version 1.3, saved as backup ' 08.03.2017: start implementation of just intonation tunings ' This will be version 1.4 ' here we will try to set the timer prescaler to 0, to increase ' tuning precision with a factor 8. ' This now seems to work on the test board. ' However, changing the tuning seems not to work at all. ' Maybe the timer IRQ's are blocking the calculations. ' so, let;s try to disable interrupts on reception of tuning commands. ' Bug found: was not in this code, bit in the GMT test-code!!! ' Mircrotuning now works. ' JI lookups lead to way too high freq's. There must be a scaling bug here. ' 09.03.2017: This bug was due to a compiler bug in that it did not calculate the constants ' at compilation time. ' Period[127] = Note95 * 5 / 32 leads to errors! ' So, we wrote a utility in PBCC to calculate all JI pitch lookups. ' There are precision errors increasing with frequency. ' Compensation for this requires further analysis. ' note 126 in EQ measures 11655.6 Hz, it should be 11840 Hz, so a 184.4Hz fault, or 1.557% ' note 84 in EQ measures 1045.1 Hz, it should be 1047 Hz, so a 1.9Hz fault, or 0.18% ' we can compensate in the lookups for these errors, assuming a linear curve. ' After applying compensations to the lookup tables the measured frequency error are: ' 0.05% for note 84, 0.06% for note 126. We consider this a very good result. ' On request of early adopters, we doubled the release time values. ' This be version 1.5: flashed in all PIC's. ' 10.03.2017: The formula to use for the calculation of the periods needs to be: ' period = ((1/freq) - t) / k ' wherein k = 1 / 60MHz and t = ISR service time, measured as 1.3us ' with this formula applied, the error for note 126 is only 0.018% ' for note 84, the error is 0.045% ' for note 85, the error is 0.022% ' 11.03.2017: lookup algorithm improved with constant ISR time ' now all errors <= 0.02% ' version 1.6 now. Flashed. ' 07.12.2020: TMR3 bug discovered. Corrected in the source code. ' we need to recompile and upload all firmware again now. 15 PIC's to be done... ' 24.12.2020: Compiler upgrade. We could improve the ADSR system, the same way we did for HybrLo ' but unsure as to whether it's worth the trouble... ''------------------------------------------------------------------------------------------------------------- ' 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 ' port-assignments: '****************** Symbol watchdog_led PORTB.7 ' red LED - pin 16 Output PORTB.6 Low PORTB.6 ' for ctrl 66, only connected on some PIC's ' PIC15 steers board 1 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 Declare Xtal = 120 ' set to Fosc $define Enable_UART_RX ' midi-in '$define Enable_UART_TX ' midi-out '$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_Timer45 ' 32-bit timer $define Enable_Timer4 ' as 16 bit timer $define Enable_Timer5 ' as 16 bit timer '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 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 initialisations for the midi input parser: Symbol Midichannel = 5 ' Pi_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 Symbol NrTasks = 3 ' metacompiler commands: ' change these for other boards: (4 boards, 15 PIC's) $define Board84_86 '$define Board87_89 '$define Board90_92 '$define Board93_95 '$define Board96_98 '$define Board99_101 '$define Board102_104 '$define Board105_107 '$define Board108_110 '$define Board111_113 '$define Board114_116 '$define Board117_119 '$define Board120_122 '$define Board123_125 '$define Board126_127 ' board 1: 84- 95 - four PIC's $ifdef Board84_86 Symbol note1 = 84 Symbol note2 = 85 Symbol note3 = 86 Symbol tun1 = note1 - 12 ' = 72 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board87_89 Symbol note1 = 87 Symbol note2 = 88 Symbol note3 = 89 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board90_92 Symbol note1 = 90 Symbol note2 = 91 Symbol note3 = 92 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 $endif $ifdef Board93_95 Symbol note1 = 93 Symbol note2 = 94 Symbol note3 = 95 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif ' board 2: 96 - 107 $ifdef Board96_98 Symbol note1 = 96 Symbol note2 = 97 Symbol note3 = 98 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board99_101 Symbol note1 = 99 Symbol note2 = 100 Symbol note3 = 101 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board102_104 Symbol note1 = 102 Symbol note2 = 103 Symbol note3 = 104 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board105_107 Symbol note1 = 105 Symbol note2 = 106 Symbol note3 = 107 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif ' board 3: 108 - 119 $ifdef Board108_110 Symbol note1 = 108 Symbol note2 = 109 Symbol note3 = 110 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board111_113 Symbol note1 = 111 Symbol note2 = 112 Symbol note3 = 113 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board114_116 Symbol note1 = 114 Symbol note2 = 115 Symbol note3 = 116 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board117_119 Symbol note1 = 117 Symbol note2 = 118 Symbol note3 = 119 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif ' board 4: 120-127 - three PIC's $ifdef Board120_122 Symbol note1 = 120 Symbol note2 = 121 Symbol note3 = 122 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board123_125 Symbol note1 = 123 Symbol note2 = 124 Symbol note3 = 125 Symbol tun1 = note1 - 12 Symbol tun2 = note2 - 12 Symbol tun3 = note3 - 12 ' bug for note 0 $endif $ifdef Board126_127 Symbol note1 = 126 Symbol note2 = 127 Symbol note3 = 0 ' has light Symbol tun1 = note1 - 12 ' 114 Symbol tun2 = note2 - 12 ' 115 'Symbol tun3 = note3 ' - 12 would be a bug for note 0 $endif 'constants used for the operation of the PWM modules ' the modus operandi should be set at compile time! ' For the Hybr boards PWMmodus must be 0. ' For the Pi boards also PWMmodus 0. Symbol PWMmodus = 0 ' 0 = all pwm channels have the same period (frequency) ' PDC1, PDC2, PDC3 steer the PWM setting for each channel ' PTPER is the register to control the period (frequency) ' PHASE1, PHASE2, PHASE3 steer the phase between output channels ' This mode can be used for ADSR control on 3 channels. ' 1 = the three PWM channels have individual period (frequency) controls ' controlled with the PHASE1, PHASE2, PHASE3 registers ' PDC1, PDC2, PDC3 registers steer the PWM ' PWM-value must be < Period ' this mode could be used to implement a 3-voice midi synth ' We only use the PWMH pins for output here, so portB.15, portB.13 and portB.11 ' are free and can be used for adrs control ' 2 = 3-phase motor control mode ' PTPER controls the period (frequency) ' MDC controls the duty cycle for the 3 channels ' PHASE1, PHASE2, PHASE3 steer the phase between the channels ' we start-up with 120 degree phase shifts. ' 3 = 2-phase ac motor using a capacitor phase shifter ' PTPER controls the period (frequency) ' MDC controls the duty cycle for the 3 cha ' PHASE1, PHASE2, PHASE3 steer the phase be' port I/O settings: ' we start-up with 90 degree phase shifts. ' pwm1H, pwm2H, pwm3H used as ADSR outputs ' we configure the L outputs as normal ports for frequency generator outputs TRISA = %100000 ' set to output - we dont use these ports TRISB = %0101011100000000 Output watchdog_led $ifdef Enable_Timer1 ' used as tone generator for note1 IPC0bits_T1IP0 = 1'1 ' set priority - this is very critical! IPC0bits_T1IP1 = 1'1 '1 ' on hybrlo set to 5 IPC0bits_T1IP2 = 0'1 ' 6 = 011 ' T1CON.5 = 0 ' 1 ' set prescaler to :8 = 01 , :64 = 10 , :256 = 11 ' T1CON.4 = 1 ' 0 ' prescaler = 1 = 00 ' first set to :8 for Pi (on Hybr it was :64) ' to get better pitch resolution, 00 would be ideal. ' setting prescaler to 0: T1CON.5 = 0 T1CON.4 = 0 ' ----------------------- T1CON.15 = 1 ' start IFS0bits_T1IF = 0 ' clear Timer1 interrupt flag 'IEC0bits_T1IE = 1 ' Enable the Timer1 interrupt $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 = 1 ' set priority to 1 IPC2bits_T3IP1 = 0 IPC2bits_T3IP2 = 0 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 '1 ' Hubrlo: prescaler set to :64, On Pi we have :8 'T4CON.4 = 1 ' 00 = :1, 01 = :8 , 10 = :64, 11 = :256 ' prescaler set to 0: T4CON.5 = 0 T4CON.4 = 0 ' ------------------------ T4CON.3 = 0 ' operate as 16 bit timer T4CON.1 = 0 ' internal clock IPC6bits_T4IP0 = 0 ' set priority to 6 IPC6bits_T4IP1 = 1 IPC6bits_T4IP2 = 1 Clear IFS1.11 ' clear interrupt flag 'Set IEC1.11 ' enable interrupt $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 for Pi 'T5CON.4 = 1 ' id. ' prescaler set to 0: T5CON.5 = 0 T5CON.4 = 0 ' ---------------------- T5CON.1 = 0 ' internal clock IPC7bits_T5IP0 = 0 ' set priority to 6 IPC7bits_T5IP1 = 1 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 ' 1 IPC2.14 = 1 ' tested with change to 4, 1 step lower then the note timers now...[09.10.2016] ' back to 6 on 10.10.2016, as this was not the cause for the glitches. 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.15 = 0 U1STA.10 = 1 ' transmit enable bit U1STA.11 = 0 Clear IFS0.12 ' clear transmit interrupt flag Set IEC0.12 ' enable interrupt IPC3.0 = 1 IPC3.1 = 1 IPC3.2 = 0 ' set priority to 3 $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 $ifdef Enable_PWM ' PWM channel initialisation ------------------------------------------------------ 'CNPD1 ' enable internal pull down resistor to reset the FLT32 flag on init ' disable interrupts: IEC5.14 = 0 IEC5.15 = 0 IEC6.0 = 0 ' clear interrupt flags: Clear IFS5.14 Clear IFS5.15 Clear IFS6.0 ' pwm time base control register: PTCON 'PTCON.pwm Clear PTCONbits_PTEN ' = PTCON.15 = 0 ' pwmx disabled for setting the bits, should be enabled at the end. PTEN 'PTCON Timebase control register Clear PTCONbits_PTSIDL ' = PTCON.13 ' PTCONbits_SESTAT 'PTCON.12 ' status bit to read Clear PTCONbits_SEIEN ' PTCON.11 disable special event interrupt 'Set PTCONbits_EIPU ' PTCON.10 1 = active period register is updated immediately Clear PTCONbits_EIPU ' PTCON.10 0 = active period register updates occur on PWMx cycle boundaries : setting changed 09.10.2016 Clear PTCONbits_SYNCPOL ' PTCON.9 sync active high. Irrelevant here as we do not use sync Clear PTCONbits_SYNCOEN ' PTCON.8 = 0 ' disable sync output Clear PTCONbits_SYNCEN ' PTCON.7 = 0 ' no external sync Clear PTCONbits_SYNCSRC0 'PTCON.4 Clear PTCONbits_SYNCSRC1 'PTCON.5 Clear PTCONbits_SYNCSRC2 'PTCON.6 Clear PTCONbits_SEVTPS0 'PTCON.0 special event postscaler bits Clear PTCONbits_SEVTPS1 'PTCON.1 Clear PTCONbits_SEVTPS2 'PTCON.2 Clear PTCONbits_SEVTPS3 'PTCON.3 '%110 = / 64 ' timing resolution should become 64x8.5ns = 544ns = 0.544us ' PTPER register primary master time base period register 'PTPER = 64 '32678 ' master time base period register --> PWM frequency 16-bits ' 1 unit is 8.33ns with a 60MHz Fcy ' so 32678 would give 3673 Hz Select Case PWMmodus Case 0 ' this works o.k. now 'PWMCON1.9 = 0 ' ITB: Independent time base mode if set to 1 'PWMCON2.9 = 0 ' PTPER register steers time base if set to 0 'PWMCON3.9 = 0 ' we do not have a SPHASE1, 2, 3 register thus independent pwm control is not possible ' cfr manual example 14-14, p.44 Clear PWMCON1 Clear PWMCON2 Clear PWMCON3 ' PTCON2 register ' pwm input clock prescaler, set to 1 (no division) 'Set PTPER ' set to lowest frequency = 1831,16 Hz ' for the ADSR implementation we should set this as fast as possible! 'PTPER = 1024 ' 256 '1024 ' would this limit the useable range for PWM values??? ' 1024 gives a pwm base frequency of 117kHz ' 09.10.2016 experiment: try this 'PTPER = 4096 ' it gives 29kHz base freq. for PWM on HybrLo ' should be as high as possible for PTPER = 511 ' this determines the range for the PWM control ' with this setting we have 9 bits ' before 24.12.2020 we had PTPER= 512... a bug of course. Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Clear PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 Clear PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 Clear PDC1 Clear PDC2 Clear PDC3 Clear PHASE1 Clear PHASE2 Clear PHASE3 Set MDC ' set to longest period ' make the pwmL port free for general I/O: (note_Ports) IOCON1.15 = 1 IOCON1.14 = 0 IOCON2.15 = 1 IOCON2.14 = 0 IOCON3.15 = 1 IOCON3.14 = 0 ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON1 ' 0xA800 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON2 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 ' now we have ports free for the timer-tone generators: Symbol Note_Port1 PORTB.15 Symbol Note_Port2 PORTB.13 Symbol Note_Port3 PORTB.11 Output Note_Port1 Output Note_Port2 Output Note_Port3 Case 1 ' cfr. example 14-18, p.48 in manual 'PWMCON1.9 = 1 ' ITB: Independent time base mode if set to 1 'PWMCON2.9 = 1 ' PTPER register steers time base if set to 0 'PWMCON3.9 = 1 ' we do not have a SPHASE1, 2, 3 register thus independent pwm control is not possible ' IOCON1,2,3 must be $C000 PWMCON1 = $0200 PWMCON2 = $0200 PWMCON3 = $0200 ' PTCON2 register ' pwm input clock prescaler, set to /64 Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Set PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 Set PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 Set PTPER '= 256 ' test value - probably irrelevant in this mode Set PHASE1 ' freq to lowest Set PHASE2 Set PHASE3 Clear PDC1 ' duty cycles note: PDC1 < PHASE1 Clear PDC2 Clear PDC3 Set MDC ' ? clear mdc - seems irrelevant here ' make the pwmL port free for general I/O: IOCON1.15 = 1 IOCON1.14 = 0 IOCON2.15 = 1 IOCON2.14 = 0 IOCON3.15 = 1 IOCON3.14 = 0 ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON1 -pwmL disabled. Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON2 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0x8000, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 ' now we have ports free for ADRS: Symbol ADSR_Port1 PORTB.15 Symbol ADSR_Port2 PORTB.13 Symbol ADSR_Port3 PORTB.11 Output ADSR_Port1 Output ADSR_Port2 Output ADSR_Port3 Case 2 ' 3-phase motor control setting ' ref. ,manual 14-16, p. 46 'PWMCON1.9 = 0 ' ITB: Independent time base mode if set to 1 'PWMCON2.9 = 0 ' PTPER register steers common time base if set to 0 'PWMCON3.9 = 0 PWMCON1 = $0100 PWMCON2 = $0100 PWMCON3 = $0100 ' PTCON2 register ' pwm input clock prescaler, set to /64 Clear PTCON2bits_PCLKDIV0 ' PTCON2.0 ' bit0 Set PTCON2bits_PCLKDIV1 ' PTCON2.1 ' bit1 Set PTCON2bits_PCLKDIV2 ' PTCON2.2 ' bit2 Clear MDC ' master duty cycle control - set to zero on init Set PTPER ' lowest freq. Clear PHASE1 ' 0 graden PHASE2 = 21845 ' 120 graden PHASE3 = 43690 ' 240 graden ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON1 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON2 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 Case 3 ' 2-phase ac motor PWMCON1 = $0100 PWMCON2 = $0100 Clear PTcon2bits_PCLKDIV0 Set PTcon2bits_PCLKDIV1 Set PTcon2bits_PCLKDIV2 Clear MDC Set PTPER Clear PHASE1 PHASE2 = 16384 ' 90 graden ' the FCLCON1,2,3 and IOCON1,2,3 require a key to be written: ' pwm channel 1: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON1 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON1 ' set pwm ownership and polarity to IOCON1 ' IOCON1 = 0xC000 sets pwm mode to complementary outputs Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON1 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON1 ' pwm channel 2: -------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON2 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON2 ' set pwm ownership and polarity to IOCON2 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON2 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON2 ' pwm channel 3: ----------------------------------------------- Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC003, w0 ' required value for FCLCON3 ' %1100000000000000 = &HC000 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, FCLCON3 ' set pwm ownership and polarity to IOCON1 Mov #0xabcd, w10 ' etc... p. 226 pwm manual Mov #0x4321, w11 Mov #0xC000, w0 ' required value for IOCON3 Mov w10, PWMKEY Mov w11, PWMKEY Mov w0, IOCON3 EndSelect ' common settings: PWMCON1.12 = 0 'fault interrupt disabled PWMCON2.12 = 0 PWMCON3.12 = 0 PWMCON1.11 = 0 'current limit disabled PWMCON2.11 = 0 PWMCON3.11 = 0 PWMCON1.10 = 0 'trigger event interrupts disabled PWMCON2.10 = 0 PWMCON3.10 = 0 ' PWMCON1.9 = 1 ' ITB: Independent time base mode if set to 1 ' PWMCON2.9 = 1 ' PTPER register steers time base if set to 0 ' PWMCON3.9 = 1 ' we do not have a SPHASE1, 2, 3 register thus independent pwm control is not possible ' PWMCON1.8 = 0 'PCD1 en SDC1 registers provide duty cycle info - ' PWMCON2.8 = 0 ' PWMCON3.8 = 0 PWMCON1.7 = 1 ' dead time disabled PWMCON2.7 = 1 PWMCON3.7 = 1 ' PWMCON1.6 = 0 ' PWMCON2.6 = 0 ' PWMCON3.6 = 0 ' PWMCON1.3 = 0 ' PWMCON2.3 = 0 ' PWMCON3.3 = 0 ' PWMCON1.2 = 0 ' edge aligned mode CAM bit. Ignored when ITB = 0 ' PWMCON2.2 = 0 ' PWMCON3.2 = 0 ' PWMCON1.1 = 0 ' PWMCON2.1 = 0 ' PWMCON3.1 = 0 ' PWMCON1.0 = 1 ' PWMCON2.0 = 1 ' PWMCON3.0 = 1 ' The pwm1 to pwm3 values for the duty cycle are in the PDC1, PDC2 and PDC3 registers ' The phases in the PHASE1, PHASE2, PHASE3 registers, if not used for frequency. AUXCON1 = 0 AUXCON2 = 0 AUXCON3 = 0 Set PTCONbits_PTEN ' = PTCON.15 pwmx should be enabled at the end. $endif ' --------------------------------------------------------------------------------- Variables: ' variable declarations: ' variables for midi reception and parsing: 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 ' variables for the timing system: Dim time As Dword ' 10 us resolution Dim maxtim As time.31 ' overflow bit, will cause timer reset after 6 hours Dim t As Word ' loopcounter 750kHz Dim tl As t.Byte0 Dim th As t.Byte1 Dim i As Byte Dim j As Word Dim fraction As Float Dim idx As Byte Dim Nxt As Dword Dim TimVals[NrTasks] As Dword Dim tg As Bit Dim resort_flag As Bit ' Dim Dur[128] As Word ' Dim Dur5[128] As Word ' Dim DataBuffer[256] As Word ' adc databuffer ' Dim DataInIdx As Byte ' Dim DataOutIdx As Byte ' 16 bit variables and floats for the PWM system Dim pwm1value As Word Dim pwm2value As Word Dim pwm3value As Word Dim pwm1freq As Word Dim pwm2freq As Word Dim pwm3freq As Word Dim pwm1phase As Word Dim pwm2phase As Word Dim pwm3phase As Word Dim dutcy1 As Float Dim dutcy2 As Float Dim dutcy3 As Float Dim period1 As Word Dim period2 As Word Dim period3 As Word Dim tuneSword1 As SWord Dim tuneSword2 As SWord Dim tuneSword3 As SWord Dim range As Word ' for microtuning 08.03.2017 Dim CC21 As Word ' value for controller 21 - tuning lookups ' variables for the ADSR system: Dim Attack1_time As Word ' runs from 1024 to 130048 , now back to 16-bit Dim Attack1_level As Word ' derived from velo, with a log-map Dim Decay1_time As Word Dim Sustain1_level As Word ' derived from volume controller ctrl 7, with log-map Dim Release1_Time As Word ' derived from release bit with noteoff commands Dim Attack2_time As Word Dim Attack2_level As Word ' derived from velo, with a log-map Dim Decay2_time As Word Dim Sustain2_level As Word ' derived from volume controller ctrl 7, with log-map Dim Release2_Time As Word ' derived from release bit with noteoff commands Dim Attack3_time As Word Dim Attack3_level As Word ' derived from velo, with a log-map Dim Decay3_time As Word Dim Sustain3_level As Word ' derived from volume controller ctrl 7, with log-map Dim Release3_Time As Word ' derived from release bit with noteoff commands Dim ADSR1_flags As Byte ' more logical arrangement, in time order: Dim Attack1_flag As ADSR1_flags.0 Dim Attack1_tog As ADSR1_flags.1 Dim Decay1_flag As ADSR1_flags.2 Dim Decay1_tog As ADSR1_flags.3 Dim Sustain1_flag As ADSR1_flags.4 Dim Sustain1_tog As ADSR1_flags.5 Dim Release1_flag As ADSR1_flags.6 Dim Release1_tog As ADSR1_flags.7 Dim cnt1 As Word ' Word Dim Astepval1 As Word ' can be > 16 bits! - no longer the case now. Dim Dstepval1 As Word Dim Rstepval1 As Word Dim ADSR2_flags As Byte Dim Attack2_flag As ADSR2_flags.0 Dim Attack2_tog As ADSR2_flags.1 Dim Decay2_flag As ADSR2_flags.2 Dim Decay2_tog As ADSR2_flags.3 Dim Sustain2_flag As ADSR2_flags.4 Dim Sustain2_tog As ADSR2_flags.5 Dim Release2_flag As ADSR2_flags.6 Dim Release2_tog As ADSR2_flags.7 Dim cnt2 As Word Dim Astepval2 As Word Dim Dstepval2 As Word Dim Rstepval2 As Word Dim ADSR3_flags As Byte Dim Attack3_flag As ADSR3_flags.0 Dim Attack3_tog As ADSR3_flags.1 Dim Decay3_flag As ADSR3_flags.2 Dim Decay3_tog As ADSR3_flags.3 Dim Sustain3_flag As ADSR3_flags.4 Dim Sustain3_tog As ADSR3_flags.5 Dim Release3_flag As ADSR3_flags.6 Dim Release3_tog As ADSR3_flags.7 Dim cnt3 As Word Dim Astepval3 As Word Dim Dstepval3 As Word Dim Rstepval3 As Word Dim Ont[128] As Word ' on-time lookup for pwm - table for Pi ' duty cycle control for tone generators: Dim On1 As Word ' for timer1 --> note1 Dim Of1 As Word Dim On2 As Word ' for timer4 --> note2 Dim Of2 As Word Dim On3 As Word ' for timer5 --> note3 Dim Of3 As Word Dim C1bit As Byte ' 13.10.2016 Dim C1val As Word 'byte ' controller #1 0-127 Dim jitter As SWord ' random byte -128 -> 127, changed to sword 13.10.2016 Dim Period[128] As Word ' required to implement different tunings. - midi note lookup table Variable_Inits: Clear Ringbuffer ' Rx Clear IndexIn ' Clear the buffer internal pointer Clear IndexOut ' Clear the buffer external pointer Clear time Clear t ' Clear Outbuffer ' Tx ' Clear OutIdxIn ' Clear OutIdxOut Set TimVals ' array ' Clear DataBuffer ' ADC ' Clear DataInIdx ' Clear DataOutIdx Clear tuneSword1 Clear tuneSword2 Clear tuneSword3 GoSub PWM_Lookup_Pi ' 03.03.2017 now using a square root table for smoothness GoSub Controller_Init_Prog0 ' default controller settings un startup: GoSub Precision_lookup ' equal temperament, with prescalers set to 0 Clear CC21 ' tuning range for linear interpollation ' note: the same range variable could also be used to implement vibrato $ifdef Board126_127 range = (Period[note1] - Period[note2]) / 2 ' tuning range for microtuning ' 285 / 2 = 142 ca. quartertone $else range = ((Period[note1] - Period[note2]) + (Period[note2] - Period[note3])) / 4 $endif GoTo MAIN ' jump over irq's Interrupt_handling: ' ------------------- Isr- T1Interrupt ' timer1 interrupt Clear IFS0bits_T1IF ' Reset the Timer1 interrupt flag ' used for pitch generator1 Clear TMR1 ' this is required! If Note_Port1 = 0 Then PR1 = On1 Set Note_Port1 Else PR1 = Of1 - jitter Clear Note_Port1 EndIf EndIsr- ' exit the interrupt Isr- T3Interrupt Clear IFS0bits_T3IF ' 32-bit value reached (T2/T3 combined) ' this is our main timer! EndIsr- Isr- T4Interrupt Clear IFS1bits_T4IF '16-bit value reached Clear TMR4 If Note_Port2 = 0 Then PR4 = On2 Set Note_Port2 Else PR4 = Of2 - jitter Clear Note_Port2 EndIf EndIsr- Isr- T5Interrupt Clear IFS1bits_T5IF ' 32-bit value reached if T4/T5 operation ib 32 bits ' 16-bit value reached if operated alone. Clear TMR5 If Note_Port3 = 0 Then PR5 = On3 Set Note_Port3 Else PR5 = Of3 - jitter Clear Note_Port3 EndIf 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 'Toggle midi_led 'debug 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 EndIf If U1STA.1 = 1 Then ' = overrun error 'Set overrun_error_led ' not happening Clear U1STA.1 EndIf EndIsr- Isr- U1TXInterrupt ' UART send IRQ Clear IFS0bits_U1TXIF ' 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 ' Toggle PORTA.1 ' for testing sampling rate - 04.08.2016: gives 58.82 kHz ' this means 8.5 us for each conversion 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 GetADC: ' here we can perform data extraction and signal conditioning ' the data-buffer has 256 words and covers 2.176ms of time. Return MAIN: While ' timer23 version: ' overflows after 5 hours. time.Word0 = TMR2 ' time is a dword var time.Word1 = TMR3HLD ' resolution is 4.224 us $ifdef Enable_UART_RX ' if receiver is enabled 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 '= 255 Set pres '= 255 Case Control_Status ' controllers and switches statusbyte = Bytein Set Ctrl Set value Case ProgChange_Status ' could be used for different lookup tables statusbyte = Bytein Set prog '= 255 ' Case Aftertouch_Status ' not used on this board ' statusbyte = Bytein ' Set aft ' Case Pitchbend_Status ' used for saw bending positioning ' statusbyte = Bytein ' Set pblsb '= 255 ' Set pbmsb '= 255 EndSelect Else 'midi byte is 7 bits Select statusbyte Case 0 'not a message for this channel GoTo Midi_Parse_done '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 ' coding with 3 ADRS's and fixed pwm channels Case note1 Clear ADSR1_flags ' reset all flags = 0 If release > 0 Then Release1_Time.Byte1 = release << 1 EndIf If Release1_Time > 0 Then Set Release1_flag ' clear PDC1 performed at the end of the release cycle = 64 Rstepval1 = Release1_Time / (Sustain1_level + 1 ) ' sustain_level mag niet 0 zijn! TimVals[0] = time + Rstepval1 ' starts timer Else ' perform a noteoff - no release phase Set TimVals[0] ' cancel timer Clear PDC1 ' stop adsr - volume to zero Clear IEC0bits_T1IE ' disable timer1 interrupt - tone generator Clear IFS0bits_T1IF ' clear interrupt flag Clear Note_Port1 EndIf Set resort_flag Case note2 Clear ADSR2_flags If release > 0 Then Release2_Time.Byte1 = release << 1 EndIf If Release2_Time > 0 Then Set Release2_flag ' clear PDC2 performed at the end of the release cycle Rstepval2 = Release2_Time / (Sustain2_level + 1) TimVals[1] = time + Rstepval2 Else ' perform a noteoff - no release phase Set TimVals[1] Clear PDC2 ' stop adsr Clear IEC1bits_T4IE ' disable timer4 interrupt Clear IFS1bits_T4IF ' clear interrupt flag Clear Note_Port2 EndIf Set resort_flag Case note3 Clear ADSR3_flags If release > 0 Then Release3_Time.Byte1 = release << 1 EndIf If Release3_Time > 0 Then Set Release3_flag ' clear PDC3 performed at the end of the release cycle Rstepval3 = Release3_Time / (Sustain3_level + 1) TimVals[2] = time + Rstepval3 Else ' perform a noteoff - no release phase Set TimVals[2] Clear PDC3 ' stop volume Clear IEC1bits_T5IE ' disable timer5 interrupt Clear IFS1bits_T5IF ' clear interrupt flag Clear Note_Port3 EndIf Set resort_flag EndSelect Set noteUit 'reset EndIf Case NoteOn_Status If noteAan = 255 Then noteAan = Bytein Else velo = Bytein If velo = 0 Then ' note off via velo=0 Select noteAan Case note1 Clear ADSR1_flags If Release1_Time > 0 Then Set Release1_flag ' clear PDC1 performed at the end of the release cycle Rstepval1 = Release1_Time / (Sustain1_level + 1) TimVals[0] = time + Rstepval1 Else ' perform a noteoff - no release phase Set TimVals[0] ' clear timer Clear PDC1 ' stop volume Clear IEC0bits_T1IE ' disable timer1 interrupt Clear IFS0bits_T1IF ' clear interrupt flag Clear Note_Port1 EndIf Set resort_flag Case note2 Clear ADSR2_flags If Release2_Time > 0 Then Set Release2_flag ' clear PDC2 performed at the end of the release cycle Rstepval2 = Release2_Time / (Sustain2_level + 1) TimVals[1] = time + Rstepval2 Else ' perform a noteoff - no release phase Set TimVals[1] Clear PDC2 ' stop tone Clear IEC1bits_T4IE ' disable timer4 interrupt Clear IFS1bits_T4IF ' clear interrupt flag Clear Note_Port2 EndIf Set resort_flag Case note3 Clear ADSR3_flags If Release3_Time > 0 Then Set Release3_flag ' clear PDC3 performed at the end of the release cycle Rstepval3 = Release3_Time / (Sustain3_level + 1) TimVals[2] = time + Rstepval3 Else ' perform a noteoff - no release phase Set TimVals[2] Clear PDC3 ' stop Clear IEC1bits_T5IE ' disable timer5 interrupt Clear IFS1bits_T5IF ' clear interrupt flag Clear Note_Port3 EndIf Set resort_flag EndSelect Else Select noteAan Case note1 Attack1_level = velo + Sustain1_level ' here velo is always > 0 If Attack1_level > 127 Then Attack1_level = 127 Clear ADSR1_flags ' program timer1 as frequency generator Clear IEC0bits_T1IE ' disable IRQ Clear Note_Port1 period1 = Period[note1] - tuneSword1 ' tunesword is bipolar and depends on range On1 = period1 * dutcy1 Of1 = period1 - On1 Clear IFS0bits_T1IF ' clear irq flag Set IEC0bits_T1IE ' enable timer1 interrupt ' now use the pwm1 channel for the ADSR Clear PDC1 ' start from volume = 0 Attack1_flag = 1 ' Set Attack1_flag ' = 1 Astepval1 = Attack1_time / Attack1_level ' start faze 1 van de ADSR ' bereken alvast de waarden die na de attack moeten volgen: If Attack1_level <> Sustain1_level Then Dstepval1 = Decay1_time / Abs(Attack1_level - Sustain1_level) Else Clear Dstepval1 EndIf TimVals[0] = time + Astepval1 Set resort_flag Case note2 Attack2_level = velo + Sustain2_level If Attack2_level > 127 Then Attack2_level = 127 Clear ADSR2_flags Clear IEC1bits_T4IE ' disable irq Clear Note_Port2 ' program timer4 as frequency generator period2 = Period[note2] - tuneSword2 On2 = period2 * dutcy2 Of2 = period2 - On2 Clear IFS1bits_T4IF ' clear IRQ flag Set IEC1bits_T4IE ' enable timer4 interrupt ' now use the pwm2 channel for the ADSR Clear PDC2 ' start from volume = 0 Attack2_flag = 1 'Set Attack2_flag Astepval2 = Attack2_time / Attack2_level If Attack2_level <> Sustain2_level Then Dstepval2 = Attack2_time / Abs(Attack2_level - Sustain2_level) Else Clear Dstepval2 EndIf TimVals[1] = time + Astepval2 Set resort_flag Case note3 Attack3_level = velo + Sustain3_level If Attack3_level > 127 Then Attack3_level = 127 Clear ADSR3_flags ' program timer5 as frequency generator Clear IEC1bits_T5IE ' disable timer5 interrupt Clear Note_Port3 period3 = Period[note3] - tuneSword3 On3 = period3 * dutcy3 Of3 = period3 - On3 Clear IFS1bits_T5IF ' clear irq flag Set IEC1bits_T5IE ' enable timer5 interrupt ' now use the pwm3 channel for the ADSR Clear PDC3 ' start from volume = 0 Attack3_flag = 1 ' =Set Attack3_flag Astepval3 = Attack3_time / Attack3_level If Attack3_level <> Sustain3_level Then Dstepval3 = Attack3_time / Abs(Attack3_level - Sustain3_level) Else Clear Dstepval3 EndIf TimVals[2] = time + Astepval3 Set resort_flag EndSelect Set noteAan '= 255 EndIf EndIf Case Keypres_Status If notePres = 255 Then notePres = Bytein Else pres = Bytein GoSub KeyPres EndIf Case Control_Status 'this is where the action takes place for controllers If Ctrl = 255 Then Ctrl = Bytein Else value = Bytein GoSub Controller EndIf Case ProgChange_Status If prog = 255 Then 'single byte message prog = Bytein GoSub ProgChange EndIf Case Aftertouch_Status If aft = 255 Then aft = Bytein GoSub Aftertouch EndIf Case Pitchbend_Status If pblsb = 255 Then pblsb = Bytein Else pbmsb = Bytein GoSub Pitchbend EndIf EndSelect EndIf $endif Midi_Parse_done: If resort_flag= 1 Then GoSub SortTimers EndIf Check_Timers: If idx < NrTasks Then ' we moeten alleen checken wanneer er een timer loopt If time >= Nxt Then ' nagaan of de eerstvolgende timer afgelopen is... ' in dit geval is de eerste timer afgelopen en moeten we de juiste aktie ondernemen: Set Nxt.31 ' timer reset, is immers afgelopen ' aan de hand van idx weten we welke timer dit is Select idx Case 0 ' noot1 adsr Select ADSR1_flags Case 1 ' if we get here, the first attack steptime has passed ' = Attack1_flag Clear cnt1 ADSR1_flags = 2 ' = Attack1_tog TimVals[0] = time + Astepval1 Case 2 ' = Attack1_flag + Attack1_tog If cnt1 < Attack1_level Then Inc cnt1 ' increase volume until attack_level reached PDC1 = Ont[cnt1] TimVals[0] = time + Astepval1 ' calculated on reception of note-on Else ' attack level reached Clear ADSR1_flags ' becomes 0 Select Attack1_level Case Sustain1_level ' no decay phase required Set TimVals[0] ' clear timer cnt1 = Sustain1_level Case > Sustain1_level Set Decay1_flag ' becomes 4 cnt1= Attack1_level ' start value for the decay ' steps calculated on reception of note-on PDC1 = Ont[cnt1] TimVals[0] = time + Dstepval1 Case Else ' attack level <= sustain level Set Decay1_tog ' further increase flag... becomes 8 cnt1 = Attack1_level PDC1 = Ont[cnt1] TimVals[0] = time + Dstepval1 EndSelect EndIf Case 4 ' decay flag is set, downwards decay Dec cnt1 PDC1 = Ont[cnt1] TimVals[0] = time + Dstepval1 If cnt1 = Sustain1_level Then Clear ADSR1_flags ' Decay1_flag ' becomes 0 Set TimVals[0] ' cancel the timer EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt1 PDC1 = Ont[cnt1] TimVals[0] = time + Dstepval1 If cnt1 = Sustain1_level Then Clear ADSR1_flags 'Decay1_tog ' becomes 0 Set TimVals[0] ' cancel timer EndIf Case 64 ' release flag is set - set in the note-off command cnt1 = Sustain1_level PDC1 = Ont[cnt1] ' ? required, added 20.09.2016 ADSR1_flags = 128 ' Set Release1_tog ' becomes 192 = 128 + 64 TimVals[0] = time + Rstepval1 ' stepval calculated at note-off time Case 128 ' 192 ' release-phase If cnt1 > 0 Then Dec cnt1 PDC1 = Ont[cnt1] TimVals[0] = time + Rstepval1 Else ' if we get here, release time has passed Clear ADSR1_flags ' Release1_flag Clear PDC1 ' so we can switch off the volume Clear TMR1 ' stop tone generator Clear IEC0bits_T1IE ' disable timer1 interrupt Clear IFS0bits_T1IF ' clear interrupt flag Clear Note_Port1 ' zero out Set TimVals[0] ' clear timer EndIf EndSelect Case 1 ' noot2 adsr Select ADSR2_flags Case 1 ' if we get here, the first attack steptime has passed Clear cnt2 ADSR2_flags = 2 'Set Attack2_tog ' now becomes = 3 TimVals[1] = time + Astepval2 Case 2 If cnt2 < Attack2_level Then Inc cnt2 ' increase volume until attack_level reached PDC2 = Ont[cnt2] TimVals[1] = time + Astepval2 Else ' attack level reached Clear ADSR2_flags ' becomes 0 If Attack2_level = Sustain2_level Then ' no decay phase required Set Sustain2_flag ' = 16 Set TimVals[1] cnt2 = Sustain2_level EndIf If Attack2_level > Sustain2_level Then Set Decay2_flag ' becomes 4 cnt2= Attack2_level ' start value for the decay PDC2 = Ont[cnt2] TimVals[1] = time + Dstepval2 Else ' attack level <= sustain level Set Decay2_tog ' further increase flag... becomes 8 cnt2 = Attack2_level PDC2 = Ont[cnt2] TimVals[1] = time + Dstepval2 EndIf EndIf Case 4 ' decay flag is set Dec cnt2 PDC2 = Ont[cnt2] TimVals[1] = time + Dstepval2 If cnt2 = Sustain2_level Then Clear Decay2_flag ' becomes 0 Set Sustain2_flag ' value becomes 16 now ' shouldn't we cancel the timer now? Set TimVals[1] EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt2 PDC2 = Ont[cnt2] TimVals[1] = time + Dstepval2 If cnt2 = Sustain2_level Then Clear Decay2_tog ' becomes 0 Set Sustain2_flag ' becomes 16 Set TimVals[1] EndIf Case 64 ' release flag is set cnt2 = Sustain2_level PDC2 = Ont[cnt2] ADSR2_flags = 128 'Set Release2_tog ' becomes 192 TimVals[1] = time + Rstepval2 Case 128 ' release-phase If cnt2 > 0 Then Dec cnt2 PDC2 = Ont[cnt2] TimVals[1] = time + Rstepval2 Else ' if we get here, release time has passed Clear ADSR2_flags ' Release1_flag Clear PDC2 ' so we can switch off the volume Clear TMR4 ' stop tone generator Clear IEC1bits_T4IE ' disable timer4 interrupt Clear IFS1bits_T4IF ' clear interrupt flag Clear Note_Port2 Set TimVals[1] EndIf EndSelect Case 2 ' noot3 adsr Select ADSR3_flags Case 1 ' if we get here, the first attack steptime has passed Clear cnt3 ADSR3_flags = 2 'Set Attack3_tog ' now becomes = 3 TimVals[2] = time + Astepval3 Case 2 If cnt3 < Attack3_level Then Inc cnt3 ' increase volume until attack_level reached PDC3 = Ont[cnt3] TimVals[2] = time + Astepval3 Else ' attack level reached Clear ADSR3_flags ' becomes 0 If Attack3_level = Sustain3_level Then ' no decay phase required Set Sustain3_flag ' = 16 Set TimVals[2] cnt3 = Sustain3_level EndIf If Attack3_level > Sustain3_level Then Set Decay3_flag ' becomes 4 cnt3= Attack3_level ' start value for the decay PDC3 = Ont[cnt3] TimVals[2] = time + Dstepval3 Else ' attack level <= sustain level Set Decay3_tog ' further increase flag... becomes 8 cnt3 = Attack3_level PDC3 = Ont[cnt3] TimVals[2] = time + Dstepval3 EndIf EndIf Case 4 ' decay flag is set Dec cnt3 PDC3 = Ont[cnt3] TimVals[2] = time + Dstepval3 If cnt3 = Sustain3_level Then Clear Decay3_flag ' becomes 0 Set Sustain3_flag ' value becomes 16 now ' shouldn't we cancel the timer now? Set TimVals[2] EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt3 PDC3 = Ont[cnt3] TimVals[2] = time + Dstepval3 If cnt3 = Sustain3_level Then Clear Decay3_tog ' becomes 0 Set Sustain3_flag ' becomes 16 Set TimVals[2] EndIf Case 64 ' release flag is set cnt3 = Sustain3_level PDC3 = Ont[cnt3] ADSR3_flags = 128 'Set Release3_tog ' becomes 192 TimVals[2] = time + Rstepval3 Case 128 ' release-phase If cnt3 > 0 Then Dec cnt3 PDC3 = Ont[cnt3] TimVals[2] = time + Rstepval3 Else ' if we get here, release time has passed Clear ADSR3_flags ' Release1_flag Clear PDC3 ' so we can switch off the volume Clear TMR5 ' stop tone generator Clear IEC1bits_T5IE ' disable timer5 interrupt Clear IFS1bits_T5IF ' clear interrupt flag Clear Note_Port3 Set TimVals[2] EndIf EndSelect 'Case Else ' ' in dit geval is idx geset ' GoTo jumpout EndSelect GoSub SortTimers ' find a new nxt and idx EndIf ' beveiliging tegen overflow crashes... If maxtim = 1 Then Clear time Clear TMR2 Clear TMR3HLD Set TimVals EndIf Else ' no timers running, so to avoid overflows, we can reset the loop timer If maxtim = 1 Then Clear time ' 16.06.2015 Clear TMR2 ' 07.08.2016 Clear TMR3HLD EndIf EndIf $ifdef Enable_UART_TX ' not defined in this code Midi_OutPut: If OutIdxOut <> OutIdxIn Then ' in dit geval is er een byte te versturen If IFS0bits_U1TXIF = 0 Then Inc OutIdxOut U1TXREG = Outbuffer[OutIdxOut] EndIf EndIf $endif jit_algo: ' for Ctrl#1 implementation j = Random & C1val ' 0 - 254, with mask so range will be 0 - C1val ' now 0 - 1023 jitter = (C1val >> 1) - j ' make it bipolar - 512 -> + 511 ' -128 -> 127 'Toggle loopcnt ' for loopspeed measurement: 1.3us now ' 10.08.2016: 366kHz met alle taken aan, 440kHz onbelast watchdog_led = time.16 ' this is the red LED on each PIC. Wend SortTimers: 'look up the next smallest timer value in the Timvals array ' zoek de de volgende kleinste timer waarde: Set idx ' makes it 255 Set Nxt.31 ' nxt is set on entry. - for speed, we just set the highest bit For i = 0 To 2 If TimVals[i] < Nxt Then Nxt = TimVals[i] ' 3 dword comparisons idx = i EndIf Next i Clear resort_flag Return ' ************************************************************************************** ' procedures for midi receiver: KeyPres: ' can be used to modulate the wave shape ' 10.10.2016: rewritten avoiding floats... ' this makes no sense on Pi ' Select notePres ' Case note1 ' bdutcy1 = pres + 1 ' On1 = note1_period.Byte1 * bdutcy1 ' Of1 = note1_period - On1 ' Case note2 ' bdutcy2 = pres + 1 ' On2 = note2_period.Byte1 * bdutcy2 ' Of2 = note2_period - On2 ' Case note3 ' bdutcy3 = pres + 1 ' On3 = note3_period.Byte1 * bdutcy3 ' Of3 = note3_period - On3 ' EndSelect Set notePres '= 255 Return ProgChange: ' Presets would also be possible to change the tuning... Select prog Case 0 'reset controllers to cold boot values GoSub Controller_Init_Prog0 ' Case 1 ' place for many more presets ' GoSub Preset1 ' Case 2 ' GoSub Preset2 ' Case 3 ' GoSub Preset3 ' Case 4 ' GoSub Preset4 ' Case 5 ' GoSub Preset5 ' Case 6 ' GoSub Preset6 ' Case 7 ' GoSub Preset7 EndSelect Set prog '= 255 'this is not realy required 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 Controller: Select Ctrl Case 1 'C1bit, C1val - introduced 13.10.2016 for HybrLo 'pitched noise generator C1val = value << 3 ' 0- 1023 '0-254 C1bit = Ncd value ' returns 0-8 'Priority encoder of a 16-bit or 32-bit value. Ncd takes a value, finds the highest bit containing a '1 and returns the bit position plus one (1 through 32). If no bit is set, the input value is 0. Ncd 'returns 0. Ncd is a fast way to get an answer to the question "what is the largest power of two 'that this value is greater than or equal to?" The answer that Ncd returns will be that power, plus 'one. Case 7 ' global sustain level controller 'CC7 = value ' needs remapping on a 16-bit log scale Sustain1_level = value Sustain2_level = value Sustain3_level = value Case 15 ' global waveform control - also done for individual notes with keypres ' note that using this controller it is not possible to change the waveform whilst the note is sounding. ' If that is required, use the key pressure commands. Inc value ' 0 crashes the system... dutcy1 = value / 256 ' 0 - 0.5 dutcy2 = dutcy1 dutcy3 = dutcy1 ' made pitch dependent for boards 3 and 4 , 07.03.2017: $ifdef Board108_110 dutcy1 = 0.1 + (dutcy1 / 1.25) dutcy2 = dutcy1 dutcy3 = dutcy1 $endif $ifdef Board111_113 dutcy1 = 0.2 + (dutcy1 / 1.666) dutcy2 = dutcy1 dutcy3 = dutcy1 $endif $ifdef Board114_116 dutcy1 = 0.25 + (dutcy1 / 2) dutcy2 = dutcy1 dutcy3 = dutcy1 $endif $ifdef Board117_119 dutcy1 = 0.3 + (dutcy1 / 2.5) dutcy2 = dutcy1 dutcy3 = dutcy1 $endif $ifdef Board120_122 dutcy1 = 0.4 + (dutcy1 / 5) ' 0.4 - o.5 dutcy2 = dutcy1 dutcy3 = dutcy1 $endif $ifdef Board123_125 dutcy1 = 0.45 + (dutcy1 / 10) ' 0.45 - 0.5 dutcy2 = dutcy1 dutcy3 = dutcy1 $endif $ifdef Board126_127 dutcy1 = 0.5 dutcy2 = 0.5 dutcy3 = 0.5 $endif Case 17 ' global attack time control Attack1_time.Byte1 = value Attack2_time = Attack1_time Attack3_time = Attack1_time Case 18 ' global decay time control Decay1_time.Byte1 = value Decay2_time = Decay1_time Decay3_time = Decay1_time Case 19 ' global release time control ' 09.03.2017: values doubled. Release1_Time.Byte1 = value << 1 Release2_Time = Release1_Time Release3_Time = Release1_Time Case 21 ' used to change the tuning lookup's If value <> CC21 Then ' avoiding multiple reads of lookups Select value Case 0 ' equal temperament GoSub Precision_lookup Case 12 ' just intonation, base C GoSub JI_C Case 13 GoSub JI_Db Case 14 GoSub JI_D Case 15 GoSub JI_Eb Case 16 GoSub JI_E Case 17 GoSub JI_F Case 18 GoSub JI_Gb Case 19 GoSub JI_G Case 20 GoSub JI_Ab Case 21 GoSub JI_A Case 22 GoSub JI_Bb Case 23 GoSub JI_B EndSelect CC21 = value EndIf Case 66 'on/off for the robot If value = 0 Then ' power down GoSub PowerDown ' should reset controllers Low PORTB.6 ' relay should release Else High PORTB.6 ' enable relay EndIf Case tun1 ' symbol ' by default these controllers are 64. ' normalize to 0-1: fraction = (value / 128.0) - 0.5 ' 0-1 - 0.492 f is declared as float ' -0.5 --- + 0.492 tuneSword1 = fraction * range ' try using integer math only: 'tunesword1 = (range * (value - 64)) / 128 Case tun2 fraction = (value / 128.0) - 0.5 tuneSword2 = fraction * range 'tunesword2 = (range * (value - 64)) / 128 $ifndef Board126_127 Case tun3 ' exception for the LED light, as tun3 is not defined. fraction = (value / 128.0) - 0.5 tuneSword3 = fraction * range 'tunesword3 = (range * (value - 64)) / 128 $endif Case 123 GoSub AllNotesOff EndSelect Set Ctrl 'mandatory reset Return AllNotesOff: ' all notes off - no controller resets Clear PDC1 Clear PDC2 Clear PDC3 Clear IEC0bits_T1IE ' disable the Timer1 interrupt Clear IEC1bits_T4IE ' disable timer4 Clear IEC1bits_T5IE ' disable timer5 Clear Note_Port1 Clear Note_Port2 Clear Note_Port3 Clear ADSR1_flags Clear ADSR2_flags Clear ADSR3_flags Set resort_flag For i = 0 To 2 'NrTasks -1 Set TimVals[i] ' stop timers Next i Return PowerDown: Set resort_flag For i = 0 To 2 'NrTasks -1 Set TimVals[i] Next i Clear PDC1 Clear PDC2 Clear PDC3 Clear IEC0bits_T1IE ' disable the Timer1 interrupt Clear IEC1bits_T4IE ' disable Timer4 irq Clear IEC1bits_T5IE ' disable Timer5 irq Low Note_Port1 Low Note_Port2 Low Note_Port3 Clear ADSR1_flags Clear ADSR2_flags Clear ADSR3_flags GoSub Controller_Init_Prog0 ' set the defaults ' reset the tuning tuneSword1 = 0 ' sword! -64 to +63 tuneSword2 = 0 tuneSword3 = 0 GoSub Precision_lookup ' reset to equal temperament Return Controller_Init_Prog0: ' reset controllers to default start-up values: Attack1_time.Byte1 = 8 Decay1_time.Byte1 = 6 Sustain1_level = 96 ' set with CC7 Release1_Time.Byte1 = 10 ' set with release byte or ctrl 19 tuneSword1 = 0 dutcy1 = 0.5 ' 0-0.5 Attack2_time = Attack1_time Decay2_time = Decay1_time Sustain2_level = Sustain1_level Release2_Time = Release1_Time tuneSword2 = 0 dutcy2 = 0.5 Attack3_time = Attack1_time Decay3_time = Decay1_time Sustain3_level = Sustain1_level Release3_Time = Release1_Time tuneSword3 = 0 dutcy3 = 0.5 Clear C1val ' reset ctrl#1 (0-1024) Return 'Dur_Lookup: ''lookup for experiment. 1 dur unit is now 2.3us with loopcounter ''using timer23, 1 dur unit is 4.224 us 'Set Dur[0] 'Dur[1]= 23674 ' 03.08.2016: 56ms ' ' 04.08/2016: 66.2ms - 7.55 Hz ' ' 07.08.2016: 2x100ms = 200ms full period --> 5Hz [o.k.14.08.2016] 'Dur[2]= 22917 ' freq= 2.18178644674259 'Dur[3]= 22548 ' freq= 2.21749157353202 'Dur[4]= 22185 ' freq= 2.25377507324769 'Dur[5]= 21827 ' freq= 2.29074082558299 'Dur[6]= 21475 ' freq= 2.32828870779977 'Dur[7]= 21129 ' freq= 2.36641582658905 'Dur[8]= 20789 ' freq= 2.40511809129828 'Dur[9]= 20454 ' freq= 2.44450963136795 'Dur[10]= 20124 ' freq= 2.48459550785132 'Dur[11]= 19800 ' freq= 2.52525252525252 'Dur[12]= 19481 ' freq= 2.56660335711719 'Dur[13]= 19167 ' freq= 2.60865028434288 'Dur[14]= 18858 ' freq= 2.65139463357726 'Dur[15]= 18554 ' freq= 2.69483669289641 'Dur[16]= 18255 ' freq= 2.73897562311695 'Dur[17]= 17961 ' freq= 2.7838093647347 'Dur[18]= 17672 ' freq= 2.82933454051607 'Dur[19]= 17387 ' freq= 2.87571173865532 'Dur[20]= 17107 ' freq= 2.92278014847723 'Dur[21]= 16831 ' freq= 2.97070881112233 'Dur[22]= 16560 ' freq= 3.01932367149758 'Dur[23]= 16293 ' freq= 3.06880255324372 'Dur[24]= 16030 ' freq= 3.11915159076731 'Dur[25]= 15772 ' freq= 3.17017499365965 'Dur[26]= 15518 ' freq= 3.22206469905916 'Dur[27]= 15268 ' freq= 3.27482315954938 'Dur[28]= 15022 ' freq= 3.32845160431367 'Dur[29]= 14780 ' freq= 3.382949932341 'Dur[30]= 14542 ' freq= 3.43831660019254 'Dur[31]= 14307 ' freq= 3.4947927587894 'Dur[32]= 14077 ' freq= 3.55189315905378 'Dur[33]= 13850 ' freq= 3.6101083032491 'Dur[34]= 13627 ' freq= 3.66918617450649 'Dur[35]= 13407 ' freq= 3.72939509211606 'Dur[36]= 13191 ' freq= 3.79046319460238 'Dur[37]= 12978 ' freq= 3.85267375558638 'Dur[38]= 12769 ' freq= 3.91573341686898 'Dur[39]= 12564 ' freq= 3.97962432346386 'Dur[40]= 12361 ' freq= 4.04498017959712 'Dur[41]= 12162 ' freq= 4.1111659266568 'Dur[42]= 11966 ' freq= 4.17850576633796 'Dur[43]= 11773 ' freq= 4.24700586086809 'Dur[44]= 11583 ' 07.08.2016: geeft 10.1177 Hz 'Dur[45]= 11397 ' freq= 4.38711941739054 'Dur[46]= 11213 ' freq= 4.45910996165165 'Dur[47]= 11032 ' freq= 4.53226976069616 'Dur[48]= 10855 ' freq= 4.60617227084293 'Dur[49]= 10680 ' freq= 4.6816479400749 'Dur[50]= 10508 ' freq= 4.75827940616673 'Dur[51]= 10338 ' freq= 4.83652544012381 'Dur[52]= 10172 ' freq= 4.91545418796697 'Dur[53]= 10008 ' freq= 4.99600319744204 'Dur[54]= 9846 ' freq= 5.07820434694292 'Dur[55]= 9688 ' freq= 5.16102394715111 'Dur[56]= 9532 ' freq= 5.24548887956357 'Dur[57]= 9378 ' freq= 5.33162721262529 'Dur[58]= 9227 ' freq= 5.4188793757451 'Dur[59]= 9078 ' freq= 5.50782110597048 'Dur[60]= 8932 ' freq= 5.59785042543663 'Dur[61]= 8788 ' freq= 5.68957669549385 'Dur[62]= 8646 ' freq= 5.78302105019662 'Dur[63]= 8507 ' 04.08.2016: 21Hz pulse duur = 23.8ms 'Dur[64]= 8370 ' geeft nu 20ms pulsen freq= 25Hz 03.08.2016 ' ' 14.0017Hz 07.08.2016 'Dur[65]= 8235 ' freq= 6.07164541590771 'Dur[66]= 8102 ' freq= 6.17131572451246 'Dur[67]= 7972 ' freq= 6.27195183140993 'Dur[68]= 7843 ' freq= 6.37511156445238 'Dur[69]= 7717 ' freq= 6.47920176234288 'Dur[70]= 7593 ' freq= 6.58501251152377 'Dur[71]= 7470 ' freq= 6.69344042838019 'Dur[72]= 7350 ' freq= 6.80272108843537 'Dur[73]= 7231 ' freq= 6.91467293597013 'Dur[74]= 7115 ' freq= 7.02740688685875 'Dur[75]= 7000 ' freq= 7.14285714285714 'Dur[76]= 6888 ' freq= 7.25900116144018 'Dur[77]= 6777 ' freq= 7.37789582411096 'Dur[78]= 6667 ' freq= 7.49962501874906 'Dur[79]= 6560 ' freq= 7.62195121951219 'Dur[80]= 6454 ' freq= 7.74713356058258 'Dur[81]= 6350 ' freq= 7.8740157480315 'Dur[82]= 6248 ' freq= 8.00256081946223 'Dur[83]= 6147 ' freq= 8.13404912965674 'Dur[84]= 6048 ' freq= 8.26719576719577 'Dur[85]= 5951 ' freq= 8.40194925222652 'Dur[86]= 5855 ' freq= 8.5397096498719 'Dur[87]= 5760 ' freq= 8.68055555555555 'Dur[88]= 5668 ' freq= 8.82145377558222 'Dur[89]= 5576 ' freq= 8.96700143472023 'Dur[90]= 5486 ' freq= 9.11410864017499 'Dur[91]= 5398 ' freq= 9.26268988514264 'Dur[92]= 5311 ' freq= 9.41442289587648 'Dur[93]= 5225 ' freq= 9.56937799043062 'Dur[94]= 5141 ' freq= 9.72573429293912 'Dur[95]= 5058 ' freq= 9.88533017002768 'Dur[96]= 4977 ' freq= 10.0462125778581 'Dur[97]= 4897 ' freq= 10.2103328568511 'Dur[98]= 4818 ' freq= 10.3777501037775 'Dur[99]= 4740 ' freq= 10.548523206751 'Dur[100]= 4664 ' freq= 10.7204116638079 'Dur[101]= 4589 ' freq= 10.8956199607758 'Dur[102]= 4515 ' freq= 11.0741971207087 'Dur[103]= 4442 ' freq= 11.2561909049977 'Dur[104]= 4370 ' freq= 11.441647597254 'Dur[105]= 4300 ' freq= 11.6279069767442 'Dur[106]= 4231 ' freq= 11.8175372252422 'Dur[107]= 4162 ' freq= 12.013455069678 'Dur[108]= 4095 ' freq= 12.2100122100122 'Dur[109]= 4029 ' freq= 12.4100273020601 'Dur[110]= 3964 ' freq= 12.6135216952573 'Dur[111]= 3901 ' freq= 12.8172263522174 'Dur[112]= 3838 ' freq= 13.0276185513288 'Dur[113]= 3776 ' freq= 13.2415254237288 'Dur[114]= 3715 ' freq= 13.4589502018842 'Dur[115]= 3655 ' freq= 13.6798905608755 'Dur[116]= 3596 ' freq= 13.9043381535039 'Dur[117]= 3538 ' freq= 14.1322781232335 'Dur[118]= 3481 ' freq= 14.3636885952312 'Dur[119]= 3425 ' freq= 14.5985401459854 'Dur[120]= 3370 ' freq= 14.8367952522255 'Dur[121]= 3316 ' freq= 15.0784077201448 'Dur[122]= 3262 ' freq= 15.3280196198651 'Dur[123]= 3210 ' freq= 15.5763239875389 'Dur[124]= 3158 ' freq= 15.8328055731476 'Dur[125]= 3107 ' freq= 16.0926939169617 'Dur[126]= 3057 ' freq= 16.3559044815178 = 38.3365Hz 07.08.2016 'Dur[127]= 3008 ' 03.08.2016: 6.9ms nu = 144Hz ' ' 04.08.2016: 8.35ms - 59.5Hz 'Return PWM_Lookup_Pi: ' new scaling for Pi ' it makes the ADSR work pretty smoothly. ' 9 bits resolution as PTPER is set to 512 For i = 1 To 127 Ont[i] = Sqr(i) * 45.43 ' scaling factor= 512 / SQR(127) Next i Ont[127] = 511 ' = PTPER ' was bug before 24.12.2020, as we had it set to 512 Ont[0] = 0 Return ' Lookup tables for the tuning: Precision_lookup: ' equal temperament: ' midi-note to period lookup for PIC24 with 120MHz clock ' time_unit = 8.33333333333333E-9 ' only valid for timer dividers set to = 1 ' lowest possible note = midi 82 ' with compensation for processing speed in the ISR ' period = (( 1/freq) - t)/ k ' k = time_unit = 1/ 60E6 ' t = ISR time, 1.3 us ' midi-note to period lookup for PIC24 with 120MHz clock ' time_unit = 1.66666666666667E-8 ' divider set to = 1 ' ISR time = 1.3 us ' with this setting errors are < 0.02% 'EQ_Lookup: Period[84]= 57256 ' soll frequency = 1047 Period[85]= 54038 ' soll frequency = 1109 Period[86]= 51000 ' soll frequency = 1175 Period[87]= 48134 ' soll frequency = 1245 Period[88]= 45428 ' soll frequency = 1319 Period[89]= 42874 ' soll frequency = 1397 Period[90]= 40463 ' soll frequency = 1480 Period[91]= 38188 ' soll frequency = 1568 Period[92]= 36040 ' soll frequency = 1661 Period[93]= 34013 ' soll frequency = 1760 Period[94]= 32099 ' soll frequency = 1865 Period[95]= 30293 ' soll frequency = 1976 Period[96]= 28589 ' soll frequency = 2093 Period[97]= 26980 ' soll frequency = 2217 Period[98]= 25461 ' soll frequency = 2349 Period[99]= 24028 ' soll frequency = 2489 Period[100]= 22675 ' soll frequency = 2637 Period[101]= 21398 ' soll frequency = 2794 Period[102]= 20192 ' soll frequency = 2960 Period[103]= 19055 ' soll frequency = 3136 Period[104]= 17981 ' soll frequency = 3322 Period[105]= 16967 ' soll frequency = 3520 Period[106]= 16011 ' soll frequency = 3729 Period[107]= 15108 ' soll frequency = 3951 Period[108]= 14255 ' soll frequency = 4186 Period[109]= 13451 ' soll frequency = 4435 Period[110]= 12691 ' soll frequency = 4699 Period[111]= 11975 ' soll frequency = 4978 Period[112]= 11298 ' soll frequency = 5274 Period[113]= 10660 ' soll frequency = 5588 Period[114]= 10057 ' soll frequency = 5920 Period[115]= 9488 ' soll frequency = 6272 Period[116]= 8951 ' soll frequency = 6645 Period[117]= 8445 ' soll frequency = 7040 Period[118]= 7966 ' soll frequency = 7459 Period[119]= 7515 ' soll frequency = 7902 Period[120]= 7089 ' soll frequency = 8372 Period[121]= 6686 ' soll frequency = 8870 Period[122]= 6307 ' soll frequency = 9397 Period[123]= 5948 ' soll frequency = 9956 Period[124]= 5610 ' soll frequency = 10548 Period[125]= 5291 ' soll frequency = 11175 Period[126]= 4989 ' soll frequency = 11840 Period[127]= 4705 ' soll frequency = 12544 Period[0] = 65535 ' dummy for light on board 4, note 0 Return JI_C: Period[84]= 57256 ' midi= 84 Period[85]= 53672 ' midi= 85.11732 Period[86]= 50885 ' midi= 86.0391 Period[87]= 47700 ' midi= 87.15641 Period[88]= 45789 ' midi= 87.86314 Period[89]= 42922 ' midi= 88.98045 Period[90]= 40693 ' midi= 89.90224 Period[91]= 38144 ' midi= 91.01955 Period[92]= 35755 ' midi= 92.13686 Period[93]= 34322 ' midi= 92.84359 Period[94]= 31774 ' midi= 94.17596 Period[95]= 30500 ' midi= 94.88269 Period[96]= 28589 ' midi= 96 Period[97]= 26797 ' midi= 97.11732 Period[98]= 25403 ' midi= 98.0391 Period[99]= 23811 ' midi= 99.15641 Period[100]= 22855 ' midi= 99.86314 Period[101]= 21422 ' midi= 100.9804 Period[102]= 20307 ' midi= 101.9022 Period[103]= 19033 ' midi= 103.0195 Period[104]= 17839 ' midi= 104.1369 Period[105]= 17122 ' midi= 104.8436 Period[106]= 15848 ' midi= 106.176 Period[107]= 15211 ' midi= 106.8827 Period[108]= 14255 ' midi= 108 Period[109]= 13359 ' midi= 109.1173 Period[110]= 12663 ' midi= 110.0391 Period[111]= 11866 ' midi= 111.1564 Period[112]= 11389 ' midi= 111.8631 Period[113]= 10672 ' midi= 112.9804 Period[114]= 10114 ' midi= 113.9022 Period[115]= 9477 ' midi= 115.0195 Period[116]= 8880 ' midi= 116.1369 Period[117]= 8522 ' midi= 116.8436 Period[118]= 7885 ' midi= 118.176 Period[119]= 7566 ' midi= 118.8827 Period[120]= 7089 ' midi= 120 Period[121]= 6641 ' midi= 121.1173 Period[122]= 6292 ' midi= 122.0391 Period[123]= 5894 ' midi= 123.1564 Period[124]= 5655 ' midi= 123.8631 Period[125]= 5297 ' midi= 124.9804 Period[126]= 5018 ' midi= 125.9022 Period[127]= 4700 ' midi= 127.0195 Return JI_Db: Period[84]= 57645 ' midi= 83.88268 Period[85]= 54038 ' midi= 85 Period[86]= 50655 ' midi= 86.11731 Period[87]= 48025 ' midi= 87.0391 Period[88]= 45018 ' midi= 88.15641 Period[89]= 43215 ' midi= 88.86314 Period[90]= 40509 ' midi= 89.98044 Period[91]= 38404 ' midi= 90.90224 Period[92]= 35999 ' midi= 92.01955 Period[93]= 33744 ' midi= 93.13686 Period[94]= 32391 ' midi= 93.84359 Period[95]= 29986 ' midi= 95.17596 Period[96]= 28784 ' midi= 95.88268 Period[97]= 26980 ' midi= 97 Period[98]= 25289 ' midi= 98.11731 Period[99]= 23973 ' midi= 99.0391 Period[100]= 22470 ' midi= 100.1564 Period[101]= 21568 ' midi= 100.8631 Period[102]= 20215 ' midi= 101.9804 Period[103]= 19163 ' midi= 102.9022 Period[104]= 17960 ' midi= 104.0195 Period[105]= 16833 ' midi= 105.1369 Period[106]= 16157 ' midi= 105.8436 Period[107]= 14954 ' midi= 107.176 Period[108]= 14353 ' midi= 107.8827 Period[109]= 13451 ' midi= 109 Period[110]= 12605 ' midi= 110.1173 Period[111]= 11948 ' midi= 111.0391 Period[112]= 11196 ' midi= 112.1564 Period[113]= 10745 ' midi= 112.8631 Period[114]= 10069 ' midi= 113.9804 Period[115]= 9542 ' midi= 114.9022 Period[116]= 8941 ' midi= 116.0195 Period[117]= 8377 ' midi= 117.1369 Period[118]= 8039 ' midi= 117.8436 Period[119]= 7438 ' midi= 119.176 Period[120]= 7137 ' midi= 119.8827 Period[121]= 6686 ' midi= 121 Period[122]= 6264 ' midi= 122.1173 Period[123]= 5935 ' midi= 123.0391 Period[124]= 5559 ' midi= 124.1564 Period[125]= 5333 ' midi= 124.8631 Period[126]= 4995 ' midi= 125.9804 Period[127]= 4732 ' midi= 126.9022 Return JI_D: Period[84]= 57385 ' midi= 83.9609 Period[85]= 54406 ' midi= 84.88269 Period[86]= 51000 ' midi= 86 Period[87]= 47808 ' midi= 87.11731 Period[88]= 45325 ' midi= 88.0391 Period[89]= 42487 ' midi= 89.15641 Period[90]= 40785 ' midi= 89.86314 Period[91]= 38231 ' midi= 90.98044 Period[92]= 36244 ' midi= 91.90224 Period[93]= 33974 ' midi= 93.01955 Period[94]= 31846 ' midi= 94.13686 Period[95]= 30569 ' midi= 94.84359 Period[96]= 28299 ' midi= 96.17596 Period[97]= 27164 ' midi= 96.88269 Period[98]= 25461 ' midi= 98 Period[99]= 23865 ' midi= 99.11731 Period[100]= 22623 ' midi= 100.0391 Period[101]= 21205 ' midi= 101.1564 Period[102]= 20353 ' midi= 101.8631 Period[103]= 19076 ' midi= 102.9804 Period[104]= 18083 ' midi= 103.9022 Period[105]= 16948 ' midi= 105.0195 Period[106]= 15884 ' midi= 106.1369 Period[107]= 15245 ' midi= 106.8436 Period[108]= 14110 ' midi= 108.176 Period[109]= 13543 ' midi= 108.8827 Period[110]= 12691 ' midi= 110 Period[111]= 11893 ' midi= 111.1173 Period[112]= 11273 ' midi= 112.0391 Period[113]= 10563 ' midi= 113.1564 Period[114]= 10138 ' midi= 113.8631 Period[115]= 9499 ' midi= 114.9804 Period[116]= 9002 ' midi= 115.9022 Period[117]= 8435 ' midi= 117.0195 Period[118]= 7903 ' midi= 118.1369 Period[119]= 7584 ' midi= 118.8436 Period[120]= 7016 ' midi= 120.176 Period[121]= 6732 ' midi= 120.8827 Period[122]= 6307 ' midi= 122 Period[123]= 5908 ' midi= 123.1173 Period[124]= 5597 ' midi= 124.0391 Period[125]= 5242 ' midi= 125.1564 Period[126]= 5030 ' midi= 125.8631 Period[127]= 4710 ' midi= 126.9804 Return JI_Eb: Period[84]= 57776 ' midi= 83.84359 Period[85]= 54160 ' midi= 84.9609 Period[86]= 51348 ' midi= 85.88269 Period[87]= 48134 ' midi= 87 Period[88]= 45120 ' midi= 88.11731 Period[89]= 42777 ' midi= 89.0391 Period[90]= 40098 ' midi= 90.15641 Period[91]= 38491 ' midi= 90.86314 Period[92]= 36081 ' midi= 91.98044 Period[93]= 34206 ' midi= 92.90224 Period[94]= 32063 ' midi= 94.01955 Period[95]= 30054 ' midi= 95.13686 Period[96]= 28849 ' midi= 95.84359 Period[97]= 26706 ' midi= 97.17596 Period[98]= 25635 ' midi= 97.88269 Period[99]= 24028 ' midi= 99 Period[100]= 22521 ' midi= 100.1173 Period[101]= 21349 ' midi= 101.0391 Period[102]= 20010 ' midi= 102.1564 Period[103]= 19207 ' midi= 102.8631 Period[104]= 18001 ' midi= 103.9804 Period[105]= 17064 ' midi= 104.9022 Period[106]= 15992 ' midi= 106.0196 Period[107]= 14988 ' midi= 107.1369 Period[108]= 14385 ' midi= 107.8436 Period[109]= 13314 ' midi= 109.176 Period[110]= 12778 ' midi= 109.8827 Period[111]= 11975 ' midi= 111 Period[112]= 11221 ' midi= 112.1173 Period[113]= 10636 ' midi= 113.0391 Period[114]= 9966 ' midi= 114.1564 Period[115]= 9564 ' midi= 114.8631 Period[116]= 8962 ' midi= 115.9804 Period[117]= 8493 ' midi= 116.9022 Period[118]= 7957 ' midi= 118.0196 Period[119]= 7455 ' midi= 119.1369 Period[120]= 7154 ' midi= 119.8436 Period[121]= 6618 ' midi= 121.176 Period[122]= 6350 ' midi= 121.8827 Period[123]= 5948 ' midi= 123 Period[124]= 5572 ' midi= 124.1173 Period[125]= 5279 ' midi= 125.0391 Period[126]= 4944 ' midi= 126.1564 Period[127]= 4743 ' midi= 126.8631 Return JI_E: Period[84]= 56804 ' midi= 84.13686 Period[85]= 54529 ' midi= 84.84359 Period[86]= 51116 ' midi= 85.9609 Period[87]= 48461 ' midi= 86.88269 Period[88]= 45428 ' midi= 88 Period[89]= 42584 ' midi= 89.11731 Period[90]= 40371 ' midi= 90.0391 Period[91]= 37843 ' midi= 91.15641 Period[92]= 36327 ' midi= 91.86314 Period[93]= 34051 ' midi= 92.98045 Period[94]= 32282 ' midi= 93.90224 Period[95]= 30259 ' midi= 95.01955 Period[96]= 28363 ' midi= 96.13686 Period[97]= 27225 ' midi= 96.84359 Period[98]= 25203 ' midi= 98.17596 Period[99]= 24192 ' midi= 98.88269 Period[100]= 22675 ' midi= 100 Period[101]= 21253 ' midi= 101.1173 Period[102]= 20147 ' midi= 102.0391 Period[103]= 18883 ' midi= 103.1564 Period[104]= 18124 ' midi= 103.8631 Period[105]= 16987 ' midi= 104.9804 Period[106]= 16102 ' midi= 105.9022 Period[107]= 15090 ' midi= 107.0196 Period[108]= 14142 ' midi= 108.1369 Period[109]= 13574 ' midi= 108.8436 Period[110]= 12562 ' midi= 110.176 Period[111]= 12057 ' midi= 110.8827 Period[112]= 11298 ' midi= 112 Period[113]= 10587 ' midi= 113.1173 Period[114]= 10034 ' midi= 114.0391 Period[115]= 9402 ' midi= 115.1564 Period[116]= 9023 ' midi= 115.8631 Period[117]= 8454 ' midi= 116.9804 Period[118]= 8012 ' midi= 117.9022 Period[119]= 7506 ' midi= 119.0196 Period[120]= 7032 ' midi= 120.1369 Period[121]= 6748 ' midi= 120.8436 Period[122]= 6242 ' midi= 122.176 Period[123]= 5989 ' midi= 122.8827 Period[124]= 5610 ' midi= 124 Period[125]= 5255 ' midi= 125.1173 Period[126]= 4978 ' midi= 126.0391 Period[127]= 4662 ' midi= 127.1564 Return JI_F: Period[84]= 57191 ' midi= 84.01955 Period[85]= 53612 ' midi= 85.13686 Period[86]= 51464 ' midi= 85.84359 Period[87]= 48243 ' midi= 86.9609 Period[88]= 45737 ' midi= 87.88269 Period[89]= 42874 ' midi= 89 Period[90]= 40189 ' midi= 90.11732 Period[91]= 38101 ' midi= 91.0391 Period[92]= 35715 ' midi= 92.15641 Period[93]= 34283 ' midi= 92.86314 Period[94]= 32136 ' midi= 93.98045 Period[95]= 30465 ' midi= 94.90224 Period[96]= 28556 ' midi= 96.01955 Period[97]= 26767 ' midi= 97.13686 Period[98]= 25693 ' midi= 97.84359 Period[99]= 23784 ' midi= 99.17596 Period[100]= 22829 ' midi= 99.88269 Period[101]= 21398 ' midi= 101 Period[102]= 20055 ' midi= 102.1173 Period[103]= 19012 ' midi= 103.0391 Period[104]= 17818 ' midi= 104.1564 Period[105]= 17103 ' midi= 104.8631 Period[106]= 16029 ' midi= 105.9804 Period[107]= 15194 ' midi= 106.9022 Period[108]= 14239 ' midi= 108.0195 Period[109]= 13344 ' midi= 109.1369 Period[110]= 12807 ' midi= 109.8436 Period[111]= 11853 ' midi= 111.176 Period[112]= 11376 ' midi= 111.8827 Period[113]= 10660 ' midi= 113 Period[114]= 9989 ' midi= 114.1173 Period[115]= 9467 ' midi= 115.0391 Period[116]= 8870 ' midi= 116.1564 Period[117]= 8512 ' midi= 116.8631 Period[118]= 7975 ' midi= 117.9804 Period[119]= 7558 ' midi= 118.9022 Period[120]= 7080 ' midi= 120.0195 Period[121]= 6633 ' midi= 121.1369 Period[122]= 6365 ' midi= 121.8436 Period[123]= 5887 ' midi= 123.176 Period[124]= 5649 ' midi= 123.8827 Period[125]= 5291 ' midi= 125 Period[126]= 4955 ' midi= 126.1173 Period[127]= 4694 ' midi= 127.0391 Return JI_Gb: Period[84]= 56933 ' midi= 84.09776 Period[85]= 53977 ' midi= 85.01955 Period[86]= 50598 ' midi= 86.13686 Period[87]= 48571 ' midi= 86.84359 Period[88]= 45531 ' midi= 87.9609 Period[89]= 43166 ' midi= 88.88268 Period[90]= 40463 ' midi= 90 Period[91]= 37929 ' midi= 91.11731 Period[92]= 35958 ' midi= 92.0391 Period[93]= 33706 ' midi= 93.15641 Period[94]= 32355 ' midi= 93.86314 Period[95]= 30328 ' midi= 94.98045 Period[96]= 28751 ' midi= 95.90224 Period[97]= 26949 ' midi= 97.01955 Period[98]= 25260 ' midi= 98.13686 Period[99]= 24246 ' midi= 98.84359 Period[100]= 22445 ' midi= 100.176 Period[101]= 21544 ' midi= 100.8827 Period[102]= 20192 ' midi= 102 Period[103]= 18925 ' midi= 103.1173 Period[104]= 17940 ' midi= 104.0391 Period[105]= 16814 ' midi= 105.1564 Period[106]= 16138 ' midi= 105.8631 Period[107]= 15125 ' midi= 106.9804 Period[108]= 14336 ' midi= 107.9022 Period[109]= 13436 ' midi= 109.0195 Period[110]= 12591 ' midi= 110.1369 Period[111]= 12084 ' midi= 110.8436 Period[112]= 11183 ' midi= 112.176 Period[113]= 10733 ' midi= 112.8827 Period[114]= 10057 ' midi= 114 Period[115]= 9424 ' midi= 115.1173 Period[116]= 8931 ' midi= 116.0391 Period[117]= 8368 ' midi= 117.1564 Period[118]= 8030 ' midi= 117.8631 Period[119]= 7523 ' midi= 118.9804 Period[120]= 7129 ' midi= 119.9022 Period[121]= 6679 ' midi= 121.0195 Period[122]= 6256 ' midi= 122.1369 Period[123]= 6003 ' midi= 122.8436 Period[124]= 5553 ' midi= 124.176 Period[125]= 5327 ' midi= 124.8827 Period[126]= 4989 ' midi= 126 Period[127]= 4673 ' midi= 127.1173 Return JI_G: Period[84]= 57320 ' midi= 83.98045 Period[85]= 53733 ' midi= 85.09776 Period[86]= 50943 ' midi= 86.01955 Period[87]= 47754 ' midi= 87.13686 Period[88]= 45841 ' midi= 87.84359 Period[89]= 42971 ' midi= 88.9609 Period[90]= 40739 ' midi= 89.88268 Period[91]= 38188 ' midi= 91 Period[92]= 35796 ' midi= 92.11731 Period[93]= 33936 ' midi= 93.0391 Period[94]= 31810 ' midi= 94.15641 Period[95]= 30534 ' midi= 94.86314 Period[96]= 28621 ' midi= 95.98045 Period[97]= 27133 ' midi= 96.90224 Period[98]= 25432 ' midi= 98.01955 Period[99]= 23838 ' midi= 99.13686 Period[100]= 22881 ' midi= 99.84359 Period[101]= 21181 ' midi= 101.176 Period[102]= 20330 ' midi= 101.8827 Period[103]= 19055 ' midi= 103 Period[104]= 17859 ' midi= 104.1173 Period[105]= 16929 ' midi= 105.0391 Period[106]= 15866 ' midi= 106.1564 Period[107]= 15228 ' midi= 106.8631 Period[108]= 14271 ' midi= 107.9804 Period[109]= 13527 ' midi= 108.9022 Period[110]= 12677 ' midi= 110.0195 Period[111]= 11880 ' midi= 111.1369 Period[112]= 11402 ' midi= 111.8436 Period[113]= 10551 ' midi= 113.176 Period[114]= 10126 ' midi= 113.8827 Period[115]= 9488 ' midi= 115 Period[116]= 8890 ' midi= 116.1173 Period[117]= 8425 ' midi= 117.0391 Period[118]= 7894 ' midi= 118.1564 Period[119]= 7575 ' midi= 118.8631 Period[120]= 7097 ' midi= 119.9804 Period[121]= 6725 ' midi= 120.9022 Period[122]= 6299 ' midi= 122.0195 Period[123]= 5901 ' midi= 123.1369 Period[124]= 5662 ' midi= 123.8436 Period[125]= 5236 ' midi= 125.176 Period[126]= 5024 ' midi= 125.8827 Period[127]= 4705 ' midi= 127 Return JI_Ab: Period[84]= 57711 ' midi= 83.86314 Period[85]= 54099 ' midi= 84.98044 Period[86]= 50713 ' midi= 86.09776 Period[87]= 48079 ' midi= 87.01955 Period[88]= 45069 ' midi= 88.13686 Period[89]= 43263 ' midi= 88.84359 Period[90]= 40555 ' midi= 89.9609 Period[91]= 38448 ' midi= 90.88269 Period[92]= 36040 ' midi= 92 Period[93]= 33782 ' midi= 93.11731 Period[94]= 32027 ' midi= 94.0391 Period[95]= 30020 ' midi= 95.15641 Period[96]= 28816 ' midi= 95.86314 Period[97]= 27010 ' midi= 96.98044 Period[98]= 25606 ' midi= 97.90224 Period[99]= 24000 ' midi= 99.01955 Period[100]= 22496 ' midi= 100.1369 Period[101]= 21593 ' midi= 100.8436 Period[102]= 19987 ' midi= 102.176 Period[103]= 19185 ' midi= 102.8827 Period[104]= 17981 ' midi= 104 Period[105]= 16852 ' midi= 105.1173 Period[106]= 15974 ' midi= 106.0391 Period[107]= 14971 ' midi= 107.1564 Period[108]= 14369 ' midi= 107.8631 Period[109]= 13466 ' midi= 108.9804 Period[110]= 12764 ' midi= 109.9022 Period[111]= 11961 ' midi= 111.0195 Period[112]= 11209 ' midi= 112.1369 Period[113]= 10757 ' midi= 112.8436 Period[114]= 9955 ' midi= 114.176 Period[115]= 9553 ' midi= 114.8827 Period[116]= 8951 ' midi= 116 Period[117]= 8387 ' midi= 117.1173 Period[118]= 7948 ' midi= 118.0391 Period[119]= 7446 ' midi= 119.1564 Period[120]= 7145 ' midi= 119.8631 Period[121]= 6694 ' midi= 120.9804 Period[122]= 6343 ' midi= 121.9022 Period[123]= 5941 ' midi= 123.0195 Period[124]= 5565 ' midi= 124.1369 Period[125]= 5339 ' midi= 124.8436 Period[126]= 4938 ' midi= 126.176 Period[127]= 4738 ' midi= 126.8827 Return JI_A: Period[84]= 56740 ' midi= 84.15641 Period[85]= 54467 ' midi= 84.86314 Period[86]= 51058 ' midi= 85.98045 Period[87]= 47862 ' midi= 87.09776 Period[88]= 45376 ' midi= 88.01955 Period[89]= 42535 ' midi= 89.13686 Period[90]= 40831 ' midi= 89.84359 Period[91]= 38274 ' midi= 90.9609 Period[92]= 36285 ' midi= 91.88269 Period[93]= 34013 ' midi= 93 Period[94]= 31882 ' midi= 94.11731 Period[95]= 30225 ' midi= 95.0391 Period[96]= 28331 ' midi= 96.15641 Period[97]= 27195 ' midi= 96.86314 Period[98]= 25490 ' midi= 97.98045 Period[99]= 24164 ' midi= 98.90224 Period[100]= 22649 ' midi= 100.0195 Period[101]= 21229 ' midi= 101.1369 Period[102]= 20376 ' midi= 101.8436 Period[103]= 18861 ' midi= 103.176 Period[104]= 18104 ' midi= 103.8827 Period[105]= 16967 ' midi= 105 Period[106]= 15902 ' midi= 106.1173 Period[107]= 15073 ' midi= 107.0391 Period[108]= 14126 ' midi= 108.1564 Period[109]= 13558 ' midi= 108.8631 Period[110]= 12706 ' midi= 109.9804 Period[111]= 12043 ' midi= 110.9022 Period[112]= 11285 ' midi= 112.0195 Period[113]= 10575 ' midi= 113.1369 Period[114]= 10149 ' midi= 113.8436 Period[115]= 9391 ' midi= 115.176 Period[116]= 9013 ' midi= 115.8827 Period[117]= 8445 ' midi= 117 Period[118]= 7912 ' midi= 118.1173 Period[119]= 7498 ' midi= 119.0391 Period[120]= 7024 ' midi= 120.1564 Period[121]= 6740 ' midi= 120.8631 Period[122]= 6314 ' midi= 121.9804 Period[123]= 5982 ' midi= 122.9022 Period[124]= 5604 ' midi= 124.0195 Period[125]= 5248 ' midi= 125.1369 Period[126]= 5035 ' midi= 125.8436 Period[127]= 4657 ' midi= 127.176 Return JI_Bb: Period[84]= 57841 ' midi= 83.82404 Period[85]= 53551 ' midi= 85.15641 Period[86]= 51406 ' midi= 85.86314 Period[87]= 48188 ' midi= 86.98045 Period[88]= 45171 ' midi= 88.09776 Period[89]= 42825 ' midi= 89.01955 Period[90]= 40144 ' midi= 90.13686 Period[91]= 38535 ' midi= 90.84359 Period[92]= 36122 ' midi= 91.9609 Period[93]= 34244 ' midi= 92.88269 Period[94]= 32099 ' midi= 94 Period[95]= 30088 ' midi= 95.11731 Period[96]= 28524 ' midi= 96.0391 Period[97]= 26736 ' midi= 97.15641 Period[98]= 25664 ' midi= 97.86314 Period[99]= 24055 ' midi= 98.98045 Period[100]= 22804 ' midi= 99.90224 Period[101]= 21373 ' midi= 101.0195 Period[102]= 20033 ' midi= 102.1369 Period[103]= 19228 ' midi= 102.8436 Period[104]= 17798 ' midi= 104.176 Period[105]= 17083 ' midi= 104.8827 Period[106]= 16011 ' midi= 106 Period[107]= 15005 ' midi= 107.1173 Period[108]= 14223 ' midi= 108.0391 Period[109]= 13329 ' midi= 109.1564 Period[110]= 12793 ' midi= 109.8631 Period[111]= 11988 ' midi= 110.9804 Period[112]= 11363 ' midi= 111.9022 Period[113]= 10648 ' midi= 113.0195 Period[114]= 9977 ' midi= 114.1369 Period[115]= 9575 ' midi= 114.8436 Period[116]= 8860 ' midi= 116.176 Period[117]= 8502 ' midi= 116.8827 Period[118]= 7966 ' midi= 118 Period[119]= 7463 ' midi= 119.1173 Period[120]= 7072 ' midi= 120.0391 Period[121]= 6625 ' midi= 121.1564 Period[122]= 6357 ' midi= 121.8631 Period[123]= 5955 ' midi= 122.9804 Period[124]= 5642 ' midi= 123.9022 Period[125]= 5285 ' midi= 125.0195 Period[126]= 4950 ' midi= 126.1369 Period[127]= 4748 ' midi= 126.8436 Return JI_B: Period[84]= 56868 ' midi= 84.11731 Period[85]= 54591 ' midi= 84.82404 Period[86]= 50541 ' midi= 86.15641 Period[87]= 48516 ' midi= 86.86314 Period[88]= 45479 ' midi= 87.98044 Period[89]= 42632 ' midi= 89.09776 Period[90]= 40417 ' midi= 90.01955 Period[91]= 37886 ' midi= 91.13686 Period[92]= 36368 ' midi= 91.84359 Period[93]= 34090 ' midi= 92.9609 Period[94]= 32318 ' midi= 93.88269 Period[95]= 30293 ' midi= 95 Period[96]= 28395 ' midi= 96.11731 Period[97]= 26919 ' midi= 97.0391 Period[98]= 25231 ' midi= 98.15641 Period[99]= 24219 ' midi= 98.86314 Period[100]= 22700 ' midi= 99.98044 Period[101]= 21519 ' midi= 100.9022 Period[102]= 20169 ' midi= 102.0195 Period[103]= 18904 ' midi= 103.1369 Period[104]= 18145 ' midi= 103.8436 Period[105]= 16795 ' midi= 105.176 Period[106]= 16120 ' midi= 105.8827 Period[107]= 15108 ' midi= 107 Period[108]= 14158 ' midi= 108.1173 Period[109]= 13420 ' midi= 109.0391 Period[110]= 12577 ' midi= 110.1564 Period[111]= 12070 ' midi= 110.8631 Period[112]= 11311 ' midi= 111.9804 Period[113]= 10721 ' midi= 112.9022 Period[114]= 10046 ' midi= 114.0195 Period[115]= 9413 ' midi= 115.1369 Period[116]= 9033 ' midi= 115.8436 Period[117]= 8358 ' midi= 117.176 Period[118]= 8021 ' midi= 117.8827 Period[119]= 7515 ' midi= 119 Period[120]= 7040 ' midi= 120.1173 Period[121]= 6671 ' midi= 121.0391 Period[122]= 6249 ' midi= 122.1564 Period[123]= 5996 ' midi= 122.8631 Period[124]= 5616 ' midi= 123.9804 Period[125]= 5321 ' midi= 124.9022 Period[126]= 4984 ' midi= 126.0195 Period[127]= 4667 ' midi= 127.1369 Return '[EOF]