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