PIC Mapping for midi to LPT decoder for musical robots using Intel 8254 Timer chips: ************************************************************************************ last update: 30.01.2005 Workout for Default midi channel (set with DIP switch)= 10 ( = binary 1010) Note that has a slightly different demultiplex board than Tubi. The circuit details are published on the page on the Logos website. data-port: RB0-RB7 Port B van de PIC, alle bits geflipt: RB7 ==> D0 pic pin 28 RB6 ==> D1 pic pin 27 RB5 ==> D2 pic pin 26 RB4 ==> D3 pic pin 25 RB3 ==> D4 pic pin 24 RB2 ==> D5 pic pin 23 RB1 ==> D6 pic pin 22 RB0 ==> D7 pic pin 21 adres-bus using port A, bits 0-5 Port A van de PIC: RA0 = bit 0 van Reg pic pin 2 RA1 = bit 1 van Reg pic pin 3 RA2 = bit 2 van Reg pic pin 4 RA3 = nc pic pin 5 RA4 = channel select dil switch bit 0 pic pin 6 bit0 RA5 = channel select DIL switch bit 1 pic pin 7 bit1 Port C van de PIC: RC0 = Timer 1 output. Test LED op PIC board (zoals op het board) LED via 1k2 naar GND. pic pin 11 RC1 = nc pic pin 12 RC2 = nc pic pin 13 RC3 = strobe bit (high at rest) pic pin 14 RC4 = channel select DIL switch bit2 pic pin 15 bit 2 RC5 = channel select DIL switch bit3 pic pin 16 bit 3 RC6 = serial output MIDI for debug pic pin 17 RC7 = serial input for MIDI data pic pin 18 (zoals op alle boards) GROUND: pic pin 19 pic pin 8 POSITIVE SUPPLY: 5V dc pic pin 20 Note1: we connect RA4, RA5, RC4, RC5 to a DIL switch for setting the midi-channel (0-F) (read only on startup or after PIC reset). Note2: it is essential that all data on the ports be stable before the strobe goes low. At rest, RA3 should always be high. Strobe duration must be 1 microsecond. Software implementation: ' constants: strobe = RC3, at rest should always be high. dport = RB7-RB0 (8 bits) aport = RA0-RA2 ( 3bits) (RA3 can be kept always low, such that we can always send a nibble) reg(0) => RA0 = 1, RA1 = 0, RA2 = 1 (dec. 5) reg(1) => RA0 = 0, RA1 = 0, RA2 = 1 (dec. 4) reg(2) => RA0 = 1, RA1 = 1, RA2 = 1 (dec. 7) reg(3) => RA0 = 0, RA1 = 1, RA2 = 1 (dec. 6) reg(4) => RA0 = 1, RA1 = 0, RA2 = 0 (dec. 1) reg(5) => RA0 = 0, RA1 = 0, RA2 = 0 (dec. 0) reg(6) => RA0 = 1, RA1 = 1, RA2 = 0 (dec. 3) reg(7) => RA0 = 0, RA1 = 1, RA2 = 0 (dec. 2) global variables: midichannel as byte dampmode as byte sustain as byte ' procedure prototypes: Vibi_Initialize local n as byte ' should be called on startup CALL Tubi_Stop ' make sure power is OFF for n = 60 to 107 ' 96 is the note limit, but we have more timers on board. CALL Vibi_Beat n, 20 ' zie proc. - this will be inaudible since we have no power yet CALL Vibi_Damp n, 20 next n CALL Vibi_Read_Port ' only read after a reset of the PIC CALL Vibi_Start ' autostart end Vibi_Read_Port IF RA4 = 1 then bit set (midichannel, 0) else bit reset (midichannel, 0) IF RA5 = 1 then bit set (midichannel, 1) else bit reset (midichannel, 1) IF RC4 = 1 then bit set (midichannel, 2) else bit reset (midichannel, 2) IF RC5 = 1 then bit set (midichannel, 3) else bit reset (midichannel, 3) end Vibi_Start ' sends pincode to board: (switch on the high power supply) ' this proc. should be called on reception of midi controller 66 with param = %true out dport, 251 ' pincode number out aport, reg(3) strobe out aport, reg(2) out dport, 251 ' required for start up of the basic stamps (BS2) strobe (RC3 high to low and back to high for 1 microsecond) end Vibi_Stop ' sends inverted pincode to board:(high power supply switched off ' not implemented on Vibi hardware yet out dport, 5 ' inverted pincode out aport, reg(2) ' port nr.3 - ext1port strobe out aport, reg(3) strobe '(RC3 high to low and back to high for 1 microsecond) end Vibi_Beat (note as byte, velo as byte) ' this is the 8 bit msb only code for the timer chips ' notes 60-96 = normal pitches local cw as dword local wvelo as dword if velo = 0 then exit function if note < 60 then exit function if note > 107 then exit function note = note - 60 wvelo = 3584 + ((velo * velo) /2) ' kwadratisch 3584-10648 velo = HIBYT(wvelo) cw = n MOD 3 ' control word , here 0,1,2 shift left cw, 6 ' put bits in the right place for the timer chip: D7 en D6 = select timer bit set cw,5 ' set bit 5, so be use msb only. (setting bit 4 would be lsb only) ' velo: ' in 256 microsecond increments ' thus the range is 0.256ms to 32 ms for 1-127 velo. out aport, reg(1) ' 2 bitlines velodatabus out dport, 3 ' set both lines high, write a command to the 82C54 strobe out aport, reg(0) ' databus 8 bit out dport, cw ' write program byte to the bus strobe out aport, reg(5) ' cause strobe on the 74154's out dport, note \ 3 ' chip number strobe out aport, reg(7) ' strobe ' now send the required data to the timer: out aport, reg(1) out dport, note MOD 3 ' 0=timer0 1=timer1 2=timer2 3=control strobe out dport, note \ 3 ' prepare chip selector out aport, reg(5) strobe ' send 1 byte of timer data out aport, reg(0) out dport, velo strobe out aport, reg(7) ' generate a strobe strobe ' now the counter should be counting... end Vibi_Damp (note as byte, velo as byte) ' should be called on reception of note off + release. ' notes 60-96 = normal pitches ' here there is less of a benefit in using 16 bit. local cw as dword local wvelo as dword if velo = 0 then exit function ' no damping if note < 60 then exit function if note > 96 then exit function note = note - 12 ' harware mapped op notes 48 - 84 wvelo = velo * velo ' kwadratisch if wvelo < 3600 then wvelo = 3600 ' opgelet , andere scaling dan vibi_beat!!! velo = HIBYT(wvelo) cw = n MOD 3 ' control word , here 0,1,2 shift left cw, 6 ' put bits in the right place for the timer chip: D7 en D6 = select timer bit set cw,5 ' set bit 5, so be use msb only. (setting bit 4 would be lsb only) ' velo: ' in 256 microsecond increments ' thus the range is 0.256ms to 32 ms for 1-127 velo. out aport, reg(1) ' 2 bitlines velodatabus out dport, 3 ' set both lines high, write a command to the 82C54 strobe out aport, reg(0) ' databus 8 bit out dport, cw ' write program byte to the bus strobe out aport, reg(5) ' cause strobe on the 74154's out dport, note \ 3 ' chip number strobe out aport, reg(7) ' strobe ' now send the required data to the timer: out aport, reg(1) out dport, note MOD 3 ' 0=timer0 1=timer1 2=timer2 3=control strobe out dport, note \ 3 ' prepare chip selector out aport, reg(5) strobe ' send 1 byte of timer data out aport, reg(0) out dport, velo strobe out aport, reg(7) ' generate a strobe strobe ' now the counter should be counting... end function Vibi_Motor (motornumber, speed) select case motornumber case 0 out dport, speed out aport, reg(3) ' port 4 - ext.2 port strobe case 1 out dport, speed out aport, reg(2) strobe case 2 out dport speed out aport, reg(3) strobe out aport, reg(2) strobe end select end function Vibi_Beat_16bitcoding (note, velo) local wvelo as dword local cw as dword ' this did not work on the wintel platform... IF note < 60 then exit function if note > 107 then exit function if isfalse velo then exit function note = note - 60 'wvelo = 3584 + ((velo * velo) /2) ' kwadratisch 3600-11648 wvelo = 3584 + (velo * 100) ' lineair in 100microsec. stapjes 3584 tot 16284 cw = note MOD 3 shift left cw, 6 bit set cw, 4 bit set cw, 5 out aport, reg(1) out dport, 3 ' command strobe out aport, reg(0) out dport, cw strobe out aport, reg(5) out dport, note \ 3 ' chip number - integer divide strobe out aport, reg(7) strobe out aport, reg(1) out dport, note MOD 3 strobe out aport, reg(5) out dport, note \ 3 strobe ' now send lsb: out aport, reg(0) out dport, LOBYT(wvelo) strobe out aport, reg(7) strobe ' then msb: out aport, reg(0) out dport, HIBYT(wvelo) strobe out aport, reg(7) strobe ' lsb-msb send, timer should be counting... end function FUNCTION Vibi_Midi_Input () static init static dampval static dampmode ' 0 = use the damp value as set with the controller ' 1 = use note-off + release for damping control static sustain ' 1 = no damping if isfalse init then 'Initialisation of default values: sustain = %False dampmode = %False damptim = 64 dampval = 80 init = %True end if if statusbyte = controller then select case controller case 20 Vibi_Motor, 0, value case 21 Vibi_Motor, 1, value case 22 Vibi_Motor, 2, value case 23 dampval = value case 24 if value then dampmode = %True else dampmode = %False case 64 ' sustain pedal if value the sustain = %true else sustain = %False case 66 CALL Vibi_On ' quite impossible with vibi hardware... case 123 sustain = %False dampmode = %False dampval = 80 Call Vibi_All_Off case 127 ' reset PIC, reread receive channel end select end if if statusbyte = note-on then select case note case > 59 select case velo case %False if isfalse sustain then if dampval then if dampmode then CALL Vibi_Damp noot, dampval else ' niks - note-off release should be used. end if end if else ' no damping at all !!! end if case else CALL Vibi_Beat noot, velo end select case 12 to 48 ' play with the dampers as beaters! note = note + 48 CALL Vibi_Damp noot, velo end select end if if statusbyte = note-off then select case value case %False ' no damping case else select case dampmode case %False CALL Vibi_Damp, noot, value case %True IF dampval then CALL Vibi_Damp, noot, dampval ' improper coding by user end if end select end select end if end function Midi implementation: should listen to Note On + Velo commands for notes 60-96. should listen to Note Off + Velo commands for notes 60-96 for the dampers. listens to following controllers: 20 ' motor 0 21 ' motor 1 22 ' both motors 23 ' set damping force 24 ' set damping mode 64 ' sustain - sets sustain mode 66 ' power ON 123 ' all notes off / resets controllers 127 ' pic reset Vibi should listen to the channel set with the dip switches (0-15). The normal channel-setting for Vibi is 10. The pincode command can be implemented as a binary midi controller >= 66 (on/off). The user should send this controller in order to enable Vibi.