'**************************************************************************** '* <4Pi> * '* 5 1/2 octave membrane driven organ * '* 3-notes per PIC with ADSR * '* dr.Godfried-Willem Raes * '* 2022 * '* Version 1.2 * ' *************************************************************************** ' NOTE: Pickit3 or PicKit4 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. '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. but 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 development 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 make 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!!! ' Microtuning 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. ' -------------------------------------------------------------------------------- ' 01.09.2018: starting from the code for Pi, adapted to 2Pi ' we need to divide the clock by two to generate notes an octave lower. ' So, we now have metacompiler commands in de timer ISR's ' Lights mapped on notes 1 and 2: Blue LED, portB.5 ' 02.09.2018: PIC's 1 to 5 flashed. ' 05.09.2018: Mounting finished. Testing board 2, PIC's 6 to 10. ' bug killed in timer 5 ISR ' 06.09.2018: Firmware reflashed. ' problems with notes 78 and 85 must be due to the buzzers ' problem with note 98 must be bad solder joint on mosfet ' 08.09.2018: Pipes 78 and 85 replaced. 77 may also need replacement. ' Default startup values for controllers changed. ' Now using declared constants (symbols) for these settings. ' 07.12.2020: Bug in reading TMR3 killed. All hex dumps recompiled. ' --------------------------------------------------------------------------------- ' 21.02.2022: Start development for <3Pi>, using conical pipe resonators. ' Problem: we want to start at note 60,but this entails a divide by 4 in the timer ISR's ' 03.03.2022: First tests and debug session on a PIC. ' 05.03.2022: timer2/3 seems to crash... ' now, no longer crash after 2.5 nor 5h30 but we have no clue as to what exactly solved it... ' 19.03.2022: <3Pi> finalized. ' 21.03.2022: <3Pi> given in the hand of our users. Midi implementation documented such as to correspond ' to this coding. ' --------------------------------------------------------------------------------- ' 27.04.2022: Start development of code for <4Pi> ' :8 divider prescaler added in timer init's for notes 36 to 59 ' Timer ISR's adapted accordingly ' Pitch look-ups adapted. ' lights mapped on notes 12,13,14. ' CC7 added as general volume controller, using a binary & operation : shaky... ' CC16 now steers sustain level ' 28.04.2022 check real time modulation of volume! If we are in the sustain phase... ' must be done in the ctrl#7 handling code ' PTPER set to 511 instead of 512. 511 is the largest possible number in 9-bits. ' Float variable VolFaktor introduced for a better implementation of a volume control. ' This seems to work fine on the test-board with the new test code in GMT. ' runtime test > 20h continuous passed. ' Key pressure implemented. ' 29.04.2022: Keypressure procedure improved and inline coded, replacing the gosub. ' 09.05.2022: PCB2 - all PIC's programmed. ' PCB1 - all PIC's programmed. ' small blue led implemented to indicate non standard tuning is active, on PCB3 ' we could implement notes 97 - 108 on board 3, such that we could play all files... ' 10.05.2022: All PIC's programmed, Version 1.0 ' 11.05.2022: First tests: board 1 o.k., boards 2 and 3 seem not to get midi in... ' board 2 repaired, note 63 not working... Board repaired, we had a short... ' 12.05.2022: First test- and demo files prepared. ' Top octave PIC's not yet programmed for 97-108 support! ' 08.06.2022: Programming session upper octave. Tested o.k. ' 31.07.2022: Intonation needs to be improved! ' 03.08.2022: pitch shift controllers seem not to be working... ' three range variables introduced. Pitch shift should now work whilst notes are sounding. ' This be version 1.1 - tested o.k. ' 04.08.2022: all volume levels (Ont() lookup table) changed to pure logarithmic. ' should be a lot smoother. ' This be version 1.2 - tested o.k. ' ------------------------------------------------------------------------------------------------ ' 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 Symbol power_relay PORTB.6 ' on the last PIC, this has a blue LED! Output PORTB.6 Low PORTB.6 ' for ctrl 66, only connected on some PIC's : the third PIC steers the relay ' the fourth PIC on each board steers the green LED ' only connected on the third PIC on each board: Symbol blue_led PORTB.5 ' can be something else on <4Pi> - non standard tuning active indicator. Output PORTB.5 Low PORTB.5 Symbol Loopcnt PORTB.4 Output Loopcnt 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, Pickit4) 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 = 11 ' Pi_Channel = 2Pi_channel = 3Pi_channel = 5 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 ' for the ADSR system Symbol LastTask = NrTasks - 1 'constant declarations for the controller default settings on startup, cold boot and reset: Symbol Default_Volume = 127 ' level, new for 4Pi Symbol Default_Attack = 10 ' time Symbol Default_Sustain = 118 ' level Symbol Default_Decay = 20 ' time Symbol Default_Release = 10 ' time Symbol Default_Noise = 6 Symbol Default_Wave = 99 ' duty cycle (0-127 for range 0 to 0.5) ' metacompiler commands: $define Bass ' define this for notes 36 to 47 '$define Tenor ' define this for notes 48 to 59 '$define Alto ' define this for notes 60 to 71 - was SubOct on 3Pi '$define Soprano ' define this for the notes 72 to 83 - was LowOct on 3Pi and 2Pi '$define TopOct ' define this for notes 84 to 127 - was normal on Pi, 2Pi and 3Pi ' change these for other boards: (3 boards, 18 PIC's) $define Board43_45 ' Bass defined '$define Board46_48 '$define Board49_51 ' Tenor defined - has lite '$define Board52_54 '$define Board55_57 '$define Board58_60 '$define Board61_63 ' Alto defined '$define Board64_66 '$define Board67_69 ' has lite '$define Board70_72 '$define Board73_75 ' soprano defined, from here on Alto must be undefined '$define Board76_78 '$define Notes97_108 ' only to be defined for boards 85-87,88-90,91-93,94-96 '$define Board79_81 '$define Board82_84 '$define Board85_87 ' define TopOct here. - has lite '$define Board88_90 '$define Board91_93 '$define Board94_96 ' this is the last pic for 4Pi ' board 1: 43-60 - six PIC's $ifdef Board43_45 '$define Bass Symbol note1 = 43 Symbol note2 = 44 Symbol note3 = 45 $endif $ifdef Board46_48 '$define Bass Symbol note1 = 46 Symbol note2 = 47 Symbol note3 = 48 $endif $ifdef Board49_51 '$define Tenor Symbol note1 = 49 Symbol note2 = 50 Symbol note3 = 51 Symbol lite = 12 $endif $ifdef Board52_54 '$define Tenor Symbol note1 = 52 Symbol note2 = 53 Symbol note3 = 54 $endif ' BOARD 2: $ifdef Board55_57 '$define Tenor Symbol note1 = 55 Symbol note2 = 56 Symbol note3 = 57 $endif $ifdef Board58_60 '$define Tenor Symbol note1 = 58 Symbol note2 = 59 Symbol note3 = 60 $endif $ifdef Board61_63 '$define Alto Symbol note1 = 61 Symbol note2 = 62 Symbol note3 = 63 $endif $ifdef Board64_66 '$define Alto Symbol note1 = 64 Symbol note2 = 65 Symbol note3 = 66 $endif $ifdef Board67_69 Symbol note1 = 67 Symbol note2 = 68 Symbol note3 = 69 Symbol lite = 13 $endif $ifdef Board70_72 Symbol note1 = 70 Symbol note2 = 71 Symbol note3 = 72 $endif $ifdef Board73_75 '$define Soprano Symbol note1 = 73 Symbol note2 = 74 Symbol note3 = 75 $endif ' board 2: $ifdef Board76_78 Symbol note1 = 76 Symbol note2 = 77 Symbol note3 = 78 $endif $ifdef Board79_81 Symbol note1 = 79 Symbol note2 = 80 Symbol note3 = 81 $endif $ifdef Board82_84 Symbol note1 = 82 Symbol note2 = 83 Symbol note3 = 84 $endif $ifdef Board85_87 '$define TopOct Symbol note1 = 85 Symbol note2 = 86 Symbol note3 = 87 Symbol lite = 14 $endif $ifdef Board88_90 Symbol note1 = 88 Symbol note2 = 89 Symbol note3 = 90 $endif $ifdef Board91_93 Symbol note1 = 91 Symbol note2 = 92 Symbol note3 = 93 $endif $ifdef Board94_96 Symbol note1 = 94 Symbol note2 = 95 Symbol note3 = 96 Symbol blue_lite = 15 $endif $ifdef Notes97_108 Symbol note4 = note1 + 12 Symbol note5 = note2 + 12 Symbol note6 = note3 + 12 $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. $ifdef Bass ' setting prescaler to :8 T1CON.5 = 0 T1CON.4 = 1 $endif $ifdef Tenor ' setting prescaler to :8 T1CON.5 = 0 T1CON.4 = 1 $endif $ifdef Alto ' setting prescaler to 0: T1CON.5 = 0 T1CON.4 = 0 $endif $ifdef Soprano ' setting prescaler to 0: T1CON.5 = 0 T1CON.4 = 0 $endif $ifdef TopOct ' setting prescaler to 0: T1CON.5 = 0 T1CON.4 = 0 $endif ' ----------------------- 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. TMR3HLD = 0 TMR2 = 0 Set PR2 ' = 65535 Set 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 TMR5HLD = 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 ' Hybrlo: prescaler set to :64, On Pi we have :8 'T4CON.4 = 1 ' 00 = :1, 01 = :8 , 10 = :64, 11 = :256 $ifdef Bass ' prescaler set to :8 T4CON.5 = 0 T4CON.4 = 1 $endif $ifdef Tenor ' prescaler set to :8 T4CON.5 = 0 T4CON.4 = 1 $endif $ifdef Alto ' prescaler set to 0: T4CON.5 = 0 T4CON.4 = 0 $endif $ifdef Soprano ' prescaler set to 0: T4CON.5 = 0 T4CON.4 = 0 $endif $ifdef TopOct ' prescaler set to 0: T4CON.5 = 0 T4CON.4 = 0 $endif ' ------------------------ 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. $ifdef Bass ' prescaler set to :8 T5CON.5 = 0 T5CON.4 = 1 $endif $ifdef Tenor ' prescaler set to :8 T5CON.5 = 0 T5CON.4 = 1 $endif $ifdef Alto ' prescaler set to :1 T5CON.5 = 0 T5CON.4 = 0 $endif $ifdef Soprano ' prescaler set to :1 T5CON.5 = 0 T5CON.4 = 0 $endif $ifdef TopOct ' prescaler set to 0: T5CON.5 = 0 T5CON.4 = 0 $endif ' ---------------------- 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 '512 ' this determines the range for the PWM control ' with this setting we have 9 bits 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 ' 4.2 us resolution Dim maxtim As time.31 ' overflow bit, will cause timer reset after 5 hours 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 ' 03.08.2022: shouldn't we have 3 separate ranges here? Dim range1 As Word Dim range2 As Word Dim range3 As Word Dim CC21 As Word ' value for controller 21 - tuning lookups Dim div1 As Word ' only 2 bits required... Dim div2 As Word Dim div3 As Word ' variables for the ADSR system: Dim CC7 As Word ' new for 4Pi Dim Volume As Word ' new for 4Pi Dim VolFaktor As Float Dim Notes As Byte Dim Sus1 As Notes.0 ' set when noot1 is in the sustain phase Dim Sus2 As Notes.1 Dim Sus3 As Notes.2 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 - now ctrl 16 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 now << 3 0 - 1023 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 Outbuffer ' Tx Clear OutIdxIn Clear OutIdxOut Set TimVals ' array ' Clear DataBuffer ' ADC ' Clear DataInIdx ' Clear DataOutIdx Clear tuneSword1 Clear tuneSword2 Clear tuneSword3 Clear Notes ' sus1, sus2, sus3 flags. 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 ' 03.08.2022: using 3 different variables: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Clear div1 Clear div2 Clear div3 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! $ifdef Bass Select div1 Case 0 PR1 = On1 Set Note_Port1 div1 = 1 Case 1 div1 = 2 Case 2 PR1 = Of1 - jitter Clear Note_Port1 div1 = 3 Case 3 Clear div1 EndSelect $endif $ifdef Tenor If Note_Port1 = 0 Then ' begin van de cyclus AAN-tijd PR1 = On1 Set Note_Port1 Else PR1 = Of1 - jitter Clear Note_Port1 EndIf $endif $ifdef Alto ' this should work for notes 60 to 71 on <3Pi> Select div1 Case 0 PR1 = On1 Set Note_Port1 div1 = 1 Case 1 div1 = 2 Case 2 div1 = 3 Case 3 div1 = 4 Case 4 PR1 = Of1 - jitter Clear Note_Port1 div1 = 5 Case 5 div1 = 6 Case 6 div1 = 7 Case 7 Clear div1 EndSelect $endif ' for an octave lower we did this for 2Pi: ' this works for notes 72 to 83 $ifdef Soprano Select div1 Case 0 PR1 = On1 Set Note_Port1 div1 = 1 Case 1 div1 = 2 Case 2 PR1 = Of1 - jitter Clear Note_Port1 div1 = 3 Case 3 Clear div1 EndSelect $endif $ifdef TopOct If Note_Port1 = 0 Then ' begin van de cyclus AAN-tijd PR1 = On1 Set Note_Port1 Else PR1 = Of1 - jitter Clear Note_Port1 EndIf $endif EndIsr- ' exit the interrupt Isr- T3Interrupt Clear IFS0bits_T3IF ' 32-bit value reached (T2/T3 combined) ' this is our main timer! Clear TMR3HLD Clear TMR2 ' Set PR2 '= 65535 ' Set PR3 ' = 65535 ' try this: 06.03.2022: - will this solve the crash after 2h30'? Set TimVals Set idx Clear time Clear maxtim Clear ADSR1_flags Clear ADSR2_flags Clear ADSR3_flags EndIsr- Isr- T4Interrupt Clear IFS1bits_T4IF '16-bit value reached Clear TMR4 $ifdef Bass Select div2 Case 0 PR4 = On2 Set Note_Port2 div2 = 1 'Inc div2 Case 1 div2 = 2 'Inc div2 Case 2 PR4 = Of2 - jitter Clear Note_Port2 div2 = 3 'Inc div2 Case 3 'PR4 = Of2 - jitter Clear div2 EndSelect $endif $ifdef Tenor If Note_Port2 = 0 Then PR4 = On2 Set Note_Port2 Else PR4 = Of2 - jitter Clear Note_Port2 EndIf $endif $ifdef Alto ' this should work for note 60 to 71 on <3Pi> Select div2 Case 0 PR4 = On2 Set Note_Port2 div2 = 1 Case 1 div2 = 2 Case 2 div2 = 3 Case 3 div2 = 4 Case 4 PR4 = Of2 - jitter Clear Note_Port2 div2 = 5 Case 5 div2 = 6 Case 6 div2 = 7 Case 7 Clear div2 EndSelect $endif $ifdef Soprano Select div2 Case 0 PR4 = On2 Set Note_Port2 div2 = 1 'Inc div2 Case 1 div2 = 2 'Inc div2 Case 2 PR4 = Of2 - jitter Clear Note_Port2 div2 = 3 'Inc div2 Case 3 'PR4 = Of2 - jitter Clear div2 EndSelect $endif $ifdef TopOct If Note_Port2 = 0 Then PR4 = On2 Set Note_Port2 Else PR4 = Of2 - jitter Clear Note_Port2 EndIf $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 $ifdef Bass Select div3 Case 0 PR5 = On3 Set Note_Port3 div3 = 1 Case 1 div3 = 2 Case 2 PR5 = Of3 - jitter Clear Note_Port3 div3 = 3 Case 3 'PR5 = Of3 - jitter Clear div3 EndSelect $endif $ifdef Tenor If Note_Port3 = 0 Then PR5 = On3 Set Note_Port3 Else PR5 = Of3 - jitter Clear Note_Port3 EndIf $endif $ifdef Alto ' this should work for notes 60 to 71 on <3Pi> Select div3 Case 0 PR5 = On3 Set Note_Port3 div3 = 1 Case 1 div3 = 2 Case 2 div3 = 3 Case 3 div3 = 4 Case 4 PR5 = Of3 - jitter Clear Note_Port3 div3 = 5 Case 5 div3 = 6 Case 6 div3 = 7 Case 7 Clear div3 EndSelect $endif $ifdef Soprano Select div3 Case 0 PR5 = On3 Set Note_Port3 div3 = 1 Case 1 div3 = 2 Case 2 PR5 = Of3 - jitter Clear Note_Port3 div3 = 3 Case 3 'PR5 = Of3 - jitter Clear div3 EndSelect $endif $ifdef TopOct If Note_Port3 = 0 Then PR5 = On3 Set Note_Port3 Else PR5 = Of3 - jitter Clear Note_Port3 EndIf $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 Set velo Case Keypres_Status ' waveshape modulator statusbyte = Bytein Set notePres Set pres Case Control_Status ' controllers and switches statusbyte = Bytein Set Ctrl Set value Case ProgChange_Status ' could be used for different lookup tables and presets statusbyte = Bytein Set prog '= 255 ' Case Aftertouch_Status ' not used on this board ' statusbyte = Bytein ' Set aft ' Case Pitchbend_Status ' 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 Clear Sus1 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 Clear Sus2 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 Clear Sus3 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 $ifdef Board49_51 Case lite Low blue_led $endif $ifdef board67_69 Case lite Low blue_led $endif $ifdef board85_87 Case lite Low blue_led $endif $ifdef Board94_96 Case blue_lite Low PORTB.6 $endif $ifdef Notes97_108 Case note4 ' as for note1 Clear ADSR1_flags ' reset all flags = 0 Clear Sus1 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 note5 Clear ADSR2_flags Clear Sus2 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 note6 Clear ADSR3_flags Clear Sus3 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 $endif 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 Clear Sus1 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 Clear Sus2 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 Clear Sus3 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 $ifdef Board49_51 Case lite Low blue_led $endif $ifdef board67_69 Case lite Low blue_led $endif $ifdef board85_87 Case lite Low blue_led $endif $ifdef Board94_96 Case blue_lite Low PORTB.6 $endif $ifdef Notes97_108 Case note4 ' as for note1 Clear ADSR1_flags ' reset all flags = 0 Clear Sus1 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 note5 Clear ADSR2_flags Clear Sus2 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 note6 Clear ADSR3_flags Clear Sus3 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 $endif EndSelect Else Select noteAan Case note1 Attack1_level = velo ' here velo is always > 0 Clear ADSR1_flags ' program timer1 as frequency generator Clear IEC0bits_T1IE ' disable IRQ Clear Note_Port1 Clear div1 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 Clear ADSR2_flags Clear IEC1bits_T4IE ' disable irq Clear Note_Port2 Clear div2 ' 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 Clear ADSR3_flags ' program timer5 as frequency generator Clear IEC1bits_T5IE ' disable timer5 interrupt Clear Note_Port3 Clear div3 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 $ifdef Board49_51 Case lite ' = 12 Set blue_led $endif $ifdef board67_69 Case lite ' = 13 Set blue_led ' red in fact... $endif $ifdef board85_87 Case lite ' = 14 Set blue_led $endif $ifdef Board94_96 Case blue_lite ' = 15 High PORTB.6 $endif $ifdef Notes97_108 Case note4 Attack1_level = velo ' here velo is always > 0 Clear ADSR1_flags ' program timer1 as frequency generator Clear IEC0bits_T1IE ' disable IRQ Clear Note_Port1 Clear div1 period1 = Period[note4] - 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 note5 Attack2_level = velo Clear ADSR2_flags Clear IEC1bits_T4IE ' disable irq Clear Note_Port2 Clear div2 ' program timer4 as frequency generator period2 = Period[note5] - 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 note6 Attack3_level = velo Clear ADSR3_flags ' program timer5 as frequency generator Clear IEC1bits_T5IE ' disable timer5 interrupt Clear Note_Port3 Clear div3 period3 = Period[note6] - 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 $endif EndSelect Set noteAan '= 255 EndIf EndIf Case Keypres_Status If notePres = 255 Then notePres = Bytein Else pres = Bytein + 1 ' if notepres = note1 then GoSub KeyPres ' if notePres = note2 then Gosub Keypres ' If notePres = note3 Then GoSub KeyPres ' set notePres ' we would do better, by inline coding here, avoiding the gosub... ' As long as we do not send cc15, the duty cycles of all notes can ' be pure polyphonic, this with different setting for each note. Select notePres Case note1 dutcy1 = pres / 256 On1 = period1 * dutcy1 Of1 = period1 - On1 Case note2 dutcy2 = pres / 256 On2 = period2 * dutcy2 Of2 = period2 - On2 Case note3 dutcy3 = pres / 256 On3 = period3 * dutcy3 Of3 = period3 - On3 $ifdef Notes97_108 Case note4 dutcy1 = pres / 256 On1 = period1 * dutcy1 Of1 = period1 - On1 Case note5 dutcy2 = pres / 256 On2 = period2 * dutcy2 Of2 = period2 - On2 Case note6 dutcy3 = pres / 256 On3 = period3 * dutcy3 Of3 = period3 - On3 $endif EndSelect Set notePres 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 'Set Nxt.Word1 ' 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 Clear Sus1 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] * VolFaktor ' & Volume ' new binary multiplier 27.04.2022 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 Set Sus1 Case > Sustain1_level Set Decay1_flag ' ADSR1_flags becomes 4 cnt1= Attack1_level ' start value for the decay ' steps calculated on reception of note-on PDC1 = Ont[cnt1] * VolFaktor ' & Volume TimVals[0] = time + Dstepval1 Case Else ' attack level <= sustain level Set Decay1_tog ' further increase flag... becomes 8 cnt1 = Attack1_level PDC1 = Ont[cnt1] * VolFaktor '& Volume TimVals[0] = time + Dstepval1 EndSelect EndIf Case 4 ' decay flag is set, downwards decay Dec cnt1 PDC1 = Ont[cnt1] * VolFaktor TimVals[0] = time + Dstepval1 If cnt1 = Sustain1_level Then Clear ADSR1_flags ' Decay1_flag ' becomes 0 Set TimVals[0] ' cancel the timer Set Sus1 EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt1 PDC1 = Ont[cnt1] * VolFaktor '& Volume TimVals[0] = time + Dstepval1 If cnt1 = Sustain1_level Then Clear ADSR1_flags 'Decay1_tog ' becomes 0 Set TimVals[0] ' cancel timer Set Sus1 EndIf Case 64 ' release flag is set - set in the note-off command cnt1 = Sustain1_level PDC1 = Ont[cnt1] * VolFaktor '& Volume ' ? 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 Clear Sus1 Case 128 ' 192 ' release-phase If cnt1 > 0 Then Dec cnt1 PDC1 = Ont[cnt1] * VolFaktor '& Volume 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 'clear Sus1 EndIf EndSelect Case 1 ' noot2 adsr Select ADSR2_flags Case 1 ' if we get here, the first attack steptime has passed Clear cnt2 Clear Sus2 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] * VolFaktor ' & Volume 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 Set Sus2 EndIf If Attack2_level > Sustain2_level Then Set Decay2_flag ' becomes 4 cnt2= Attack2_level ' start value for the decay PDC2 = Ont[cnt2] * VolFaktor '& Volume TimVals[1] = time + Dstepval2 Else ' attack level <= sustain level Set Decay2_tog ' further increase flag... becomes 8 cnt2 = Attack2_level PDC2 = Ont[cnt2] * VolFaktor '& Volume TimVals[1] = time + Dstepval2 EndIf EndIf Case 4 ' decay flag is set Dec cnt2 PDC2 = Ont[cnt2] * VolFaktor '& Volume 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] Set Sus2 EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt2 PDC2 = Ont[cnt2] * VolFaktor '& Volume TimVals[1] = time + Dstepval2 If cnt2 = Sustain2_level Then Clear Decay2_tog ' becomes 0 Set Sustain2_flag ' becomes 16 Set TimVals[1] Set Sus2 EndIf Case 64 ' release flag is set cnt2 = Sustain2_level PDC2 = Ont[cnt2] * VolFaktor ' & Volume ADSR2_flags = 128 'Set Release2_tog ' becomes 192 TimVals[1] = time + Rstepval2 Clear Sus2 Case 128 ' release-phase If cnt2 > 0 Then Dec cnt2 PDC2 = Ont[cnt2] * VolFaktor ' & Volume 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 Clear Sus3 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] * VolFaktor '& Volume 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] Set Sus3 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] * VolFaktor '& Volume TimVals[2] = time + Dstepval3 Else ' attack level <= sustain level Set Decay3_tog ' further increase flag... becomes 8 cnt3 = Attack3_level PDC3 = Ont[cnt3] * VolFaktor '& Volume TimVals[2] = time + Dstepval3 EndIf EndIf Case 4 ' decay flag is set Dec cnt3 PDC3 = Ont[cnt3] * VolFaktor 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] Set Sus3 EndIf Case 8 ' in this case we should increase volume until sustain level is reached Inc cnt3 PDC3 = Ont[cnt3] * VolFaktor '& Volume TimVals[2] = time + Dstepval3 If cnt3 = Sustain3_level Then Clear Decay3_tog ' becomes 0 Set Sustain3_flag ' becomes 16 Set TimVals[2] Set Sus3 EndIf Case 64 ' release flag is set cnt3 = Sustain3_level PDC3 = Ont[cnt3] * VolFaktor ' & Volume ADSR3_flags = 128 'Set Release3_tog ' becomes 192 TimVals[2] = time + Rstepval3 Clear Sus3 Case 128 ' release-phase If cnt3 > 0 Then Dec cnt3 PDC3 = Ont[cnt3] * VolFaktor '& Volume 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 TMR3HLD Clear TMR2 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 TMR3HLD Clear TMR2 ' 07.08.2016 Set TimVals ' should not be required here EndIf EndIf $ifdef Enable_UART_TX ' not used 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 ' 04.03.2022: 226kHz - 4.4us ' 28.04.2022: 257kHz - 285kHz watchdog_led = time.16 ' this is the red LED on each PIC. ' if this bit is not blinking, timer2/3 has crashed. 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 Set Nxt ' 04.03.2022: must be unsigned of course! Clear i Repeat If TimVals[i] < Nxt Then Nxt = TimVals[i] ' 3 dword comparisons idx = i EndIf Inc i Until i = NrTasks Clear resort_flag Return ' ************************************************************************************** ' procedures for midi receiver: KeyPres: ' can be used to modulate the wave shape 'inc pres - done in the parser. ' 29.04.2022: procedure moved to inline coding in the parser. ' so now, this gosub is no longer called. Select notePres Case note1 'bdutcy1 = pres + 1 dutcy1 = pres / 256 On1 = period1 * dutcy1 Of1 = period1 - On1 'On1 = note1_period.Byte1 * dutcy1 'Of1 = note1_period - On1 Case note2 'bdutcy2 = pres + 1 dutcy2 = pres / 256 On2 = period2 * dutcy2 Of2 = period2 - On2 'On2 = note2_period.Byte1 * dutcy2 'Of2 = note2_period - On2 Case note3 'bdutcy3 = pres + 1 dutcy3 = pres / 256 On3 = period3 * dutcy3 Of3 = period3 - On3 'On3 = note3_period.Byte1 * dutcy3 'Of3 = note3_period - On3 $ifdef Notes97_108 Case note4 dutcy1 = pres / 256 On1 = period1 * dutcy1 Of1 = period1 - On1 Case note5 dutcy2 = pres / 256 On2 = period2 * dutcy2 Of2 = period2 - On2 Case note6 dutcy3 = pres / 256 On3 = period3 * dutcy3 Of3 = period3 - On3 $endif EndSelect Set notePres 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 ' 10-bits: 0- 1023 '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 level controller CC7 = value ' remapped on a 9-bit log scale Volume = Ont[CC7] ' 9 bit value 'linaire scaling: 'VolFaktor = (value + 1.0) / 128.0 ' float! ' to preserve the log-nature of the curve we could also do: VolFaktor = Volume / 511.0 ' Ont[127] ' loopt dus van 45.34/511 tot 511/511, dus van 0.088 tot 1 ' to make real-time amplitude modulation possible, we should check for sounding notes ' 28.04.2022 ' note: there can be glitches if we change CC7 whilst in other phases of the ADSR, as ' the stepvalues are calculated at reception of a note-on command. ' This should still be remedied... If Sus1 = 1 Then ' however we must be in the sustain phase... PDC1 = Ont[Sustain1_level] * VolFaktor '& Volume EndIf If Sus2 = 1 Then PDC2 = Ont[Sustain2_level] * VolFaktor '& Volume EndIf If Sus3 = 1 Then PDC3 = Ont[Sustain3_level] * VolFaktor ' & Volume EndIf 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. ' this controller will affect the duty cycle of all notes. Inc value ' 0 crashes the system... dutcy1 = value / 256 ' 0 - 0.5 dutcy2 = dutcy1 dutcy3 = dutcy1 Case 16 ' new for 4Pi - was ctrl7 for Pi, 2Pi, 3Pi Sustain1_level = value Sustain2_level = value Sustain3_level = value 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 $ifdef Board94_96 If CC21 <> 0 Then ' blue led on last PIC ON High PORTB.6 ' = power_relay Else Low PORTB.6 EndIf $endif EndIf Case 66 'on/off for the robot If value = 0 Then ' power down GoSub PowerDown ' should reset controllers Low power_relay ' =PORTB.6 ' relay should release Else GoSub AllNotesOff $ifdef Board94_96 If CC21 = 0 Then Low power_relay ' has blue LED to indicate tuning! Else High power_relay EndIf $else High power_relay '= PORTB.6 ' enable relay $endif ' restart the timer: 'set idx 'set nxt 'set Timvals Clear TMR3HLD Clear TMR2 Clear time EndIf ' following redesigned for <4Pi>, as here controllers run from 69 to 120 ' we cannot implement this for the notes 97 to 108 though... Case note1 + 24 ' symbol ' 03.08.2022: this seems not working for some reason... ' range1,2,3 set on init. ' by default these controllers are 64. ' now it works... ' 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 * range1 ' do we also need to do this here?: ' yes, if we want to slide the pitches whilst the note is sounding. period1 = Period[note1] - tuneSword1 ' tunesword is bipolar and depends on range On1 = period1 * dutcy1 Of1 = period1 - On1 ' try using integer math only: 'tunesword1 = (range * (value - 64)) / 128 Case note2 + 24 fraction = (value / 128.0) - 0.5 tuneSword2 = fraction * range2 period2 = Period[note2] - tuneSword2 On2 = period2 * dutcy2 Of2 = period2 - On2 Case note3 + 24 fraction = (value / 128.0) - 0.5 tuneSword3 = fraction * range3 period3 = Period[note3] - tuneSword3 On3 = period3 * dutcy3 Of3 = period3 - On3 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 Clear Notes ' sus1, sus2, sus3 'Set resort_flag For i = 0 To LastTask ' =2 'NrTasks -1 Set TimVals[i] ' stop timers Next i Set idx Set Nxt $ifdef Board49_51 Low blue_led $endif $ifdef board67_69 Low blue_led ' red in fact... $endif $ifdef board85_87 Low blue_led $endif Return PowerDown: 'Set resort_flag For i = 0 To LastTask '2 'NrTasks -1 Set TimVals[i] Next i Set idx Set Nxt 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 Clear Notes ' clears Sus1, Sus2, Sus3 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 $ifdef Board49_51 Low blue_led $endif $ifdef board67_69 Low blue_led ' red LED in fact... $endif $ifdef board85_87 Low blue_led $endif Return Controller_Init_Prog0: ' reset controllers to default start-up values: CC7 = Default_Volume ' = 127 Volume = Ont[CC7] ' = 511 = PTPER VolFaktor = Volume / 511.0 ' = 1.0 Attack1_time.Byte1 = Default_Attack Decay1_time.Byte1 = Default_Decay Sustain1_level = Default_Sustain Release1_Time.Byte1 = Default_Release ' op 3pi = 10 ' set with release byte or ctrl 19 tuneSword1 = 0 dutcy1 = Default_Wave / 256.0 ' op 3pi = 0.386 C1val = Default_Noise << 3 ' 0- 1023 '0-254 ' op 3pi = 8, dus 64 hier 'C1bit = Ncd value ' returns 0-8 Attack2_time = Attack1_time Decay2_time = Decay1_time Sustain2_level = Sustain1_level Release2_Time = Release1_Time tuneSword2 = 0 dutcy2 = dutcy1 Attack3_time = Attack1_time Decay3_time = Decay1_time Sustain3_level = Sustain1_level Release3_Time = Release1_Time tuneSword3 = 0 dutcy3 = dutcy1 '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 511 ' ' changed to 511, 28.04.2022. ' For i = 1 To 127 ' Ont[i] = Sqr(i) * 45.34 ' scaling factor= 511 / SQR(127) ' Next i ' ' Ont[i] loopt nu dus van 45 tot 511 ' ' Ont[64] = 363 ' ' Ont[32] = 256 ' ' Ont[16] = 181 ' Ont[127] = 511 ' = PTPER ' Ont[0] = 0 ' version 1.2: changed to Log curve ' using pure logarithmic: ' log10(128) = 2.1072 ln(128) = 4.852030 ' scaling factor = 511 / 2.1072 = 242.5 511 / 4.852030 = 105.31673 For i = 2 To 128 'Ont[i-1] = (Log10(i)) * 242.5 Ont[i-1] = (Log(i)) * 105.31673 Next i ' Ont[64] = 439 ' Ont[32] = 368 ' Ont[16] = 298 ' Ont[8] = 231 ' Ont[4] = 169 ' Ont[2] = 115 ' Ont[1] = 73 Ont[127] = 511 ' = PTPER 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: '' for notes 60-71 the :4 divider is active, so: 'Period[60]= 57256 ' soll frequency = 1047 / 4 'Period[61]= 54038 ' soll frequency = 1109 / 4 'Period[62]= 51000 ' soll frequency = 1175 / 4 'Period[63]= 48134 ' soll frequency = 1245 / 4 'Period[64]= 45428 ' soll frequency = 1319 / 4 'Period[65]= 42874 ' soll frequency = 1397 / 4 'Period[66]= 40463 ' soll frequency = 1480 / 4 'Period[67]= 38188 ' soll frequency = 1568 / 4 'Period[68]= 36040 ' soll frequency = 1661 / 4 'Period[69]= 34013 ' soll frequency = 1760 / 4 = 440 Hz 'Period[70]= 32099 ' soll frequency = 1865 / 4 'Period[71]= 30293 ' soll frequency = 1976 / 4 ' for notes 72-81 the divider is active, and the values are the same as 84 - 95 'Period[72]= 57256 ' soll frequency = 1047 / 2 'Period[73]= 54038 ' soll frequency = 1109 / 2 'Period[74]= 51000 ' soll frequency = 1175 / 2 'Period[75]= 48134 ' soll frequency = 1245 / 2 'Period[76]= 45428 ' soll frequency = 1319 / 2 'Period[77]= 42874 ' soll frequency = 1397 / 2 'Period[78]= 40463 ' soll frequency = 1480 / 2 'Period[79]= 38188 ' soll frequency = 1568 / 2 'Period[80]= 36040 ' soll frequency = 1661 / 2 'Period[81]= 34013 ' soll frequency = 1760 / 2 = 880 Hz 'Period[82]= 32099 ' soll frequency = 1865 / 2 'Period[83]= 30293 ' soll frequency = 1976 / 2 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 $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_C: 'Period[72]= 57256 ' midi= 72 / 2 'Period[73]= 53672 ' midi= 85.11732 / 2 'Period[74]= 50885 ' midi= 86.0391 'Period[75]= 47700 ' midi= 87.15641 'Period[76]= 45789 ' midi= 87.86314 'Period[77]= 42922 ' midi= 88.98045 'Period[78]= 40693 ' midi= 89.90224 'Period[79]= 38144 ' midi= 91.01955 'Period[80]= 35755 ' midi= 92.13686 'Period[81]= 34322 ' midi= 92.84359 'Period[82]= 31774 ' midi= 94.17596 'Period[83]= 30500 ' midi= 94.88269 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_Db: 'Period[72]= 57645 ' midi= 83.88268 'Period[73]= 54038 ' midi= 85 'Period[74]= 50655 ' midi= 86.11731 'Period[75]= 48025 ' midi= 87.0391 'Period[76]= 45018 ' midi= 88.15641 'Period[77]= 43215 ' midi= 88.86314 'Period[78]= 40509 ' midi= 89.98044 'Period[79]= 38404 ' midi= 90.90224 'Period[80]= 35999 ' midi= 92.01955 'Period[81]= 33744 ' midi= 93.13686 'Period[82]= 32391 ' midi= 93.84359 'Period[83]= 29986 ' midi= 95.17596 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_D: 'Period[72]= 57385 ' midi= 83.9609 'Period[73]= 54406 ' midi= 84.88269 'Period[74]= 51000 ' midi= 86 'Period[75]= 47808 ' midi= 87.11731 'Period[76]= 45325 ' midi= 88.0391 'Period[77]= 42487 ' midi= 89.15641 'Period[78]= 40785 ' midi= 89.86314 'Period[79]= 38231 ' midi= 90.98044 'Period[80]= 36244 ' midi= 91.90224 'Period[81]= 33974 ' midi= 93.01955 'Period[82]= 31846 ' midi= 94.13686 'Period[83]= 30569 ' midi= 94.84359 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif Return JI_Eb: 'Period[72]= 57776 ' midi= 83.84359 'Period[73]= 54160 ' midi= 84.9609 'Period[74]= 51348 ' midi= 85.88269 'Period[75]= 48134 ' midi= 87 'Period[76]= 45120 ' midi= 88.11731 'Period[77]= 42777 ' midi= 89.0391 'Period[78]= 40098 ' midi= 90.15641 'Period[79]= 38491 ' midi= 90.86314 'Period[80]= 36081 ' midi= 91.98044 'Period[81]= 34206 ' midi= 92.90224 'Period[82]= 32063 ' midi= 94.01955 'Period[83]= 30054 ' midi= 95.13686 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_E: 'Period[72]= 56804 ' midi= 84.13686 'Period[73]= 54529 ' midi= 84.84359 'Period[74]= 51116 ' midi= 85.9609 'Period[75]= 48461 ' midi= 86.88269 'Period[76]= 45428 ' midi= 88 'Period[77]= 42584 ' midi= 89.11731 'Period[78]= 40371 ' midi= 90.0391 'Period[79]= 37843 ' midi= 91.15641 'Period[80]= 36327 ' midi= 91.86314 'Period[81]= 34051 ' midi= 92.98045 'Period[82]= 32282 ' midi= 93.90224 'Period[83]= 30259 ' midi= 95.01955 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_F: 'Period[72]= 57191 ' midi= 84.01955 'Period[73]= 53612 ' midi= 85.13686 'Period[74]= 51464 ' midi= 85.84359 'Period[75]= 48243 ' midi= 86.9609 'Period[76]= 45737 ' midi= 87.88269 'Period[77]= 42874 ' midi= 89 'Period[78]= 40189 ' midi= 90.11732 'Period[79]= 38101 ' midi= 91.0391 'Period[80]= 35715 ' midi= 92.15641 'Period[81]= 34283 ' midi= 92.86314 'Period[82]= 32136 ' midi= 93.98045 'Period[83]= 30465 ' midi= 94.90224 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_Gb: 'Period[72]= 56933 ' midi= 84.09776 'Period[73]= 53977 ' midi= 85.01955 'Period[74]= 50598 ' midi= 86.13686 'Period[75]= 48571 ' midi= 86.84359 'Period[76]= 45531 ' midi= 87.9609 'Period[77]= 43166 ' midi= 88.88268 'Period[78]= 40463 ' midi= 90 'Period[79]= 37929 ' midi= 91.11731 'Period[80]= 35958 ' midi= 92.0391 'Period[81]= 33706 ' midi= 93.15641 'Period[82]= 32355 ' midi= 93.86314 'Period[83]= 30328 ' midi= 94.98045 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_G: 'Period[72]= 57320 ' midi= 83.98045 'Period[73]= 53733 ' midi= 85.09776 'Period[74]= 50943 ' midi= 86.01955 'Period[75]= 47754 ' midi= 87.13686 'Period[76]= 45841 ' midi= 87.84359 'Period[77]= 42971 ' midi= 88.9609 'Period[78]= 40739 ' midi= 89.88268 'Period[79]= 38188 ' midi= 91 'Period[80]= 35796 ' midi= 92.11731 'Period[81]= 33936 ' midi= 93.0391 'Period[82]= 31810 ' midi= 94.15641 'Period[83]= 30534 ' midi= 94.86314 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_Ab: 'Period[72]= 57711 ' midi= 83.86314 'Period[73]= 54099 ' midi= 84.98044 'Period[74]= 50713 ' midi= 86.09776 'Period[75]= 48079 ' midi= 87.01955 'Period[76]= 45069 ' midi= 88.13686 'Period[77]= 43263 ' midi= 88.84359 'Period[78]= 40555 ' midi= 89.9609 'Period[79]= 38448 ' midi= 90.88269 'Period[80]= 36040 ' midi= 92 'Period[81]= 33782 ' midi= 93.11731 'Period[82]= 32027 ' midi= 94.0391 'Period[83]= 30020 ' midi= 95.15641 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_A: 'Period[72]= 56740 ' midi= 84.15641 'Period[73]= 54467 ' midi= 84.86314 'Period[74]= 51058 ' midi= 85.98045 'Period[75]= 47862 ' midi= 87.09776 'Period[76]= 45376 ' midi= 88.01955 'Period[77]= 42535 ' midi= 89.13686 'Period[78]= 40831 ' midi= 89.84359 'Period[79]= 38274 ' midi= 90.9609 'Period[80]= 36285 ' midi= 91.88269 'Period[81]= 34013 ' midi= 93 'Period[82]= 31882 ' midi= 94.11731 'Period[83]= 30225 ' midi= 95.0391 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_Bb: 'Period[72]= 57841 ' midi= 83.82404 'Period[73]= 53551 ' midi= 85.15641 'Period[74]= 51406 ' midi= 85.86314 'Period[75]= 48188 ' midi= 86.98045 'Period[76]= 45171 ' midi= 88.09776 'Period[77]= 42825 ' midi= 89.01955 'Period[78]= 40144 ' midi= 90.13686 'Period[79]= 38535 ' midi= 90.84359 'Period[80]= 36122 ' midi= 91.9609 'Period[81]= 34244 ' midi= 92.88269 'Period[82]= 32099 ' midi= 94 'Period[83]= 30088 ' midi= 95.11731 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return JI_B: 'Period[72]= 56868 ' midi= 84.11731 'Period[73]= 54591 ' midi= 84.82404 'Period[74]= 50541 ' midi= 86.15641 'Period[75]= 48516 ' midi= 86.86314 'Period[76]= 45479 ' midi= 87.98044 'Period[77]= 42632 ' midi= 89.09776 'Period[78]= 40417 ' midi= 90.01955 'Period[79]= 37886 ' midi= 91.13686 'Period[80]= 36368 ' midi= 91.84359 'Period[81]= 34090 ' midi= 92.9609 'Period[82]= 32318 ' midi= 93.88269 'Period[83]= 30293 ' midi= 95 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 'For i = 60 To 71 ' Period[i] = Period[i+12] 'Next i $ifdef Bass For i = 36 To 60 Period[i] = Period[i+48] Next i $endif $ifdef Tenor For i = 48 To 72 Period[i] = Period[i+36] Next i $endif $ifdef Alto For i = 60 To 84 Period[i] = Period[i+24] Next i $endif $ifdef Soprano For i = 72 To 96 Period[i] = Period[i+12] Next i $endif ' recalculate the pitch-bend ranges: range1 = (Period[note1] - Period[note2]) range2 = (Period[note2] - Period[note3]) range3 = (Period[note3] - Period[note3 + 1]) Return '[EOF]