home *** CD-ROM | disk | FTP | other *** search
/ News-Disk 11 / News_Disk_Issue_11_19xx___BASIC.atr / midi.asm < prev    next >
Assembly Source File  |  2023-02-26  |  12KB  |  1 lines

  1. 10  .TITLE "Atari Midi Interface"¢20  .PAGE "C Terpin 1991"¢30 ; created: 06/89  revised:03/91¢40 ;¢50 ; Midi 'V:' Handler¢60 ;¢70 ;  Christopher Terpin¢80 ;  144 Eggert Road¢90 ;  Buffalo, N.Y. 14215¢0100 ;  terpin@autarch.acsu.buffalo.edu¢0110 ; or terpin@ubunix.acsu.buffalo.edu¢0120 ;¢0130 ; THIS SOURCE CODE IS IN THE¢0140 ; PUBLIC DOMAIN.¢0150 ; Please feel free to modify and¢0160 ; improve this code.  Please¢0170 ; let me know about any major¢0180 ; improvements or bugs you¢0190 ; have discovered. Enjoy!¢0200 ;¢0210 ;¢0220 ;¢0230 ; execution from AtariBASIC:¢0240 ;1. POKE 106,154:GR.0:DOS¢0250 ;2. load D:MIDI.OBJ¢0255 ;3. run BASIC cartridge¢0260 ;4. I=USR(39168,cmd,[start, end],speed) (see below)¢0270 ;------------------------------¢0280 ; to initialize V: handler:¢0290 ; I=USR(39168,ASC("I"))¢0300 ; CLOSE #1:OPEN #1,8,0,"V:"¢0310 ; use ?#1; or PUT #1 to send midi codes (i.e. ?#1;"ÉA@";)¢0320 ;------------------------------¢0330 ;¢0340 ; to reset normal serial i/o:¢0350 ; I=USR(39168,ASC("C"))¢0360 ;-------------------------------¢0370 ; to record:¢0380 ; I=USR(39168,ASC("R"),ADR(A$))¢0390 ; POKE 204,1  to start recording¢0400 ; POKE 204,0  to stop recording¢0410 ; L = PEEK(205)+256*PEEK(206)¢0420 ; is # of bytes recorded¢0430 ;------------------------------¢0440 ; to playback:¢0450 ; I=USR(39168,ASC("P"),ADR(A$),ADR(A$)+L)¢0460 ;------------------------------¢0470 ; to record B while playing A:¢0480 ; I=USR(39168,ASC("R"),ADR(B$))¢0490 ; POKE 204,1 :I=USR(39168,ASC("P"),ADR(A$),ADR(A$)+L):POKE 204,0¢0500 ;------------------------------¢0510 ;¢0520 ;  equates¢0530 ;¢0540 AUDCTL=$D208 ; pokey register¢0550 OUTBUF=$CB   ; character for output¢0560 SWITCH= $CC  ; 0==stop recording¢0570 BUFADD = $CD  ; pointer to buffer for recording¢0580 PLAYBUF = $CF ; pointer to buffer for playback¢0590 CH = $2FC   ; last key pressed¢0600 RECVDN = $39  ; receive flag¢0610 SERIN = $D20D ; serial i/o¢0620 SEROUT = SERIN¢0630 ;¢0640 VSERIN=$020A  ; interrupt vector for serial input¢0650 VSEROR = $20C ; interrupt vector for serial output ready¢0660 VSEROC = $20E ; interrupt vector for serial output complete¢0670 ;¢0680 AUDF3=$D204 ; pokey ch3 :baudlo¢0690 AUDF4=$D206 ; pokey ch4 :baudhi¢0700 XMTDON=$3A  ; transmit done flag¢0710 SSKCTL=$232 ; serial port control shadow¢0720 SKCTL=$D20F ; serial port control (W)¢0730 SKSTAT=$D20F ; serial port status (R)¢0740 SKRES= $D20A ; resets SKSTAT¢0750 POKMSK=$10  ; shadow of IRQEN¢0760 IRQEN=$D20E ; interrupt request¢0770 HATABS=$31A ; pointer to handler table¢0780 MIDIL= 22   ; midi baud rate¢0790 MIDIH = 0   ; values¢0800 RD = 4      ; CIO: open for read¢0810 WR = 8      ; CIO: open for write¢0820 CPUT = 11   ; CIO: PUT command¢0830 COPEN = 3   ; CIO: OPEN command¢0840 CCLOSE = 12 ; CIO: CLOSE command¢0850 ;¢0860 ; input-output control block (iocb)¢0870 ; structure:¢0880 ;¢0890 ICCOM = $342 ; command¢0900 ICAX1 = $34A ; aux1¢0910 ICAX2 = $34B ; aux2¢0920 ICBAH = $345 ; buffer address hi¢0930 ICBAL = $344 ; buffer address lo¢0940 ICBLL = $348 ; buffer length lo¢0950 ICBLH = $349 ; buffer length hi¢0960 CIOV = $E456 ; Central I/O vector¢0970 ;¢0980 ;¢0990 ; countdown timers¢1000 ;¢1010 CDTMA1 = $0226 ; timer1 vector¢1020 CDTMA2 = $0228 ; timer2 vector¢1030 CDTMF5 = $022E ; timer5 flag¢1040 SETVBV = $E45C ; set vblank¢1050 CONSOL = $D01F ; used for keyboard click¢1060 ;¢1070 MARK = 255 ; buffer timing mark¢1080 CTRLC = 146 ; control-c key¢1090 ;¢1100  *= $9900¢1110 ;¢1120 ;¢1130 START¢1140  PLA¢1150  PLA¢1160  PLA          get command¢1170 ;¢1180  CMP #'I¢1190  BNE OPT2¢1200  JMP SETHAND  ; setup CIO handler¢1210 ;¢1220 OPT2 CMP #'R¢1230  BNE OPT3¢1240  JMP RECORD   ; midi record¢1250 ;¢1260 OPT3 CMP #'P¢1270  BNE OPT4¢1280  JMP PLAYBACK ; midi playback¢1290 ;¢1300 OPT4 CMP #'C¢1310  BNE NOOPT¢1320  JMP RESET  ; reset ser port¢1330 NOOPT SEC     ; error¢1340  RTS¢1350 ;-----------------------------¢1360 ;  MIDI "V:" handler¢1370 ;¢1380 SETHAND¢1390  LDY #0   ; add our handler¢1400 LPHND LDA HATABS,Y¢1410  CMP #0     ;free entry?¢1420  BEQ FOUND  ;yes..¢1430  INY        ;no, skip 3 bytes¢1440  INY¢1450  INY¢1460  CPY #34    ; end of table?¢1470  BNE LPHND  ; no...keep looking¢1480  SEC        ; yes..full table!¢1490  RTS        ; quit with error¢1500 ;¢1510 FOUND LDA #'V  ; "V:" handler¢1520  STA HATABS,Y  ; save in table¢1530  INY¢1540  LDA #VTABL&255 ; store address¢1550  STA HATABS,Y   ; of vector¢1560  INY            ; table in¢1570  LDA #VTABL/255 ; handler table¢1580  STA HATABS,Y¢1590 ;¢1600 ; save interrupt vectors¢1610 ;¢1620  LDY #5¢1630 SAVESER LDA VSERIN,Y¢1640  STA SAVEVEC,Y¢1650  DEY¢1660  BPL SAVESER¢1670 ;¢1680  RTS¢1690 ;¢1700 SAVEVEC .BYTE 0,0,0,0,0,0¢1710 ;¢1720 ;--------------------------¢1730 ; begin MIDI Handler¢1740 ;¢1750 ; vector table:¢1760 VTABL .WORD VOPEN-1¢1770       .WORD VCLOSE-1¢1780       .WORD NOFUNC-1 (get)¢1790       .WORD VPUT-1¢1800       .WORD NOFUNC-1 (status)¢1810       .WORD NOFUNC-1 (special)¢1820  JMP VINIT ; initialization¢1830 ;-----------------------------¢1840 VCLOSE¢1850 VOPEN LDA #0¢1860  STA MODE¢1870 VINIT¢1880 RETURN1 LDY #1 ; return success¢1890 NOFUNC RTS¢1900 ;-----------------------------¢1910 ;¢1920 ;¢1930 ;¢1940 ;----------------------------¢1950 ; PUT function¢1960 ;¢1970 VPUT STA OUTBUF ; save accumulator¢1980  LDA MODE ; write mode ?¢1990  CMP #WR¢2000  BEQ WRMODE ; yes...¢2010  LDA #WR    ; no..set flag¢2020  STA MODE   ; and¢2030  JSR SETIO ; set up for serial output¢2040 ;¢2050 WRMODE LDA OUTBUF ; retrieve byte¢2060  STA SEROUT     ; send it out &¢2070 WAIT LDA XMTDON  wait for irqs¢2080  BEQ WAIT        to do their¢2090  LDA #0          stuff...¢2100  STA XMTDON      reset flag¢2110  LDY #1          exit¢2120  RTS             with success¢2130 ;----------------------------¢2140 ;¢2150 ;¢2160 ;----------------------------¢2180 ; enable serial I/O¢2190 SETIO LDA #$73 ; ALLOW I & O concurrently!¢2200 CONT STA SSKCTL ; set the serial port control,¢2210  STA SKCTL        and shadow¢2220  LDA POKMSK    ; get irqen mask¢2230  AND #$CF      ; no keyboard interrupts¢2240  CLC¢2250  ORA #$30     ;allow both types¢2260  STA POKMSK    of serial interrupts¢2270  STA IRQEN¢2280  LDA #MIDIL¢2290  STA AUDF3    ;set 31.5k baud¢2300  LDA #MIDIH    rate for i/o¢2310  STA AUDF4     in POKEY¢2320  LDA #$28     ; clock ch3 with 1.79MHz¢2330  STA AUDCTL   ; & link ch3 to ch4¢2340 ;¢2350  LDA #0      ; reset transmit¢2360  STA XMTDON    done flag¢2370  RTS¢2380 ;¢2390 ;¢2400 MODE .BYTE 0  ; read/write mode flag¢2410 ;¢2420 ;------------------------------¢2430 ; reset serial port¢2440 RESET¢2450  LDA #$03¢2460  STA SSKCTL  ; disable¢2470  STA SKCTL     serial port¢2480  LDA POKMSK    interrupts¢2490  AND #$C0¢2500  STA POKMSK¢2510  STA IRQEN¢2520  LDA #0¢2530  STA SWITCH¢2540  STA XMTDON¢2550  LDY #5     ; restore vectors¢2560 RESTV LDA SAVEVEC,Y¢2570  STA VSERIN,Y¢2580  DEY¢2590  BPL RESTV¢2600  RTS¢2610 ;----------------------------¢2620 ;¢2630 ;¢2640 ; interrupt service routine¢2650 ; for serial input ready¢2660 ;¢2670 ;----------------------------¢2680 ISRSIR TYA¢2690  PHA          save y register¢2700  LDA SKSTAT   reset latches¢2710  STA SKRES    in case of overrun¢2720  LDA SWITCH   check software switch¢2730  BEQ LEAVIT   switch on?¢2740  LDY #0      ; yes,save interval¢2750  LDA INTERVAL¢2755  CMP #2      ; 2 jiffies?¢2760  BCC TOOSHORT ;time is too short¢2770  LDY #1¢2780  STA (BUFADD),Y¢2790  LDA #MARK¢2800  LDY #0¢2810  STA (BUFADD),Y¢2820  STY INTERVAL  ; reset counter¢2830  LDY #2¢2840 TOOSHORT LDA SERIN ;load serial input¢2850  STA (BUFADD),Y  store input¢2860  INY             in buffer &¢2870  TYA¢2880  CLC¢2890  ADC BUFADD¢2900  STA BUFADD      increment the¢2910  LDA BUFADD+1    buffer pointer¢2920  ADC #0¢2930  STA BUFADD+1¢2940 ;¢2950 LEAVIT LDA #$FF  set recvdn flag¢2960  STA RECVDN¢2970  PLA    restore the¢2980  TAY     y register¢2990  PLA    and the accumulator¢3000  RTI    & return from interrupt.¢3010 ;-----------------------------¢3020 ;¢3030 ;¢3040 ;-----------------------------¢3050 ; TIMER ROUTINE¢3060 ;¢3070 ; inserts timing marks¢3080 ; to count time interval¢3090 ;¢3100 ;----------------------------¢3110 TIMER¢3120  LDA SWITCH    ;are we recording?¢3130  BEQ SETTIM    ;NO...reset this vbi¢3150  INC INTERVAL  ; count # of marks¢3160  CMP #255      ; max count?¢3170  BNE SETTIM    ; no, continue¢3190  LDY #0        ; write to buffer¢3200  LDA #MARK     ; timing mark¢3210  STA (BUFADD),Y¢3220  LDY #1¢3230  LDA #255¢3240  STA (BUFADD),Y¢3260  LDA #0         ; reset counter¢3270  STA INTERVAL¢3280 ;¢3290  CLC            ;increment the¢3300  LDA BUFADD     ; buffer pointer¢3310  ADC #2         ; by two¢3320  STA BUFADD¢3330  LDA BUFADD+1¢3340  ADC #0¢3350  STA BUFADD+1¢3360 ;¢3370 ;¢3380 SETTIM¢3390  LDA #TIMER&255 ; reset the¢3400  STA CDTMA2       timer vector¢3410  LDA #TIMER/256¢3420  STA CDTMA2+1¢3490  LDY #1   ; speed lo (1 jiffy)¢3500  LDX #0   ; speed hi¢3510  LDA #2         ; use timer 2¢3520  JSR SETVBV     ; start it!¢3530  RTS            ; done..¢3540 ;------------------------------¢3550 ;¢3560 ;¢3570 ;¢3580 ;-----------------------------¢3590 ; RECORD routine¢3600 ;¢3610 ;¢3620 RECORD¢3630  PLA¢3640  STA BUFADD+1  ;address of¢3650  PLA            recording buffer¢3660  STA BUFADD¢3710  LDA #0¢3720  STA INTERVAL    ; reset counter¢3730  STA RECVDN   ; reset input flag¢3740  JSR SETTIM     ; start timer¢3750  LDA #ISRSIR&255¢3760  STA VSERIN      ;setup serial¢3770  LDA #ISRSIR/256  input interrupts¢3780  STA VSERIN+1¢3790  JSR SETIO    ;enable serial input¢3800  RTS         ; done!¢3820 INTERVAL .BYTE 0¢3830 ;-----------------------------¢3840 ;¢3850 ;¢3860 ; PLAYBACK routine¢3870 ;¢3880 PLAYBACK¢3890  PLA¢3900  STA PLAYBUF+1   ; playback buffer¢3910  PLA¢3920  STA PLAYBUF¢3930  PLA¢3940  STA ENDBUF+1  ; pointer to end of buffer¢3950  PLA¢3970  STA ENDBUF¢4020 ;¢4030  LDA #0¢4040  STA DONE      ; reset flag¢4050 ;¢4060  LDA #ISEROR&255 ; set up¢4070  STA VSEROR        serial output¢4080  LDA #ISEROR/256   ready¢4090  STA VSEROR+1      interrupt¢4100 ;¢4110  LDA #ISRTD&255  ; set up¢4120  STA VSEROC        serial output¢4130  LDA #ISRTD/256    complete¢4140  STA VSEROC+1      interrupt¢4150  JSR SETIO¢4160 ;¢4170 ;¢4180 ;¢4190 ;¢4200 ;------------------------------¢4210 ; output buffer¢4220 PLAYLOOP¢4230  LDY #0¢4240  LDA (PLAYBUF),Y  ; get note¢4250  CMP #MARK   ; is it a mark?¢4260  BNE ISMIDI  ; no...¢4270  LDY #1      ; yes...wait¢4280  LDA (PLAYBUF),Y¢4290  TAY         ; Y=jiffys to wait¢4300  LDA #$10¢4310  STA CDTMF5¢4320  LDX #0¢4330  LDA #5¢4340  JSR SETVBV  ; start timer 5¢4350 WAITLOOP LDA CDTMF5 ; dumdedum..¢4360  BNE WAITLOOP¢4370 ;¢4380  LDA #2¢4390  JSR INCPLAY  ; inc buffer by 2¢4400  LDA CH       ; check for break¢4410  CMP #CTRLC¢4420  BNE PLAYLOOP¢4430  RTS¢4440 ;¢4450 ISMIDI JSR VPUT    ; otherwise send it¢4460  LDA #1¢4470  JSR INCPLAY  ; incr. by 1¢4480  LDA DONE     ; finished?¢4490  BEQ PLAYLOOP ; no....¢4500  RTS          ; yes..quit¢4510 ;¢4520 ;¢4530 ;¢4540 INCPLAY¢4550  CLC           ; increment¢4560  ADC PLAYBUF     playbuf by A¢4570  STA PLAYBUF¢4580  LDA PLAYBUF+1¢4590  ADC #0¢4600  STA PLAYBUF+1¢4610 ;¢4620  CMP ENDBUF+1   ; end of song?¢4630  BCC NOTEND¢4640  LDA PLAYBUF¢4650  CMP ENDBUF¢4660  BCC NOTEND     ; no..¢4670  LDA #1         ; yes...¢4680  STA DONE         set done flag¢4690 NOTEND RTS¢4700 ;¢4710 ;¢4720 ENDBUF .BYTE 0,0¢4730 DONE .BYTE 0,0¢4740 ;¢4750 ;¢4760 ;¢4770 ;¢4780 ;-----------------------------¢4790 ; serial output ready¢4800 ; interrupt service routine¢4810 ;¢4820 ISEROR¢4830 ;¢4840  LDA POKMSK ; enable¢4850  ORA #$08     the transmit done¢4860  STA POKMSK   interrupt¢4870  STA IRQEN¢4880  PLA        ; pop accumulator¢4890  RTI¢4900 ;¢4910 ;---------------------------¢4920 ; Transmit Done Interrupt¢4930 ;¢4940 ISRTD¢4950  LDA #$FF      ;set transmit¢4960  STA XMTDON     done flag¢4970  LDA POKMSK¢4980  AND #$F7      ;disable tdi¢4990  STA POKMSK¢5000  STA IRQEN¢5010  PLA           ;restore accum.¢5020  RTI¢5030 ;----------------------------¢