home *** CD-ROM | disk | FTP | other *** search
- #Options Z
-
- // mod 10 27 85 tsh - reduce 'pop' when sound goes on and off,
- // remove AVBufB
- // mod 9 29 85 tsh - stand-alone high quality playback version
-
- // Sound Output Routine
-
- #include "MacCDefs.h"
- #include "MAZlib.h"
-
- /* asm defines */
- #asm
- ; Bring in all the dirty constants
- INCLUDE SysEquX.D
-
- ; Parameters
- cphase EQU 25 ;sound buffer phase lag / cubic
- #endasm
-
- // saved VBufA contents
- short saveVBufA;
-
- // cubic spline interpolation tables
- short cs1[256], cs2[256], cs3[256], cs4[256], cs5[256], cs6[256];
-
- // for OutputSound / CubicOutputSound
- unsigned char *runBuf;
- long runCnt;
-
- // globals for OutputSound
- long outRegSave[12]; // coroutine register state save (D0-D7/A2-A3)
- char DoneOut; // done boolean
- short vbl[7]; // my vbl entry
-
-
- // play the sound
- play_back_sound(buffer, count, sampling)
- unsigned char *buffer;
- long count;
- short sampling;
- {
- int j;
- unsigned int u;
-
- // setup for output
- if (buffer == null || count == 0)
- return; // can't play
- runBuf = buffer;
- runCnt = count;
- // setup the translate tables
- switch (sampling)
- {
- default:
- break;
- case 2:
- for (u=0;u<256;u++)
- {
- cs1[u] = -u;
- cs2[u] = u*9;
- }
- break;
- case 3:
- for (u=0;u<256;u++)
- {
- cs1[u] = -u*5*16/81;
- cs2[u] = u*20*16/27;
- cs3[u] = u*10*16/27;
- cs4[u] = -u*4*16/81;
- }
- break;
- case 4:
- for (u=0;u<256;u++)
- {
- cs1[u] = -u;
- cs2[u] = u*9;
- cs3[u] = -u*7/8;
- cs4[u] = u*105/8;
- cs5[u] = u*35/8;
- cs6[u] = -u*5/8;
- }
- break;
- }
- // turn sound on
- sound_on();
- // do the playing
- CubicOutputSound(sampling);
- // turn sound off
- sound_off();
- }
-
-
- // output some sound -- return zero if aborted, 1 if not
- int CubicOutputSound(sampling)
- short sampling
- {
- #asm
- MOVE.L runBuf(A5),A2 ;A2 buf
- MOVE.L runCnt(A5),D6 ;D6 count
- LEA SVA5,A0
- MOVE.L A5,(A0) ;save A5 in code
- SF DoneOut(A5) ;not done yet
- ; load the appropriate state addr into A3
- LEA out1,A3 ;times 1 sampling
- CMPI.W #1,D0
- BEQ.S @1
- LEA out2,A3 ;times 2 sampling
- CMPI.W #2,D0
- BEQ.S @1
- LEA out3,A3 ;times 3 sampling
- CMPI.W #3,D0
- BEQ.S @1
- LEA out4,A3 ;otherwise times 4 sampling
- @1 MOVEQ #0,D5 ;clean D5
- MOVE.B (A2)+,D5 ;load first byte as point2
- SUBQ.L #1,D6 ;allow for byte loaded
- MOVE.W #$80,D4 ;init points before the start
- ; save state for interrupt world
- LEA outRegSave(A5),A0
- MOVEM.L D1-D7/A2-A3,(A0)
-
- ; setup vbl to call _Vinstall
- LEA vbl(A5),A0 ;addr vbl record
- MOVE.W #vType,qType(A0) ;set q type
- LEA cmyVR,A1
- MOVE.L A1,vblAddr(A0) ;set routine addr
- MOVE.W #1,vblCount(A0) ;set count = 1
- CLR.W vblPhase(A0) ;set phase = 0
- DC.W $A033 ;_Vinstall
-
- ; loop until done (action occurs at interrupt level)
- soloop: TST.B DoneOut(A5) ; test for done
- BEQ.S soloop
- BRA.S csbye
-
- ; remove our vertical retrace routine
- csout: LEA vbl(A5),A0 ;addr vbl record
- DC.W $A034 ;_Vremove
- ; init the sound output buffer to prevent a BUZZ if box is off
- csbye: JSR clear_sound_buffer
- RTS ; return
-
- ; saved A5 in code segment
- SVA5: DC.L 0
-
- ; vertical retrace interrupt routine
- cmyVR: MOVEM.L A4-A5/D4-D7,-(SP) ;save extra registers
- MOVE.L SVA5,A5 ;load our A5
- ; restore register state: D1-D7, A2-A3
- LEA outRegSave(A5),A0
- MOVEM.L (A0),D1-D7/A2-A3
- ; first call: A4 = soundBuf + cphase*2, D7 = sndBufWLen-cphase-1
- MOVE.L SoundBase,A4 ;init the sound buffer addr
- ADD.L #cphase+cphase,A4
- MOVE.W #sndBufWLen-cphase-1,D7
- JSR (A3) ;resume
- TST.L D6 ;test for done
- BLE.S doneSound
- ; second call: A4 = soundBuf, D7 = cphase-1
- MOVE.L SoundBase,A4 ;init the sound buffer addr
- MOVE.W #cphase-1,D7
- JSR (A3) ;resume
- TST.L D6 ;test for done
- BLE.S doneSound
- ; save state
- LEA outRegSave(A5),A0
- MOVEM.L D1-D7/A2-A3,(A0)
- MOVEQ #1,D1 ;reset count = 1 to continue
-
- ; exit from vbl interrupt routine
- ; D1 = tick count for next call (0 = remove driver)
- cgoExit: LEA vbl(A5),A0 ;addr vbl record
- MOVE.W D1,vblCount(A0) ;set the tick count for next call
- MOVEM.L (SP)+,A4-A5/D4-D7 ; restore interrupt world reg's
- RTS ;return
-
- ; Done: unlatch interrupt routine of ours -- we are done
- doneSound: MOVE.B #1,DoneOut(A5) ; set done flag
- MOVEQ #0,D1 ; count = 0 to remove driver
- BRA.S cgoExit
-
-
- ; sampling rate = 1
-
- ; D5 = point
- ; A2 = input buffer ptr
- ; D6 = input buffer count
- ; A4 = output buffer
- ; D7 = output buffer count
- ; A3 = &out1
- out1: MOVE.B D5,(A4) ; store byte
- ADDQ.L #2,A4 ; increment by 2
- MOVE.B (A2)+,D5 ; load next data byte
- SUBQ.L #1,D6 ; count down and test for done
- BEQ.S tstrep1 ; yes, we're done
- gorep1: DBF D7,out1 ; loop
- RTS
-
-
- ; test for repetitions
- tstrep1: RTS ; yes, return with D6 = 0
-
- ; test for repetitions
- tstrep2: RTS ; yes, return with D6 = 0
-
- ; sampling rate = 2
-
- ; D3 = interpolated point
- ; D5 = point2
- ; D4 = point1
- ; A2 = input buffer ptr
- ; D6 = input buffer count
- ; A4 = output buffer
- ; D7 = output buffer count
- ; A3 = resume address
- out2: MOVE.W D4,D0 ; point1 is now point0
- MOVE.W D5,D4 ; point2 is now point1
- MOVE.B D5,(A4) ; store real point1
- ADDQ.L #2,A4 ; increment by 2
- MOVE.B (A2)+,D5 ; load next data byte as point2
- SUBQ.L #1,D6 ; count down and test for done
- BEQ.S tstrep2 ; yes, we're done
- gorep2: LEA cs1(A5),A0 ; translate table 1
- ADD.W D0,D0 ; times 2
- MOVE.W 0(A0,D0.W),D3 ; contribution from point0
- MOVEQ #0,D0
- MOVE.B (A2),D0 ;load next point = point3
- ADD.W D0,D0 ; times 2
- ADD.W 0(A0,D0.W),D3 ; add in contribution for point3
- LEA cs2(A5),A0 ; translate table 2
- MOVE.W D4,D0 ; get point1
- ADD.W D0,D0 ; times 2
- ADD.W 0(A0,D0.W),D3 ; contribution from point1
- MOVE.W D5,D0 ; get point2
- ADD.W D0,D0 ; times 2
- ADD.W 0(A0,D0.W),D3 ; contribution from point2
- ASR.W #4,D3 ; form a byte
- BLT.S small2 ; test for too small
- CMPI.W #255,D3 ; test for too big
- BGT.S big2 ; yes
- go2: DBF D7,inter2 ; jump unless out buffer full
- LEA inter2,A3 ; resume at inter2
- RTS
-
- small2: MOVEQ #0,D3
- BRA.S go2
- big2: MOVE.W #255,D3
- BRA.S go2
-
- inter2: MOVE.B D3,(A4) ; store byte
- ADDQ.L #2,A4 ; increment by 2
- DBF D7,out2 ; jump unless out buffer full
- LEA out2,A3 ; resume at out2
- RTS
-
- ; test for repetitions
- tstrep3: RTS ; yes, return with D6 = 0
-
- ; sampling rate = 3
-
- ; D2 = interpolated point 1
- ; D3 = interpolated point 2
- ; D5 = point2
- ; D4 = point1
- ; A2 = input buffer ptr
- ; D6 = input buffer count
- ; A4 = output buffer
- ; D7 = output buffer count
- ; A3 = resume address
- out3: MOVE.W D4,D0 ; point1 is now point0
- MOVE.W D5,D4 ; point2 is now point1
- MOVE.B D5,(A4) ; store real point1
- ADDQ.L #2,A4 ; increment by 2
- MOVE.B (A2)+,D5 ; load next data byte as point2
- SUBQ.L #1,D6 ; count down and test for done
- BEQ.S tstrep3 ; yes, we're done
- gorep3: LEA cs1(A5),A0 ; translate table 1
- LEA cs4(A5),A1 ; translate table 4
- ADD.W D0,D0 ; point0 times 2
- MOVE.W 0(A0,D0.W),D2 ; contribution from point0
- MOVE.W 0(A1,D0.W),D3 ; contribution from point0
- MOVEQ #0,D0
- MOVE.B (A2),D0 ;load next point = point3
- ADD.W D0,D0 ; times 2
- ADD.W 0(A1,D0.W),D2 ; add in contribution for point3
- ADD.W 0(A0,D0.W),D3 ; add in contribution for point3
- LEA cs2(A5),A0 ; translate table 2
- LEA cs3(A5),A1 ; translate table 3
- MOVE.W D4,D0 ; get point1
- ADD.W D0,D0 ; times 2
- ADD.W 0(A0,D0.W),D2 ; contribution from point1
- ADD.W 0(A1,D0.W),D3 ; contribution from point1
- MOVE.W D5,D0 ; get point2
- ADD.W D0,D0 ; times 2
- ADD.W 0(A1,D0.W),D2 ; contribution from point2
- ADD.W 0(A0,D0.W),D3 ; contribution from point2
- ASR.W #4,D2 ; form a byte
- BLT.S small31 ; test for too small
- CMPI.W #255,D2 ; test for too big
- BGT.S big31 ; yes
- go31: ASR.W #4,D3 ; form a byte
- BLT.S small32 ; test for too small
- CMPI.W #255,D3 ; test for too big
- BGT.S big32 ; yes
- go32: DBF D7,inter31 ; jump unless out buffer full
- LEA inter31,A3 ; resume at inter31
- RTS
-
- small31: MOVEQ #0,D2
- BRA.S go31
- big31: MOVE.W #255,D2
- BRA.S go31
-
- small32: MOVEQ #0,D3
- BRA.S go32
- big32: MOVE.W #255,D3
- BRA.S go32
-
- inter31: MOVE.B D2,(A4) ; store byte
- ADDQ.L #2,A4 ; increment by 2
- DBF D7,inter32 ; jump unless out buffer full
- LEA inter32,A3 ; resume at inter32
- RTS
-
- inter32: MOVE.B D3,(A4) ; store byte
- ADDQ.L #2,A4 ; increment by 2
- DBF D7,out3 ; jump unless out buffer full
- LEA out3,A3 ; resume at out3
- exit3: RTS
-
- ; test for repetitions
- tstrep4: RTS ; yes, return with D6 = 0
-
-
- ; sampling rate = 4
- ; D1 = interpolated point 1
- ; D2 = interpolated point 2
- ; D3 = interpolated point 3
- ; D5 = point2
- ; D4 = point1
- ; A2 = input buffer ptr
- ; D6 = input buffer count
- ; A4 = output buffer
- ; D7 = output buffer count
- ; A3 = resume address
- out4: MOVE.W D4,D0 ; point1 is now point0
- MOVE.W D5,D4 ; point2 is now point1
- MOVE.B D5,(A4) ; store real point1
- ADDQ.L #2,A4 ; increment by 2
- MOVE.B (A2)+,D5 ; load next data byte as point2
- SUBQ.L #1,D6 ; count down and test for done
- BEQ.S tstrep4 ; yes, we're done
- gorep4: LEA cs3(A5),A0 ; translate table 3
- LEA cs6(A5),A1 ; translate table 6
- ADD.W D0,D0 ; times 2
- MOVE.W 0(A0,D0.W),D1 ; contribution from point0
- MOVE.W 0(A1,D0.W),D3 ; contribution from point0
- LEA cs1(A5),A0 ; translate table 1
- MOVE.W 0(A0,D0.W),D2 ; contribution from point0
- MOVEQ #0,D0
- MOVE.B (A2),D0 ; load next point = point3
- ADD.W D0,D0 ; times 2
- ADD.W 0(A0,D0.W),D2 ; contribution from point0
- ADD.W 0(A1,D0.W),D1 ; add in contribution for point3
- LEA cs3(A5),A0 ; translate table 3
- ADD.W 0(A0,D0.W),D3 ; add in contribution for point3
- LEA cs4(A5),A0 ; translate table 4
- LEA cs5(A5),A1 ; translate table 5
- MOVE.W D4,D0 ; get point1
- ADD.W D0,D0 ; times 2
- ADD.W 0(A0,D0.W),D1 ; contribution from point1
- ADD.W 0(A1,D0.W),D3 ; contribution from point1
- LEA cs2(A5),A0 ; translate table 2
- ADD.W 0(A0,D0.W),D2 ; contribution from point0
- MOVE.W D5,D0 ; get point2
- ADD.W D0,D0 ; times 2
- ADD.W 0(A0,D0.W),D2 ; contribution from point0
- ADD.W 0(A1,D0.W),D1 ; contribution from point2
- LEA cs4(A5),A0 ; translate table 4
- ADD.W 0(A0,D0.W),D3 ; contribution from point2
- ASR.W #4,D1 ; form a byte
- BLT.S small41 ; test for too small
- CMPI.W #255,D1 ; test for too big
- BGT.S big41 ; yes
- go41: ASR.W #4,D2 ; form a byte
- BLT.S small42 ; test for too small
- CMPI.W #255,D2 ; test for too big
- BGT.S big42 ; yes
- go42: ASR.W #4,D3 ; form a byte
- BLT.S small43 ; test for too small
- CMPI.W #255,D3 ; test for too big
- BGT.S big43 ; yes
- go43: DBF D7,inter41 ; jump unless out buffer full
- LEA inter41,A3 ; resume at inter41
- RTS
-
- small41: MOVEQ #0,D1
- BRA.S go41
- big41: MOVE.W #255,D1
- BRA.S go41
-
- small42: MOVEQ #0,D2
- BRA.S go42
- big42: MOVE.W #255,D2
- BRA.S go42
-
- small43: MOVEQ #0,D3
- BRA.S go43
- big43: MOVE.W #255,D3
- BRA.S go43
-
- inter41: MOVE.B D1,(A4) ; store byte
- ADDQ.L #2,A4 ; increment by 2
- DBF D7,inter42 ; jump unless out buffer full
- LEA inter42,A3 ; resume at inter42
- RTS
-
- inter42: MOVE.B D2,(A4) ; store byte
- ADDQ.L #2,A4 ; increment by 2
- DBF D7,inter43 ; jump unless out buffer full
- LEA inter43,A3 ; resume at inter43
- RTS
-
- inter43: MOVE.B D3,(A4) ; store byte
- ADDQ.L #2,A4 ; increment by 2
- DBF D7,out4 ; jump unless out buffer full
- LEA out4,A3 ; resume at out4
- RTS
- #endasm
- }
-
- clear_sound_buffer()
- {
- #asm
- ; init the sound output buffer to prevent a BUZZ if box is off
- MOVE.L SoundBase,A2 ;start of sound buffer
- MOVE.W #sndBufWLen-1,D2 ;size of sound buffer
- @1: MOVE.B #$80,(A2)
- ADDQ.L #2,A2 ; BUMP POINTER BY WORD.
- DBF D2,@1
- #endasm
- }
-
- sound_on()
- {
- #asm
- ; turn volume down to zero
- MOVE.L VIA,A0 ;get VIA device address
- MOVE.B vBufA(A0),D0 ;load current contents of vBufA
- MOVE D0,saveVBufA(A5) ;save current contents
- ANDI.B #$F8,D0 ;set volume to zero
- MOVE.B D0,vBufA(A0) ;set it
- ; init the sound output buffer to prevent a BUZZ if box is off
- JSR clear_sound_buffer
- ; turn on the sound
- MOVE.L VIA,A0 ;get VIA device address
- BCLR #VSndEnb,(A0) ;clear the sound disable bit
- ; wait a moment for the dust to settle
- LEA 3,A0 ;wait for three ticks
- DC.W $A03B ;_Delay
- ; and reset volume to the max for the play
- MOVE.L VIA,A0 ;get VIA device address
- MOVE saveVBufA(A5),D0 ;get vBufa
- ORI.B #$07,D0 ;turn it all the way up
- MOVE.B D0,vBufA(A0) ;and play it loud!
- #endasm
- }
-
- sound_off()
- {
- #asm
- ; turn volume down to zero
- MOVE.L VIA,A0 ;get VIA device address
- MOVE.B vBufA(A0),D0 ;load current contents of vBufA
- MOVE D0,saveVBufA(A5) ;save current contents
- ANDI.B #$F8,D0 ;set volume to zero
- MOVE.B D0,vBufA(A0) ;set it
- ; turn off the sound
- MOVE.L VIA,A0 ;get VIA device address
- BSET #VSndEnb,(A0) ;set the sound disable bit
- ; wait a moment for the dust to settle
- LEA 3,A0 ;wait for three ticks
- DC.W $A03B ;_Delay
- ; and reset volume to the original value
- MOVE.L VIA,A0 ;get VIA device address
- MOVE saveVBufA(A5),D0 ;get vBufa
- MOVE.B D0,vBufA(A0) ;and play it loud!
- #endasm
- }
-
-