home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / soundpla.pit / SoundPlay.c.pit / SIPlay.c < prev    next >
Encoding:
Text File  |  1985-09-25  |  12.6 KB  |  491 lines

  1. #Options Z
  2.  
  3. // mod 10 27 85 tsh - reduce 'pop' when sound goes on and off,
  4. //    remove AVBufB
  5. // mod 9 29 85 tsh - stand-alone high quality playback version
  6.  
  7. // Sound Output Routine
  8.  
  9. #include "MacCDefs.h"
  10. #include "MAZlib.h"
  11.  
  12. /* asm defines */
  13. #asm
  14. ; Bring in all the dirty constants
  15.     INCLUDE    SysEquX.D
  16.  
  17. ; Parameters
  18. cphase    EQU    25            ;sound buffer phase lag / cubic
  19. #endasm
  20.  
  21. // saved VBufA contents
  22. short saveVBufA;
  23.  
  24. // cubic spline interpolation tables
  25. short cs1[256], cs2[256], cs3[256], cs4[256], cs5[256], cs6[256];
  26.  
  27. // for OutputSound / CubicOutputSound
  28. unsigned char *runBuf;
  29. long runCnt;
  30.  
  31. // globals for OutputSound
  32. long outRegSave[12];    // coroutine register state save (D0-D7/A2-A3)
  33. char DoneOut;        // done boolean
  34. short vbl[7];        // my vbl entry
  35.  
  36.  
  37. // play the sound
  38. play_back_sound(buffer, count, sampling)
  39.  unsigned char *buffer;
  40.  long count;
  41.  short sampling;
  42.     {
  43.     int j;
  44.     unsigned int u;
  45.  
  46.     // setup for output
  47.     if (buffer == null || count == 0)
  48.     return; // can't play
  49.     runBuf = buffer;
  50.     runCnt = count;
  51.     // setup the translate tables
  52.     switch (sampling)
  53.       {
  54.       default:
  55.     break;
  56.       case 2:
  57.     for (u=0;u<256;u++)
  58.         {
  59.         cs1[u] = -u;
  60.         cs2[u] = u*9;
  61.         }
  62.     break;
  63.       case 3:
  64.     for (u=0;u<256;u++)
  65.         {
  66.         cs1[u] = -u*5*16/81;
  67.         cs2[u] = u*20*16/27;
  68.         cs3[u] = u*10*16/27;
  69.         cs4[u] = -u*4*16/81;
  70.         }
  71.     break;
  72.       case 4:
  73.     for (u=0;u<256;u++)
  74.         {
  75.         cs1[u] = -u;
  76.         cs2[u] = u*9;
  77.         cs3[u] = -u*7/8;
  78.         cs4[u] = u*105/8;
  79.         cs5[u] = u*35/8;
  80.         cs6[u] = -u*5/8;
  81.         }
  82.     break;
  83.     }
  84.     // turn sound on
  85.     sound_on();
  86.     // do the playing
  87.     CubicOutputSound(sampling);
  88.     // turn sound off
  89.     sound_off();
  90.     }
  91.  
  92.  
  93. // output some sound -- return zero if aborted, 1 if not
  94. int CubicOutputSound(sampling)
  95.   short sampling
  96.     {
  97. #asm
  98.     MOVE.L    runBuf(A5),A2        ;A2 buf
  99.     MOVE.L    runCnt(A5),D6        ;D6 count
  100.     LEA    SVA5,A0
  101.     MOVE.L    A5,(A0)            ;save A5 in code
  102.     SF    DoneOut(A5)        ;not done yet
  103. ; load the appropriate state addr into A3
  104.     LEA    out1,A3            ;times 1 sampling
  105.     CMPI.W    #1,D0
  106.     BEQ.S    @1
  107.     LEA    out2,A3            ;times 2 sampling
  108.     CMPI.W    #2,D0
  109.     BEQ.S    @1
  110.     LEA    out3,A3            ;times 3 sampling
  111.     CMPI.W    #3,D0
  112.     BEQ.S    @1
  113.     LEA    out4,A3            ;otherwise times 4 sampling
  114. @1    MOVEQ    #0,D5            ;clean D5
  115.     MOVE.B    (A2)+,D5        ;load first byte as point2
  116.     SUBQ.L    #1,D6            ;allow for byte loaded
  117.     MOVE.W    #$80,D4            ;init points before the start
  118. ; save state for interrupt world
  119.     LEA    outRegSave(A5),A0
  120.     MOVEM.L    D1-D7/A2-A3,(A0)
  121.  
  122. ; setup vbl to call _Vinstall
  123.     LEA    vbl(A5),A0        ;addr vbl record
  124.     MOVE.W    #vType,qType(A0)    ;set q type
  125.     LEA    cmyVR,A1
  126.     MOVE.L    A1,vblAddr(A0)        ;set routine addr
  127.     MOVE.W    #1,vblCount(A0)        ;set count = 1
  128.     CLR.W    vblPhase(A0)        ;set phase = 0
  129.     DC.W    $A033    ;_Vinstall
  130.  
  131. ; loop until done (action occurs at interrupt level)
  132. soloop:    TST.B    DoneOut(A5)        ; test for done
  133.     BEQ.S    soloop
  134.     BRA.S    csbye
  135.  
  136. ; remove our vertical retrace routine
  137. csout:    LEA    vbl(A5),A0        ;addr vbl record
  138.     DC.W    $A034    ;_Vremove
  139. ; init the sound output buffer to prevent a BUZZ if box is off
  140. csbye:    JSR    clear_sound_buffer
  141.     RTS                ; return
  142.  
  143. ; saved A5 in code segment
  144. SVA5:    DC.L    0
  145.  
  146. ; vertical retrace interrupt routine
  147. cmyVR:    MOVEM.L    A4-A5/D4-D7,-(SP)    ;save extra registers
  148.     MOVE.L    SVA5,A5            ;load our A5
  149. ; restore register state: D1-D7, A2-A3
  150.     LEA    outRegSave(A5),A0
  151.     MOVEM.L    (A0),D1-D7/A2-A3
  152. ; first call: A4 = soundBuf + cphase*2, D7 = sndBufWLen-cphase-1
  153.     MOVE.L    SoundBase,A4        ;init the sound buffer addr
  154.     ADD.L    #cphase+cphase,A4
  155.     MOVE.W    #sndBufWLen-cphase-1,D7
  156.     JSR    (A3)            ;resume
  157.     TST.L    D6            ;test for done
  158.     BLE.S    doneSound
  159. ; second call: A4 = soundBuf, D7 = cphase-1
  160.     MOVE.L    SoundBase,A4        ;init the sound buffer addr
  161.     MOVE.W    #cphase-1,D7
  162.     JSR    (A3)            ;resume
  163.     TST.L    D6            ;test for done
  164.     BLE.S    doneSound
  165. ; save state
  166.     LEA    outRegSave(A5),A0
  167.     MOVEM.L    D1-D7/A2-A3,(A0)
  168.     MOVEQ    #1,D1            ;reset count = 1 to continue
  169.  
  170. ; exit from vbl interrupt routine
  171. ; D1 = tick count for next call (0 = remove driver)
  172. cgoExit: LEA    vbl(A5),A0        ;addr vbl record
  173.     MOVE.W    D1,vblCount(A0)        ;set the tick count for next call
  174.     MOVEM.L    (SP)+,A4-A5/D4-D7    ; restore interrupt world reg's
  175.     RTS                ;return
  176.  
  177. ; Done: unlatch interrupt routine of ours -- we are done
  178. doneSound: MOVE.B #1,DoneOut(A5)     ; set done flag
  179.     MOVEQ    #0,D1            ; count = 0 to remove driver
  180.     BRA.S    cgoExit
  181.     
  182.  
  183. ; sampling rate = 1
  184.  
  185. ; D5 = point
  186. ; A2 = input buffer ptr
  187. ; D6 = input buffer count
  188. ; A4 = output buffer
  189. ; D7 = output buffer count
  190. ; A3 = &out1
  191. out1:    MOVE.B    D5,(A4)            ; store byte
  192.     ADDQ.L    #2,A4            ; increment by 2
  193.     MOVE.B    (A2)+,D5        ; load next data byte
  194.     SUBQ.L    #1,D6            ; count down and test for done
  195.     BEQ.S    tstrep1            ; yes, we're done
  196. gorep1:    DBF    D7,out1            ; loop
  197.     RTS
  198.  
  199.  
  200. ; test for repetitions
  201. tstrep1: RTS                ; yes, return with D6 = 0
  202.  
  203. ; test for repetitions
  204. tstrep2: RTS                ; yes, return with D6 = 0
  205.  
  206. ; sampling rate = 2
  207.  
  208. ; D3 = interpolated point
  209. ; D5 = point2
  210. ; D4 = point1
  211. ; A2 = input buffer ptr
  212. ; D6 = input buffer count
  213. ; A4 = output buffer
  214. ; D7 = output buffer count
  215. ; A3 = resume address
  216. out2:    MOVE.W    D4,D0            ; point1 is now point0
  217.     MOVE.W    D5,D4            ; point2 is now point1
  218.     MOVE.B    D5,(A4)            ; store real point1
  219.     ADDQ.L    #2,A4            ; increment by 2
  220.     MOVE.B    (A2)+,D5        ; load next data byte as point2
  221.     SUBQ.L    #1,D6            ; count down and test for done
  222.     BEQ.S    tstrep2            ; yes, we're done
  223. gorep2:    LEA    cs1(A5),A0        ; translate table 1
  224.     ADD.W    D0,D0            ; times 2
  225.     MOVE.W    0(A0,D0.W),D3        ; contribution from point0
  226.     MOVEQ    #0,D0
  227.     MOVE.B    (A2),D0            ;load next point = point3
  228.     ADD.W    D0,D0            ; times 2
  229.     ADD.W    0(A0,D0.W),D3        ; add in contribution for point3
  230.     LEA    cs2(A5),A0        ; translate table 2
  231.     MOVE.W    D4,D0            ; get point1
  232.     ADD.W    D0,D0            ; times 2
  233.     ADD.W    0(A0,D0.W),D3        ; contribution from point1
  234.     MOVE.W    D5,D0            ; get point2
  235.     ADD.W    D0,D0            ; times 2
  236.     ADD.W    0(A0,D0.W),D3        ; contribution from point2
  237.     ASR.W    #4,D3            ; form a byte
  238.     BLT.S    small2            ; test for too small
  239.     CMPI.W    #255,D3            ; test for too big
  240.     BGT.S    big2            ; yes
  241. go2:    DBF    D7,inter2        ; jump unless out buffer full
  242.     LEA    inter2,A3        ; resume at inter2
  243.     RTS
  244.  
  245. small2:    MOVEQ    #0,D3
  246.     BRA.S    go2
  247. big2:    MOVE.W    #255,D3
  248.     BRA.S    go2
  249.  
  250. inter2:    MOVE.B    D3,(A4)            ; store byte
  251.     ADDQ.L    #2,A4            ; increment by 2
  252.     DBF    D7,out2            ; jump unless out buffer full
  253.     LEA    out2,A3            ; resume at out2
  254.     RTS
  255.  
  256. ; test for repetitions
  257. tstrep3: RTS                ; yes, return with D6 = 0
  258.  
  259. ; sampling rate = 3
  260.  
  261. ; D2 = interpolated point 1
  262. ; D3 = interpolated point 2
  263. ; D5 = point2
  264. ; D4 = point1
  265. ; A2 = input buffer ptr
  266. ; D6 = input buffer count
  267. ; A4 = output buffer
  268. ; D7 = output buffer count
  269. ; A3 = resume address
  270. out3:    MOVE.W    D4,D0            ; point1 is now point0
  271.     MOVE.W    D5,D4            ; point2 is now point1
  272.     MOVE.B    D5,(A4)            ; store real point1
  273.     ADDQ.L    #2,A4            ; increment by 2
  274.     MOVE.B    (A2)+,D5        ; load next data byte as point2
  275.     SUBQ.L    #1,D6            ; count down and test for done
  276.     BEQ.S    tstrep3            ; yes, we're done
  277. gorep3:    LEA    cs1(A5),A0        ; translate table 1
  278.     LEA    cs4(A5),A1        ; translate table 4
  279.     ADD.W    D0,D0            ; point0 times 2
  280.     MOVE.W    0(A0,D0.W),D2        ; contribution from point0
  281.     MOVE.W    0(A1,D0.W),D3        ; contribution from point0
  282.     MOVEQ    #0,D0
  283.     MOVE.B    (A2),D0            ;load next point = point3
  284.     ADD.W    D0,D0            ; times 2
  285.     ADD.W    0(A1,D0.W),D2        ; add in contribution for point3
  286.     ADD.W    0(A0,D0.W),D3        ; add in contribution for point3
  287.     LEA    cs2(A5),A0        ; translate table 2
  288.     LEA    cs3(A5),A1        ; translate table 3
  289.     MOVE.W    D4,D0            ; get point1
  290.     ADD.W    D0,D0            ; times 2
  291.     ADD.W    0(A0,D0.W),D2        ; contribution from point1
  292.     ADD.W    0(A1,D0.W),D3        ; contribution from point1
  293.     MOVE.W    D5,D0            ; get point2
  294.     ADD.W    D0,D0            ; times 2
  295.     ADD.W    0(A1,D0.W),D2        ; contribution from point2
  296.     ADD.W    0(A0,D0.W),D3        ; contribution from point2
  297.     ASR.W    #4,D2            ; form a byte
  298.     BLT.S    small31            ; test for too small
  299.     CMPI.W    #255,D2            ; test for too big
  300.     BGT.S    big31            ; yes
  301. go31:    ASR.W    #4,D3            ; form a byte
  302.     BLT.S    small32            ; test for too small
  303.     CMPI.W    #255,D3            ; test for too big
  304.     BGT.S    big32            ; yes
  305. go32:    DBF    D7,inter31        ; jump unless out buffer full
  306.     LEA    inter31,A3        ; resume at inter31
  307.     RTS
  308.  
  309. small31: MOVEQ    #0,D2
  310.     BRA.S    go31
  311. big31:    MOVE.W    #255,D2
  312.     BRA.S    go31
  313.  
  314. small32: MOVEQ    #0,D3
  315.     BRA.S    go32
  316. big32:    MOVE.W    #255,D3
  317.     BRA.S    go32
  318.  
  319. inter31: MOVE.B    D2,(A4)            ; store byte
  320.     ADDQ.L    #2,A4            ; increment by 2
  321.     DBF    D7,inter32        ; jump unless out buffer full
  322.     LEA    inter32,A3        ; resume at inter32
  323.     RTS
  324.  
  325. inter32: MOVE.B    D3,(A4)            ; store byte
  326.     ADDQ.L    #2,A4            ; increment by 2
  327.     DBF    D7,out3            ; jump unless out buffer full
  328.     LEA    out3,A3            ; resume at out3
  329. exit3:    RTS
  330.  
  331. ; test for repetitions
  332. tstrep4: RTS                ; yes, return with D6 = 0
  333.  
  334.  
  335. ; sampling rate = 4
  336. ; D1 = interpolated point 1
  337. ; D2 = interpolated point 2
  338. ; D3 = interpolated point 3
  339. ; D5 = point2
  340. ; D4 = point1
  341. ; A2 = input buffer ptr
  342. ; D6 = input buffer count
  343. ; A4 = output buffer
  344. ; D7 = output buffer count
  345. ; A3 = resume address
  346. out4:    MOVE.W    D4,D0            ; point1 is now point0
  347.     MOVE.W    D5,D4            ; point2 is now point1
  348.     MOVE.B    D5,(A4)            ; store real point1
  349.     ADDQ.L    #2,A4            ; increment by 2
  350.     MOVE.B    (A2)+,D5        ; load next data byte as point2
  351.     SUBQ.L    #1,D6            ; count down and test for done
  352.     BEQ.S    tstrep4            ; yes, we're done
  353. gorep4:    LEA    cs3(A5),A0        ; translate table 3
  354.     LEA    cs6(A5),A1        ; translate table 6
  355.     ADD.W    D0,D0            ; times 2
  356.     MOVE.W    0(A0,D0.W),D1        ; contribution from point0
  357.     MOVE.W    0(A1,D0.W),D3        ; contribution from point0
  358.     LEA    cs1(A5),A0        ; translate table 1
  359.     MOVE.W    0(A0,D0.W),D2        ; contribution from point0
  360.     MOVEQ    #0,D0
  361.     MOVE.B    (A2),D0            ; load next point = point3
  362.     ADD.W    D0,D0            ; times 2
  363.     ADD.W    0(A0,D0.W),D2        ; contribution from point0
  364.     ADD.W    0(A1,D0.W),D1        ; add in contribution for point3
  365.     LEA    cs3(A5),A0        ; translate table 3
  366.     ADD.W    0(A0,D0.W),D3        ; add in contribution for point3
  367.     LEA    cs4(A5),A0        ; translate table 4
  368.     LEA    cs5(A5),A1        ; translate table 5
  369.     MOVE.W    D4,D0            ; get point1
  370.     ADD.W    D0,D0            ; times 2
  371.     ADD.W    0(A0,D0.W),D1        ; contribution from point1
  372.     ADD.W    0(A1,D0.W),D3        ; contribution from point1
  373.     LEA    cs2(A5),A0        ; translate table 2
  374.     ADD.W    0(A0,D0.W),D2        ; contribution from point0
  375.     MOVE.W    D5,D0            ; get point2
  376.     ADD.W    D0,D0            ; times 2
  377.     ADD.W    0(A0,D0.W),D2        ; contribution from point0
  378.     ADD.W    0(A1,D0.W),D1        ; contribution from point2
  379.     LEA    cs4(A5),A0        ; translate table 4
  380.     ADD.W    0(A0,D0.W),D3        ; contribution from point2
  381.     ASR.W    #4,D1            ; form a byte
  382.     BLT.S    small41            ; test for too small
  383.     CMPI.W    #255,D1            ; test for too big
  384.     BGT.S    big41            ; yes
  385. go41:    ASR.W    #4,D2            ; form a byte
  386.     BLT.S    small42            ; test for too small
  387.     CMPI.W    #255,D2            ; test for too big
  388.     BGT.S    big42            ; yes
  389. go42:    ASR.W    #4,D3            ; form a byte
  390.     BLT.S    small43            ; test for too small
  391.     CMPI.W    #255,D3            ; test for too big
  392.     BGT.S    big43            ; yes
  393. go43:    DBF    D7,inter41        ; jump unless out buffer full
  394.     LEA    inter41,A3        ; resume at inter41
  395.     RTS
  396.  
  397. small41: MOVEQ    #0,D1
  398.     BRA.S    go41
  399. big41:    MOVE.W    #255,D1
  400.     BRA.S    go41
  401.  
  402. small42: MOVEQ    #0,D2
  403.     BRA.S    go42
  404. big42:    MOVE.W    #255,D2
  405.     BRA.S    go42
  406.  
  407. small43: MOVEQ    #0,D3
  408.     BRA.S    go43
  409. big43:    MOVE.W    #255,D3
  410.     BRA.S    go43
  411.  
  412. inter41: MOVE.B    D1,(A4)            ; store byte
  413.     ADDQ.L    #2,A4            ; increment by 2
  414.     DBF    D7,inter42        ; jump unless out buffer full
  415.     LEA    inter42,A3        ; resume at inter42
  416.     RTS
  417.  
  418. inter42: MOVE.B    D2,(A4)            ; store byte
  419.     ADDQ.L    #2,A4            ; increment by 2
  420.     DBF    D7,inter43        ; jump unless out buffer full
  421.     LEA    inter43,A3        ; resume at inter43
  422.     RTS
  423.  
  424. inter43: MOVE.B    D3,(A4)            ; store byte
  425.     ADDQ.L    #2,A4            ; increment by 2
  426.     DBF    D7,out4            ; jump unless out buffer full
  427.     LEA    out4,A3            ; resume at out4
  428.     RTS
  429. #endasm
  430.     }
  431.  
  432. clear_sound_buffer()
  433.     {
  434. #asm
  435. ; init the sound output buffer to prevent a BUZZ if box is off
  436.     MOVE.L    SoundBase,A2        ;start of sound buffer
  437.     MOVE.W    #sndBufWLen-1,D2    ;size of sound buffer
  438. @1:    MOVE.B    #$80,(A2)
  439.     ADDQ.L    #2,A2            ; BUMP POINTER BY WORD.
  440.     DBF    D2,@1
  441. #endasm
  442. }
  443.  
  444. sound_on()
  445.     {
  446. #asm
  447. ; turn volume down to zero
  448.     MOVE.L    VIA,A0            ;get VIA device address
  449.     MOVE.B    vBufA(A0),D0        ;load current contents of vBufA
  450.     MOVE    D0,saveVBufA(A5)    ;save current contents
  451.     ANDI.B    #$F8,D0            ;set volume to zero
  452.     MOVE.B    D0,vBufA(A0)        ;set it
  453. ; init the sound output buffer to prevent a BUZZ if box is off
  454.     JSR    clear_sound_buffer
  455. ; turn on the sound
  456.     MOVE.L    VIA,A0            ;get VIA device address
  457.     BCLR    #VSndEnb,(A0)        ;clear the sound disable bit
  458. ; wait a moment for the dust to settle
  459.     LEA    3,A0            ;wait for three ticks
  460.     DC.W    $A03B    ;_Delay
  461. ; and reset volume to the max for the play
  462.     MOVE.L    VIA,A0            ;get VIA device address
  463.     MOVE    saveVBufA(A5),D0    ;get vBufa
  464.     ORI.B    #$07,D0            ;turn it all the way up
  465.     MOVE.B    D0,vBufA(A0)        ;and play it loud!
  466. #endasm
  467.     }
  468.  
  469. sound_off()
  470.     {
  471. #asm
  472. ; turn volume down to zero
  473.     MOVE.L    VIA,A0            ;get VIA device address
  474.     MOVE.B    vBufA(A0),D0        ;load current contents of vBufA
  475.     MOVE    D0,saveVBufA(A5)    ;save current contents
  476.     ANDI.B    #$F8,D0            ;set volume to zero
  477.     MOVE.B    D0,vBufA(A0)        ;set it
  478. ; turn off the sound
  479.     MOVE.L    VIA,A0            ;get VIA device address
  480.     BSET    #VSndEnb,(A0)        ;set the sound disable bit
  481. ; wait a moment for the dust to settle
  482.     LEA    3,A0            ;wait for three ticks
  483.     DC.W    $A03B    ;_Delay
  484. ; and reset volume to the original value
  485.     MOVE.L    VIA,A0            ;get VIA device address
  486.     MOVE    saveVBufA(A5),D0    ;get vBufa
  487.     MOVE.B    D0,vBufA(A0)        ;and play it loud!
  488. #endasm
  489.     }
  490.  
  491.