;-----------------------------------------------------------------------------------------------; ; Program: PSIM Super Sequencer ; ; Developed by David J. Brown ; ; Much of this program was based on the PSIM-CVS Template program ; ; Copyright (c) April 13, 2004 David J. Brown ; ; Email: davebr@earthlink.net ; ; Web site: http://modularsynthesis.com ; ;-----------------------------------------------------------------------------------------------; ; LICENSE AGREEMENT: ; ; This program is free software. You can redistribute it and/or modify it. ; ; ; ; This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY, ; ; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ; ;-----------------------------------------------------------------------------------------------; ; ; Description: ; This program implements a 1 to 16 step sequencer. ; Expansion controls set the note values over 5 volt (octave) range. A control ; voltage and trigger is output along with a MIDI note on/off command. ; ; Menus are used to input and set various program parameters: ; sequence or setup ; number of steps from 1 to 16 (saved in nv memory if AtomPro28 used) ; ordered or random sequencing (default ordered) ; gate1 hi or low for each step in sequence (saved in nv memory if AtomPro28 used) ; gate2 hi or low for each step in sequence (saved in nv memory if AtomPro28 used) ; midi program change for each step in sequence (saved in nv memory if AtomPro28 used) ; offset in semitones to add to midi note value (saved in nv memory if AtomPro28 used) ; ; Inputs: ; Start = Various menu selection input ; Stop = Various menu selection input ; In-1 = User variable selection input ; In-2 = n/a ; In-3 = n/a ; In-4 = n/a ; Aux = Clock In ;Ext In-1 = Step 1 level ;Ext In-2 = Step 2 level ;Ext In-3 = Step 3 level ;Ext In-4 = Step 4 level ;Ext In-5 = Step 5 level ;Ext In-6 = Step 6 level ;Ext In-7 = Step 7 level ;Ext In-8 = Step 8 level ;Ext In-9 = Step 9 level ;Ext In-10= Step 10 level ;Ext In-11= Step 11 level ;Ext In-12= Step 12 level ;Ext In-13= Step 13 level ;Ext In-14= Step 14 level ;Ext In-15= Step 15 level ;Ext In-16= Step 16 level ; ; Outputs: ; Out-1 = CV Out, 0 to 5 volts ; Out-2 = Trigger Out, 5 volts, ~5 mS ; Out-3 = Gate1 Out, 0 to 5 volts ; Out-4 = Gate2 Out, 0 to 5 volts ; Midi-Out= Notes (offset by midi_offset) ; ; Display = Menu selection or step and note number ; Run led = Toggles @ 0.5 S (timer interrupts enabled) ; Stop led= Indicates setup mode ; ; Revision: 0.5 ; Date April 20, 2007 ; History: 0.5 initial conversion of program to PSIM using i2c expansion inputs ; Written: January 21, 2007 ; ;---------ENABLE ATOMPRO28 CONDITIONAL COMPILE OPTION-------------------------------------------; ; ; ; COMMENT OUT NEXT LINE TO ENABLE NV MEMORY WITH AN ATOMPRO28 ; ;ap28_en con 1 ;define to enable AtomPro28 NV memory storage ; ; ;comment to enable AtomPro24 normal operation ; ;---------ENABLE TIMER INTERRUPT CONDITIONAL COMPILE OPTION-------------------------------------; ; Notes: run led will blink to verify timer operation ; ; ; ; COMMENT OUT NEXT LINE TO DISABLE TIMER INTERRUPTS ; timer_int_en con 1 ;define to enable timer interrupts ; ; ;comment to disable timer interrupts ; ;-----------------------------------------------------------------------------------------------; ; BasicMicro AtomPro24 ; ;-----------------------------------------------------------------------------------------------; ; P0 - digital in/out, analog in-1 ; ; P1 - digital in/out, analog in-2 ; ; P2 - digital in/out, analog in-3 ; ; P3 - digital in/out, analog in-4 ; ; P4 - start button (no input/default=0/low, pressed=1/hi) ; ; P5 - stop button (no input/default=0/low, pressed=1/hi) ; ; P6 - i2c data ; ; P7 - i2c clock ; ; P8 - aux in/out (no input/default=1/hi) ; ; P9 - stop led (low=off, hi=on) ; ; P10 - run led (low=off hi=on) ; ; P11 - dac load_dacs ; ; P12 - dac ser_data ; ; P13 - dac clock ; ; P14 - midi-in ; ; P15 - midi-out ; ;-----------------------------------------------------------------------------------------------; ; LCD commands ; ;-----------------------------------------------------------------------------------------------; ; $08 - (backspace) moves the active display position one backwards ; ; $09 - (tab) moves the active display position one forward ; ; $0a - (line feed) clears the display & sets active display position to beginning of line 1 ; ; $0b - (vertical tab) sets the active display position to beginning of line 2 ; ; $0c - (form feed) clears the display & sets active display position to beginning of line 2 ; ; $0d - (carriage return) Sets the active display position to beginning of line 1 ; ; $0e - (shift out) selects the lower characters set for display ; ; $0f - (shift in) selects the upper characters set for display ; ; $10 - program character0 row7, row6 ... row0 (bottom) ; ; $11 - program character1 row7, row6 ... row0 (bottom) ; ; $12 - program character2 row7, row6 ... row0 (bottom) ; ; $13 - program character3 row7, row6 ... row0 (bottom) ; ; $14 - program character4 row7, row6 ... row0 (bottom) ; ; $15 - program character5 row7, row6 ... row0 (bottom) ; ; $16 - program character6 row7, row6 ... row0 (bottom) ; ; $17 - program character7 row7, row6 ... row0 (bottom) ; ; $18 - sets the display mode to overwrite; new characters overwrite previous ; ; $19 - sets the display mode to scroll; display scrolls for new characters ; ; $1a - sets absolute position data ; ; $1b - sets relative position data ; ; $1c - reserved ; ; $1d - reserved ; ; $1e - reserved ; ; $1f - writes new default message character 1, character 2 ... character 32 ; ;-----------------------------------------------------------------------------------------------; ; ;pin declarations pin_j1 con p0 ;in-1 pin pin_j2 con p1 ;in-2 pin pin_j3 con p2 ;in-3 pin pin_j4 con p3 ;in-4 pin start_j var in4 ;start jack and switch stop_j var in5 ;stop jack and switch i2c_data con p6 ;i2c data pin i2c_clk con p7 ;i2c clock pin aux_j con p8 ;aux jack pin (used with high/low/toggle) aux_in var in8 ;aux jack (used for input) stop_led con p9 ;stop led (used with high/low/toggle) stop_led_out var out9 ;stop led alias (used with let) run_led con p10 ;run led (used with high/low/toggle) run_led_out var out10 ;run led alias (used with let) load_dacs con p11 ;load dac pin ser_data con p12 ;dac serial data input pin clock con p13 ;dac clock pin midi_sdata con p15 ;midi data serial output ;i/o declarations in_j1 var word ;in-1 value: get_inputs, get_inputs_avg, avg1 in_j2 var word ;in-2 value: get_inputs, get_inputs_avg, avc2 in_j3 var word ;in-3 value: get_inputs, get_inputs_avg, avg3 in_j4 var word ;in-4 value: get_inputs, get_inputs_avg, avg4 out_j1 var word ;out-1 value: load_outputs out_j2 var word ;out-2 value: load_outputs out_j3 var word ;out-3 value: load_outputs out_j4 var word ;out-4 value: load_outputs hys con 3 ;PSIM hysteresis +/- value in_j1_low var word ;in-1 low value: get_in1_hy in_j1_high var word ;in-1 high value: get_in1_hy ;midi variable declarations allup con $7b ;midi all notes-off command keyup con $80 ;midi note-off command keydn con $90 ;midi note-on command conctrl con $b0 ;midi continuous controller command pgmchg con $c0 ;midi program change command chnprs con $d0 ;midi channel pressure command pitchb con $e0 ;midi pitch bend command midi_chan var nib ;midi channel: send_note_on, send_note_off, send_cc, send_prog_change midi_note var byte ;midi note value: send_note_on, send_note_off midi_vel var byte ;midi velocity value: send_note_on, send_note_off midi_pgm var byte ;midi program change value: send_prog_change midi_cc var byte ;midi continuous controller number: send_cc midi_data var byte ;variable: send_midi, send_note_on, send_note_off ;timer declarations #ifdef timer_int_en time_count var long ;1 mS timer count value: tm_isr turn_off var long ;time value to turn off stop led: tm_isr #endif ;display declarations num_data var word ;data for ascii conversion: hex2ascii tths var byte ;ten thousands digit: hex2ascii thos var byte ;thousands digit: hex2ascii huns var byte ;hundreds digit: hex2ascii tens var byte ;tens digit: hex2ascii ones var byte ;ones digit: hex2ascii ;misc declarations fivevolts con 1920 ;5 volt output value temp1 var word ;temporary local variable ;program declarations seq_flg var byte ;sequential or random flag rnd_num var long ;random number sel_flg var byte ;selection flag: select midi_flg var byte ;note sent flag: clk_h midi_offset var word ;midi offset in semitones gate1 var word ;gate1 values gate2 var word ;gate2 valuse mask var word ;mask for bit indexing ctrl_v var word(16) ;input control values step_num var byte ;sequencer step count step_max var word ;maximum steps out_v var word ;output value note_oct var byte ;note octave note_num var byte ;note number within octave note_asc var byte ;note ascii value note_sh var byte ;note sharp or space last_patch var byte ;last program change patch patch var byte(8) ;step program change patchs ; ;-----------------------------------------------------------------------------------------------; ; Tables ; ;-----------------------------------------------------------------------------------------------; ; step_tbl bytetable 256,128,86,64,52,43,37,32,29,26,24,22,20,19,18,17 ;byte to step max divisors note_tbl bytetable "C C",$02,"D D",$02,"E F F",$02,"G G",$02,"A A",$02,"B ";semitone number to note conversion gate_tbl bytetable "084C2A6E195D3B7F" ;gate hex value conversion patch_tbl bytetable | ;GM instrument patch names "AcouGrnd", | ; 1 "BrightAc", | ; 2 "ElecGrnd", | ; 3 "HonkyTnk", | ; 4 "ElPiano1", | ; 5 "ElPiano2", | ; 6 "Harpscrd", | ; 7 "Clavinet", | ; 8 "Celesta ", | ; 9 "Glcknspl", | ;10 "MusicBox", | ;11 "Vibraphn", | ;12 "Marimba ", | ;13 "Xylophon", | ;14 "TubBells", | ;15 "Dulcimer", | ;16 "Drawbar ", | ;17 "Perc Org", | ;18 "Rock Org", | ;19 "Church ", | ;20 "Reed Org", | ;21 "Acordian", | ;22 "Harmnica", | ;23 "TangoAcc", | ;24 "NylonGtr", | ;25 "SteelGtr", | ;26 "Jazz Gtr", | ;27 "CleanGtr", | ;28 "MutedGtr", | ;29 "OverDriv", | ;30 "Distortn", | ;31 "Harmonic", | ;32 "AcouBass", | ;33 "FingerAc", | ;34 "PickBass", | ;35 "Fretless", | ;36 "Slp1Bass", | ;37 "Slp2Bass", | ;38 "SynBass1", | ;39 "SynBass2", | ;40 "Violin ", | ;41 "Viola ", | ;42 "Cello ", | ;43 "Contra ", | ;44 "Trem Str", | ;45 "Pizicato", | ;46 "Orchestl", | ;47 "Timpani ", | ;48 "StrEnsm1", | ;49 "StrEnsm2", | ;50 "SynStr1 ", | ;51 "SynStr2 ", | ;52 "ChoirAhs", | ;53 "VoiceOhs", | ;54 "SynthVoc", | ;55 "OrchHits", | ;56 "Trumpet ", | ;57 "Trombone", | ;58 "Tuba ", | ;59 "MuteTrmp", | ;60 "FrnchHrn", | ;61 "BrassSec", | ;62 "SynBrss1", | ;63 "SynBrss2", | ;64 "SoprnSax", | ;65 "Alto Sax", | ;66 "TenorSax", | ;67 "Baritone", | ;68 "Oboe ", | ;69 "English ", | ;70 "Bassoon ", | ;71 "Clarinet", | ;72 "Piccolo ", | ;73 "Flute ", | ;74 "Recorder", | ;75 "PanFlute", | ;76 "BlownBtl", | ;77 "Shakuhac", | ;78 "Whistle ", | ;79 "Ocarina ", | ;80 "SquareWv", | ;81 "Sawtooth", | ;82 "Calliope", | ;83 "Chiff Ld", | ;84 "Charang ", | ;85 "Voice Ld", | ;86 "5thsLead", | ;87 "BassLead", | ;88 "New Age ", | ;89 "Warm Syn", | ;90 "Poly Syn", | ;91 "ChoirPad", | ;92 "BowedPad", | ;93 "Metallic", | ;94 "Halo Pad", | ;95 "SweepPad", | ;96 "Rain Fx ", | ;97 "Soundtrk", | ;98 "Crystal ", | ;99 "Atmosphr", | ;100 "Britness", | ;101 "Goblins ", | ;102 "EchoesFx", | ;103 "SciFi Fx", | ;104 "Sitar ", | ;105 "Banjo ", | ;106 "Shamisen", | ;107 "Koto ", | ;108 "Kalimba ", | ;109 "Bag Pipe", | ;110 "Fiddle ", | ;111 "Shanai ", | ;112 "TinklBel", | ;113 "Agogo ", | ;114 "SteelDrm", | ;115 "Woodblok", | ;116 "TaikoDrm", | ;117 "Melodic ", | ;118 "Syn Drum", | ;119 "RevCymbl", | ;120 "Gtr Fret", | ;121 "Breath ", | ;122 "Seashore", | ;123 "BrdTweet", | ;124 "Tel Ring", | ;125 "Helicptr", | ;126 "Applause", | ;127 "Gunshot " ;128 ; ;-----------------------------------------------------------------------------------------------; ; AtomPro28 NV Memory ; ;-----------------------------------------------------------------------------------------------; #ifdef ap28_en ; address variable ; ------- -------- nv_step_max con 0 ;addr000 step_max nv_midi_offset con 1 ;addr001 midi_offset nv_gate1_lo con 2 ;addr002 gate1.byte0 nv_gate1_hi con 3 ;addr003 gate1.byte1 nv_gate2_lo con 4 ;addr004 gate2.byte0 nv_gate2_hi con 5 ;addr005 gate2.byte1 nv_patch con 6 ;addr006 step 1 patch ;nv_patch(1) con 7 ;addr007 step 2 patch ;nv_patch(2) con 8 ;addr008 step 3 patch ;nv_patch(3) con 9 ;addr009 step 4 patch ;nv_patch(4) con 10 ;addr010 step 5 patch ;nv_patch(5) con 11 ;addr011 step 6 patch ;nv_patch(6) con 12 ;addr012 step 7 patch ;nv_patch(7) con 13 ;addr013 step 8 patch ;nv_patch(8) con 14 ;addr014 step 9 patch ;nv_patch(9) con 15 ;addr015 step 10 patch ;nv_patch(10) con 16 ;addr016 step 11 patch ;nv_patch(11) con 17 ;addr017 step 12 patch ;nv_patch(12) con 18 ;addr018 step 13 patch ;nv_patch(13) con 19 ;addr019 step 14 patch ;nv_patch(14) con 20 ;addr020 step 15 patch ;nv_patch(15) con 21 ;addr021 step 16 patch #endif ; ;-----------------------------------------------------------------------------------------------; ; Program ; ;-----------------------------------------------------------------------------------------------; ; ;initialize pins #ifdef ap28_en dires=%0000000000000000 ;configure pin direction (1=output, 0=input) ;note: PSIM modified with AtomPro28 #endif dirs=%0001011000000000 ;configure pin direction (1=output, 0=input) ;note: setting midi-out, i2c_clock, i2c_data, and load_dacs to outputs can glitch so initialize as inputs ;inputs: midi-in, aux, start, stop, in-4, in-3, in-2, in-1 ;initialize as inputs: midi-out, clock, load_dacs, ic2_data, ic2_clk ;outputs: ser_data, stop led, run led high load_dacs ;set dac load high high clock ;set dac clock high so cs can not advance low run_led ;reset run led low stop_led ;reset stop led ;initialize outputs let out_j1=0 ;set out-1 low let out_j2=0 ;set out-2 low let out_j3=0 ;set out-3 low let out_j4=0 ;set out-4 low gosub load_outputs ;initialize input variables let in_j1_low=0 ;initialize in-1 hysteresis values let in_j1_high=2*hys ;initialize midi variables let midi_chan=0 ;set midi channel let midi_note=0 ;set midi note let midi_vel=64 ;set default velocity ;initialize timerW hardware for 1 mS #ifdef timer_int_en let tmrw=%10001000 ;set Timer Mode Register to enable count let tcrw=%10110000 ;set Timer Control Register ; clear on compare match A ; 16 MHz clock /8 prescalar S = 2 MHz timer clock let gra=2000 ;2 MHz / 2000 = 1 mS ;enable timerW interrupts let time_count=0 ;reset real time count let turn_off=0 ;reset turn off time oninterrupt timerwint_imiea, tm_isr enable timerwint_imiea ;enable timer interrupt #endif ;enable midi interrupts enablehserial sethserial h31200,h8databits,hnoparity,h1stopbits ;initialize display pause 50 ;let display start hserout [$f0,$7d,$10,$01,$7f,$09,$00,$0b,$11,$0e,$f7] ;character0 G1 (sideways) hserout [$f0,$7d,$11,$09,$15,$13,$00,$0b,$11,$0e,$f7] ;character1 G2 (sideways) ;character2 default sharp hserout [$f0,$7d,$13,$07,$04,$04,$04,$04,$04,$1c,$f7] ;character3 rising edge hserout [$f0,$7d,$14,$1f,$00,$00,$00,$00,$00,$00,$f7] ;character4 high level hserout [$f0,$7d,$15,$1c,$04,$04,$04,$04,$04,$07,$f7] ;character5 falling edge hserout [$f0,$7d,$16,$00,$00,$00,$00,$00,$00,$1f,$f7] ;character6 low level hserout [$f0,$7d,$17,$00,$00,$0a,$00,$11,$0e,$00,$f7] ;character7 smiley face hserout [$f0,$7d,$0a,$18,"PSIM Sequencer ",$07," David J. Brown ",$f7] ;clear, overwrite, name gosub send_all_off ;ensure no stuck notes ; ;-----------------------------------------------------------------------------------------------; ; Main Program ; ;-----------------------------------------------------------------------------------------------; ; pause 2000 ;display program name before starting ;initialize program parameters let rnd_num=1 ;start with non-zero number let midi_flg=0 ;indicate no notes on let seq_flg=1 ;default to sequential let last_patch=255 ;set last patch invalid #ifdef ap28_en ;get non-volatile parameters if using AtomPro28 ;these will be valid after first program execution read nv_step_max,step_max ;get number of steps read nv_gate1_hi,gate1.byte1 ;get gate1 read nv_gate1_lo,gate1.byte0 read nv_gate2_hi,gate2.byte1 ;get gate2 read nv_gate2_lo,gate2.byte0 read nv_midi_offset,midi_offset ;get midi_offset for temp1=0 to 15 ;get patchs read nv_patch+temp1,patch(temp1) next #else ;set parameter defaults if using AtomPro24 let step_max=16 ;default steps to 16 let gate1=$ffff ;default gate1 to all high let gate2=$5555 ;default gate2 to alternating let midi_offset=36 ;default midi offset up 3 octaves let patch(0) =0 ;default patch to Accoustic Grand let patch(1) =0 ;default patch to Accoustic Grand let patch(2) =0 ;default patch to Accoustic Grand let patch(3) =0 ;default patch to Accoustic Grand let patch(4) =0 ;default patch to Accoustic Grand let patch(5) =0 ;default patch to Accoustic Grand let patch(6) =0 ;default patch to Accoustic Grand let patch(7) =0 ;default patch to Accoustic Grand let patch(8) =0 ;default patch to Accoustic Grand let patch(9) =0 ;default patch to Accoustic Grand let patch(10)=0 ;default patch to Accoustic Grand let patch(11)=0 ;default patch to Accoustic Grand let patch(12)=0 ;default patch to Accoustic Grand let patch(13)=0 ;default patch to Accoustic Grand let patch(14)=0 ;default patch to Accoustic Grand let patch(15)=0 ;default patch to Accoustic Grand #endif ; ;menu choice to sequence or setup start: high stop_led ;indicate setup mode hserout [$f0,$7d,$0a,"Start? Sequence Stop? Setup ",$f7] ;display choice gosub select ;get input if sel_flg=1 then sequence ;menu choice to set number of steps let num_data=step_max gosub hex2ascii hserout [$f0,$7d,$0a,"Start? Steps ",tens,ones," Stop? Modify ",$f7] ;display choice gosub select ;get input if sel_flg=1 then set_rnd hserout [$f0,$7d,$0a,"In-1? Steps Start? Select ",$f7] ;display choice set_step: pause 20 gosub get_in1_hy ;get in-1 using hysteresis let step_max=(in_j1/64)+1 ;allow 1-16 let num_data=step_max gosub hex2ascii hserout [$f0,$7d,$1a,$0d,tens,ones,$f7] ;display steps if start_j=0 then set_step ;continue set_step1: ;start switch pause 20 if start_j=1 then set_step1 ;wait for release ; write nv_step_max,step_max ;nv save step_max ;menu choice sequential or random set_rnd: hserout [$f0,$7d,$0a,"Start? Ordered Stop? Random ",$f7] ;display choice gosub select ;get input let seq_flg=sel_flg ;start=sequential ;menu choice to set gate1 set1_gate: let step_num=0 ;start at the beginning hserout [$f0,$7d,$0a,"Start? Gt1 "] ;display choice hserout [gate_tbl(gate1.nib0),gate_tbl(gate1.nib1),gate_tbl(gate1.nib2),gate_tbl(gate1.nib3)] hserout [" Stop? Modify ",$f7] gosub select ;get input if sel_flg=1 then set2_gate set1_gate1: let mask=dcd (step_num+1) ;calculate bit index let num_data=step_num+1 gosub hex2ascii hserout [$f0,$7d,$0a,"Start? Step ",tens,ones," Stop? Rev Gt1 ",$f7] ;display choice set1_gate2: if (gate1&mask)<>0 then ;check gate1 level hserout [$f0,$7d,$1a,$1e,$03,$04,$f7] ;display level hi else hserout [$f0,$7d,$1a,$1e,$05,$06,$f7] ;display level lo endif gosub select ;get input if sel_flg=0 then ;toggle gate1 level let gate1=gate1^mask goto set1_gate2 ;display new level endif let step_num=step_num+1 ;increment step if step_num<>step_max then set1_gate1 ;check if done #ifdef ap28_en write nv_gate1_hi,gate1.byte1 ;nv save gate1 write nv_gate1_lo,gate1.byte0 #endif goto set1_gate ;do next step ; ;menu choice to set gate2 set2_gate: let step_num=0 ;start at the beginning hserout [$f0,$7d,$0a,"Start? Gt2 "] ;display choice hserout [gate_tbl(gate2.nib0),gate_tbl(gate2.nib1),gate_tbl(gate2.nib2),gate_tbl(gate2.nib3)] hserout [" Stop? Modify ",$f7] gosub select ;get input if sel_flg=1 then set_midi set2_gate1: let mask=dcd (step_num+1) ;calculate bit index let num_data=step_num+1 gosub hex2ascii hserout [$f0,$7d,$0a,"Start? Step ",tens,ones," Stop? Rev Gt2 ",$f7] ;display choice set2_gate2: if (gate2&mask)<>0 then ;check gate2 level hserout [$f0,$7d,$1a,$1e,$03,$04,$f7] ;display level hi else hserout [$f0,$7d,$1a,$1e,$05,$06,$f7] ;display level lo endif gosub select ;get input if sel_flg=0 then ;toggle gate2 level let gate2=gate2^mask goto set2_gate2 ;display new level endif let step_num=step_num+1 ;increment step if step_num<>step_max then set2_gate1 ;check if done #ifdef ap28_en write nv_gate2_hi,gate2.byte1 ;nv save gate2 write nv_gate2_lo,gate2.byte0 #endif goto set2_gate ;do next step ; ;menu choice to set midi program change set_midi: let step_num=0 ;initialize step number hserout [$f0,$7d,$0a,"Start? NextMenu Stop? SetPatch ",$f7] ;display choice gosub select ;get input if sel_flg=1 then set_offset set_midi1: hserout [$f0,$7d,$0a,"Step",$0b,"Stop? Modify ",$f7] ;initialize display hserout [$f0,$7d,$1a,$05,dec step_num+1," ",$f7] ;display step number and space let midi_pgm=patch(step_num) ;get program change patch hserout [$f0,$7d,$1a,$08] ;set LCD position for temp1=0 to 7 ;get characters of patch name hserout [patch_tbl((midi_pgm*8)+temp1)] ;display patch name next hserout [$f7] ;complete lcd message gosub select ;get input if sel_flg=1 then set_midi4 ;check if done with this step hserout [$f0,$7d,$0a,"In-1?",$0b,"Start? Select ",$f7] ;display choice set_midi2: pause 20 gosub get_in1_hy ;get in-1 using hysteresis let midi_pgm=(in_j1/8) ;allow 0 - 127 let patch(step_num)=midi_pgm ;set patch hserout [$f0,$7d,$1a,$08] ;set LCD position for temp1=0 to 7 ;get characters of patch name hserout [patch_tbl((midi_pgm*8)+temp1)] ;display patch name next hserout [$f7] ;complete lcd message if start_j=0 then set_midi2 ;continue set_midi3: ;start switch pause 20 if start_j=1 then set_midi3 ;wait for release #ifdef ap28_en write nv_patch+step_num,patch(step_num) ;nv save patch #endif set_midi4: let step_num=step_num+1 ;go to next step if step_num=step_max then set_midi ;check for end goto set_midi1 ;continue with next step ; ;menu choice for midi offset set_offset: let num_data=midi_offset gosub hex2ascii hserout [$f0,$7d,$0a,"Start? Midi+N ",tens,ones,"Stop? Modify ",$f7] ;display choice gosub select ;get input if sel_flg=1 then adj_step hserout [$f0,$7d,$0a,"In-1? Midi+N Start? Select ",$f7] ;display choice set_offset1: pause 20 gosub get_in1_hy ;get in-1 using hysteresis let midi_offset=(in_j1/21) ;allow 0 - 48 let num_data=midi_offset gosub hex2ascii hserout [$f0,$7d,$1a,$0e,tens,ones,$f7] ;display gate set if start_j=0 then set_offset1 ;continue set_offset2: ;start switch pause 20 if start_j=1 then set_offset2 ;wait for release #ifdef ap28_en write nv_midi_offset,midi_offset ;nv save midi_offset #endif ;menu choice to set levels adj_step: let step_num=0 ;initialize step number hserout [$f0,$7d,$0a,"Start? NextMenu Stop? SetLevels",$f7] ;display choice gosub select ;get input if sel_flg=1 then start hserout [$f0,$7d,$0a,"Step",$0b,"Note Start?",$f7] ;initialize display adj_step1: hserout [$f0,$7d,$1a,$05,dec step_num+1," ",$f7] ;display step number and space let midi_pgm=patch(step_num) ;get program change patch hserout [$f0,$7d,$1a,$08] ;set LCD position for temp1=0 to 7 ;get characters of patch name hserout [patch_tbl((midi_pgm*8)+temp1)] ;display patch name next hserout [$f7] ;complete lcd message gosub in_val ;get input gosub out_val ;output and display value if start_j=0 then adj_step3 ;check forward select adj_step2: pause 20 ;debounce switch if start_j=1 then adj_step2 ;wait for release let let step_num=step_num+1 ;increment step number if step_num<>step_max then adj_step1 ;check for end goto adj_step ;decide if sequence or adjust ; adj_step3: if stop_j=0 then adj_step1 ;check backward select adj_step4: pause 20 ;debounce switch if stop_j=1 then adj_step4 ;wait for release let let step_num=step_num-1 ;decrement step number if step_num=255 then ;check for beginning let step_num=step_max-1 ;reset to end of sequence endif goto adj_step1 ;continue ; ;sequence sequence: low stop_led ;indicate sequence mode if seq_flg=1 then ;check random or sequential hserout [$f0,$7d,$0a,"Step",$0b,"Note ",$00," ",$01," ",$f7] ;initialize sequential display else hserout [$f0,$7d,$0a,"Rndm",$0b,"Note ",$00," ",$01," ",$f7] ;initialize random display endif let step_num=step_max-1 ;setup to start with step 1 goto clk_l ;wait for clock low to prevent short first cycle ; clk_h: pause 20 ;debounce switch if stop_j=1 then restart ;check stop if aux_in=0 then clk_h ;check for clock high transition let num_data=step_num+1 gosub hex2ascii hserout [$f0,$7d,$1a,$05,tens,ones,$f7] ;display step number let midi_pgm=patch(step_num) ;get patch hserout [$f0,$7d,$1a,$08] ;set LCD position for temp1=0 to 7 ;get characters of patch name hserout [patch_tbl((midi_pgm*8)+temp1)] ;display patch name next hserout [$f7] ;complete lcd message let out_j2=fivevolts ;set trigger if (gate1&mask)<>0 then ;check gate1 levels let out_j3=fivevolts ;set gate1 high hserout [$f0,$7d,$1a,$1a,$03,$04,$f7] ;display step level hi else let out_j3=0 ;set gate1 low hserout [$f0,$7d,$1a,$1a,$05,$06,$f7] ;display step level lo endif if (gate2&mask)<>0 then ;check gate2 levels let out_j4=fivevolts ;set gate2 high hserout [$f0,$7d,$1a,$1e,$03,$04,$f7] ;display step level hi else let out_j4=0 ;set gate2 low hserout [$f0,$7d,$1a,$1e,$05,$06,$f7] ;display step level lo endif gosub in_val ;get input gosub out_val ;set output value and display value gosub load_outputs ;set outputs if midi_pgm<>last_patch then ;check if different let last_patch=midi_pgm ;yes so save new patch gosub send_prog_change ;send program change endif if midi_flg=1 then ;check if sent note on gosub send_note_off ;yes so send note off endif let midi_note=out_v+midi_offset ;offset up several octaves gosub send_note_on let midi_flg=1 ;set flag to indicate note on pause 5 shiftout ser_data,clock,4,[$8000\16] ;reset trigger pulsout load_dacs,1 ;clock loaddacs clk_l: pause 20 ;debounce switch if stop_j=1 then restart ;check stop if aux_in=1 then clk_l ;wait for clock low transition if seq_flg=1 then ;check random or sequential let step_num=step_num+1 if step_num=step_max then ;check for end of sequence step_num=0 endif else let rnd_num=random(rnd_num) let step_num=(rnd_num.byte0^rnd_num.byte1^rnd_num.byte2^rnd_num.byte3) let step_num=step_num/(step_tbl(step_max-1)) ;keep to proper number of bits endif let mask=dcd (step_num+1) ;calculate bit index goto clk_h ; restart: pause 20 if stop_j=1 then restart let out_j1=0 ;reset all outputs let out_j2=0 let out_j3=0 let out_j4=0 gosub load_outputs if midi_flg=1 then ;check if sent note on gosub send_note_off ;yes so send note off let midi_flg=0 ;indicate no notes on endif goto start ; ;get external input values ;ctrl_v(x)=input values ;written by David J. Brown in_val: let step_num=step_num&$0f ;make sure only 16 steps maximum branch step_num,[ain1,ain2,ain3,ain4,ain5,ain6,ain7,ain8,ain9,ain10,ain11,ain12,ain13,ain14,ain15,ain16] ;get individual inputs ain1: i2cin i2c_data,i2c_clk,in_error,$98,$00,[ctrl_v(0),ctrl_v(0)] return ain2: i2cin i2c_data,i2c_clk,in_error,$98,$01,[ctrl_v(1),ctrl_v(1)] return ain3: i2cin i2c_data,i2c_clk,in_error,$98,$02,[ctrl_v(2),ctrl_v(2)] return ain4: i2cin i2c_data,i2c_clk,in_error,$98,$03,[ctrl_v(3),ctrl_v(3)] return ain5: i2cin i2c_data,i2c_clk,in_error,$9a,$00,[ctrl_v(4),ctrl_v(4)] return ain6: i2cin i2c_data,i2c_clk,in_error,$9a,$01,[ctrl_v(5),ctrl_v(5)] return ain7: i2cin i2c_data,i2c_clk,in_error,$9a,$02,[ctrl_v(6),ctrl_v(6)] return ain8: i2cin i2c_data,i2c_clk,in_error,$9a,$03,[ctrl_v(7),ctrl_v(7)] return ain9: i2cin i2c_data,i2c_clk,in_error,$9c,$00,[ctrl_v(8),ctrl_v(8)] return ain10: i2cin i2c_data,i2c_clk,in_error,$9c,$01,[ctrl_v(9),ctrl_v(9)] return ain11: i2cin i2c_data,i2c_clk,in_error,$9c,$02,[ctrl_v(10),ctrl_v(10)] return ain12: i2cin i2c_data,i2c_clk,in_error,$9c,$03,[ctrl_v(11),ctrl_v(11)] return ain13: i2cin i2c_data,i2c_clk,in_error,$9e,$00,[ctrl_v(12),ctrl_v(12)] return ain14: i2cin i2c_data,i2c_clk,in_error,$9e,$01,[ctrl_v(13),ctrl_v(13)] return ain15: i2cin i2c_data,i2c_clk,in_error,$9e,$02,[ctrl_v(14),ctrl_v(14)] return ain16: i2cin i2c_data,i2c_clk,in_error,$9e,$03,[ctrl_v(15),ctrl_v(15)] return in_error: return ; ;output value and display note ;step_num=current step number ;written by David J. Brown out_val: let out_v=ctrl_v(step_num) let out_v=((out_v*4)/17)*32 ;scale and quantize let out_j1=out_v let out_v=out_v>>5 ;reduce output to semitone number let note_oct=out_v/12 ;calulate octave let note_num=(out_v-(note_oct*12))*2 ;calculate note number within octave (X2 for lookup) let note_asc=note_tbl(note_num) ;calculate note ascii value let note_sh=note_tbl(note_num+1) ;get # or space let note_oct=note_oct+$30 ;convert octave to ascii hserout [$f0,$7d,$1a,$15,note_asc,note_oct,note_sh,$f7] ;display note return ; ;wait for selection ;sel_data_flg=1 if start select: let rnd_num=rnd_num+1 ;vary random seed pause 20 ;debounce switch if start_j=1 then sel3 ;check start if stop_j=0 then select ;check stop sel2: pause 20 ;debounce switch if stop_j=1 then sel2 ;wait for stop release let sel_flg=0 ;indicate stop return sel3: pause 20 ;debounce switch if start_j=1 then sel3 ;wait for start release let sel_flg=1 ;indicate start return ; ;sample in-1 with hysteresis ;in_jx is input value (0 - 1023) ;140 uS execution time for PSIM ;written by David J. Brown get_in1_hy: adin pin_j1,in_j1 let in_j1=in_j1+hys ;offset for compare at zero if in_j1>in_j1_low then ;check lower range if in_j1