home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / midas / dsm.asm < prev    next >
Assembly Source File  |  1994-08-06  |  92KB  |  3,413 lines

  1. ;*    DSM.ASM
  2. ;*
  3. ;* Digital Sound Mixer, v1.11
  4. ;*
  5. ;* Copyright 1994 Petteri Kangaslampi and Jarno Paananen
  6. ;*
  7. ;* This file is part of the MIDAS Sound System, and may only be
  8. ;* used, modified and distributed under the terms of the MIDAS
  9. ;* Sound System license, LICENSE.TXT. By continuing to use,
  10. ;* modify or distribute this file you indicate that you have
  11. ;* read the license and understand and accept it fully.
  12. ;*
  13.  
  14.  
  15. IDEAL
  16. P386
  17. JUMPS
  18.  
  19. INCLUDE "lang.inc"
  20. INCLUDE "errors.inc"
  21. INCLUDE "mglobals.inc"
  22. INCLUDE "dsm.inc"
  23. INCLUDE "dma.inc"
  24. INCLUDE "mmem.inc"
  25. INCLUDE "ems.inc"
  26. INCLUDE "sdevice.inc"
  27.  
  28.  
  29.  
  30. TBUF_MAX = 2048             ; maximum size of temporary buffer
  31.  
  32.  
  33.  
  34. DATASEG
  35.  
  36. dsmMixRate    DW    ?        ; mixing rate in Hz
  37. dsmMode     DW    ?        ; output mode (see enum sdMode)
  38. dsmVolTableMem    DD    ?        ; pointer to volume table returned
  39.                     ; by memAlloc(). Used for deallocating
  40. dsmVolTableSeg    DW    ?        ; volume table segment
  41. dsmTempBuffer    DD    ?        ; temporary mixing buffer for 8-bit
  42.                     ; modes
  43. dsmTBufSize    DW    ?        ; temp. buffer size in bytes
  44. dsmChannels    DD    ?        ; pointer to channel datas
  45. dsmChOpen    DW    ?        ; number of open channels
  46. dsmMasterVolume DB      ?               ; master volume
  47. dsmInstruments    DD    ?        ; instrument structures
  48. dsmUpdateMix    DW    ?        ; amount of data to mix between two
  49.                     ; updates
  50. dsmMixLeft    DW    ?        ; amount of data to be mixed before
  51.                     ; the next update
  52. dsmMixPos    DW    ?        ; mixing position in buffer
  53. dsmSamplePtr    DD      ?               ; conventional memory sample pointer,
  54.                                         ; used internally by some functions
  55. dsmMuted        DW      ?               ; 1 if muted, 0 if not
  56. dsmPaused       DW      ?               ; 1 if paused, 0 if not
  57.  
  58.  
  59. ;/***************************************************************************\
  60. ;*    Global variables for C version:
  61. ;\***************************************************************************/
  62.  
  63. IFNDEF __TP__
  64.  
  65. dsmBuffer    dmaBuffer  ?        ; final mixing buffer
  66. dsmDMAPos    DW    ?        ; mixing buffer playing position
  67.  
  68. ENDIF
  69.  
  70.  
  71.  
  72. CODESEG
  73.  
  74.  
  75. ;/***************************************************************************\
  76. ;*     Code segment variables used by some mixing routines:
  77. ;\***************************************************************************/
  78.  
  79. _mixCount    DW    ?        ; mixing counter
  80. _bpvalue    DW    ?        ; bp value in some mixing routines
  81.  
  82.  
  83.  
  84.  
  85. ;/***************************************************************************\
  86. ;*
  87. ;* Macro:    ChnPtr    segreg, indexreg, channum
  88. ;*
  89. ;* Description: Points a segment:index register pair to the channel structure
  90. ;*        of a channel. Also jumps to @@err if channel number is too
  91. ;*        big.
  92. ;*
  93. ;* Input:    segreg        segment register to be used
  94. ;*        indexreg    index register to be used
  95. ;*        channum     number of the channel
  96. ;*
  97. ;* Destroys:    ax, dx
  98. ;*
  99. ;\***************************************************************************/
  100.  
  101. MACRO    ChanPtr segreg, indexreg, channum
  102. LOCAL   chok
  103.  
  104.     mov    ax,channum
  105.     cmp    ax,[dsmChOpen]        ; channel number too big?
  106.         jb      chok
  107.         mov     ax,errInvalidChanNumber
  108.         jmp     @@err
  109.  
  110. chok:
  111.     mov    indexreg,SIZE dsmChannel
  112.     mul    indexreg            ; segreg:indexreg points to
  113.     mov    indexreg,[word dsmChannels]    ; the channel structure
  114.     add    indexreg,ax
  115.     mov    segreg,[word dsmChannels+2]
  116. ENDM
  117.  
  118.  
  119.  
  120. ;/***************************************************************************\
  121. ;*
  122. ;* Macro:    InstPtr segreg, indexreg, instnum
  123. ;*
  124. ;* Description: Points a segment:index register pair to the instrument
  125. ;*        structure for instrument instnum.
  126. ;*
  127. ;* Input:    segreg        segment register to be used
  128. ;*        indexreg    index register to be used
  129. ;*        instnum     number of the instrument
  130. ;*
  131. ;* Destroys:    ax, dx
  132. ;*
  133. ;\***************************************************************************/
  134.  
  135. MACRO    InstPtr segreg, indexreg, instnum
  136.  
  137.     ; point segreg:indexreg to beginning of instrument structures:
  138.     mov    segreg,[word dsmInstruments + 2]
  139.     mov    indexreg,[word dsmInstruments]
  140.  
  141.     mov    ax,instnum
  142.     mov    dx,SIZE dsmInstrument    ; segreg:indexreg points to instrument
  143.     mul    dx            ; data structure
  144.     add    indexreg,ax
  145. ENDM
  146.  
  147.  
  148.  
  149. ;/***************************************************************************\
  150. ;*
  151. ;* Macro:    NumLabel lblname, lblnum
  152. ;*
  153. ;* Description: Creates a numbered label in the source, format _namenum
  154. ;*        (ie. _table1)
  155. ;*
  156. ;* Input:    lblname     name for the label
  157. ;*        lblnum        number for the label
  158. ;*
  159. ;\***************************************************************************/
  160.  
  161. MACRO    NumLabel lblname, lblnum
  162. _&lblname&lblnum:
  163. ENDM
  164.  
  165.  
  166.  
  167. ;/***************************************************************************\
  168. ;*
  169. ;* Macro:    JmpTable lblname, lblcount
  170. ;*
  171. ;* Description: Creates a jump offset table in the source. The table consists
  172. ;*        of near offsets of labels _lblname0 - _lblnameX
  173. ;*
  174. ;* Input:    lblname     name of labels to be used for the table
  175. ;*        lblcount    number of labels
  176. ;*
  177. ;\***************************************************************************/
  178.  
  179. MACRO    dwoffs lblname, lblnum
  180.     DW    offset _&lblname&lblnum
  181. ENDM
  182.  
  183. MACRO    JmpTable lblname, lblcount
  184. ;LOCAL     numb
  185. numb = 0
  186. REPT    lblcount
  187.     dwoffs lblname, %numb
  188. numb = numb + 1
  189. ENDM
  190. ENDM
  191.  
  192.  
  193. ;/***************************************************************************\
  194. ;*
  195. ;* Macro:    MixLoop     mname, mixLp, DIinc, BPinc, counter
  196. ;*
  197. ;* Description: Generates code for inner mixing loop
  198. ;*
  199. ;* Input:    mname        mixing loop name (ie. m8mna)
  200. ;*        mixLp        macro that contains code for mixing loop
  201. ;*        DIinc        DI increment after each loop (32 times)
  202. ;*        BPinc        BP increment (0 if BP should not be modified)
  203. ;*        counter     loop counter (ie. cx)
  204. ;*
  205. ;\***************************************************************************/
  206.  
  207. MACRO    MixLoop     mname, mixLp, DIinc, BPinc, counter
  208. LOCAL    lp
  209.  
  210. LABEL    &mname    WORD
  211. JmpTable    &mname, 17
  212.  
  213.  
  214. lp:
  215. num = 0
  216. REPT    16
  217.     NumLabel &mname, %num
  218.     &mixLp %num
  219.     num = num + 1
  220. ENDM
  221.     NumLabel &mname, %num
  222.  
  223. IF DIinc NE 0
  224.     add    di,DIinc        ; mix next 32 bytes
  225. ENDIF
  226. IF BPinc NE 0
  227.     add    bp,BPinc
  228. ENDIF
  229.     dec    counter
  230.     jnz    lp
  231.     retn
  232.  
  233. ENDM    MixLoop
  234.  
  235.  
  236.  
  237. ;/***************************************************************************\
  238. ;*
  239. ;* Function:    dsmClearBuffer
  240. ;*
  241. ;* Description: Clears the DMA buffer
  242. ;*
  243. ;* Returns:     MIDAS error code
  244. ;*
  245. ;\***************************************************************************/
  246.  
  247. PROC    dsmClearBuffer  FAR
  248.  
  249.         test    [dsmMode],sd16bit       ; check if output mode is 16-bit
  250.     jnz    @@16
  251.  
  252.         push    di                              ; no, the buffer is unsigned
  253.         mov     es,[dsmBuffer.bsegment]         ; 8-bit - clear with 80h
  254.         xor     di,di                           ; bytes
  255.         mov     al,80h
  256.     mov    cx,[dsmBuffer.blength]
  257.     cld
  258.     rep    stosb
  259.     pop    di
  260.     jmp    @@ok
  261.  
  262. @@16:
  263.     push    di
  264.         mov     es,[dsmBuffer.bsegment]         ; 16-bit signed buffer
  265.         xor     di,di                           ; - clear with zero words
  266.         xor     ax,ax
  267.     mov    cx,[dsmBuffer.blength]
  268.     shr    cx,1
  269.     cld
  270.     rep    stosw
  271.     pop    di
  272.  
  273. @@ok:
  274.         xor     ax,ax
  275.         ret
  276. ENDP
  277.  
  278.  
  279.  
  280.  
  281. ;/***************************************************************************\
  282. ;*
  283. ;* Function:     int dsmInit(ushort mixRate, ushort mode);
  284. ;*
  285. ;* Description:  Initializes DSM
  286. ;*
  287. ;* Input:     ushort mixRate      mixing rate
  288. ;*         ushort mode         mixing mode (see enum sdMode)
  289. ;*
  290. ;* Returns:      MIDAS error code
  291. ;*
  292. ;\***************************************************************************/
  293.  
  294. PROC    dsmInit     FAR    mixRate : word, mode : word
  295.  
  296.         cld
  297.  
  298.     mov    [dsmChOpen],0        ; no open channels
  299.     mov    [dsmChannels],0     ; point channel structures to NULL
  300.         mov     [dsmMuted],0            ; not muted
  301.         mov     [dsmPaused],0           ; not paused
  302.  
  303.     mov    ax,[mode]
  304.  
  305.         or      ax,sdNormalQ
  306.         and     ax,not sdLowQ           ; only normal quality output
  307.         and     ax,not sdHighQ
  308.  
  309.     mov    [dsmMode],ax
  310.  
  311.     mov    ax,[mixRate]
  312.     mov    [dsmMixRate],ax
  313.     mov    bx,25            ; calculate mixing buffer size.
  314.     xor    dx,dx            ; dsmPlay _must_ be called at least
  315.     div    bx            ; 50 times per second, so the buffer
  316.                     ; is 1/25th second long
  317.     test    [dsmMode],sd16bit    ; 16-bit mixing?
  318.     jz    @@b16            ; if yes, multiply buffer length with
  319.     shl    ax,1            ; two
  320.  
  321. @@b16:    test    [dsmMode],sdStereo    ; stereo?
  322.     jz    @@bst            ; if yes, multiply buffer length with
  323.     shl    ax,1            ; two
  324.  
  325. @@bst:
  326.         add     ax,16                   ; make buffer length a multiple of 16
  327.         and     ax,0FFF0h
  328.  
  329.         ; allocate DMA buffer:
  330.     call    dmaAllocBuffer LANG, ax, seg dsmBuffer offset dsmBuffer
  331.         test    ax,ax                   ; buffer allocated succesfully?
  332.         jnz     @@err
  333.  
  334.  
  335.     mov    ax,VOLLEVELS * 256 * 2 + 16    ; volume table size in bytes
  336.  
  337.     test    [dsmMode],sd8bit    ; is a temporary mixing buffer needed?
  338.     jz    @@notb
  339.     test    [dsmMode],sdLowQ
  340.     jnz    @@notb
  341.  
  342.     mov    bx,[dsmBuffer.blength]    ; size of temporary 16-bit mixing
  343.     shl    bx,1            ; buffer for 8-bit modes
  344.     cmp    bx,TBUF_MAX        ; maximum size is TBUF_MAX, as in
  345.     jbe    @@tbok            ; the real mode we have to save
  346.     mov    bx,TBUF_MAX        ; memory...
  347.  
  348. @@tbok: mov    [dsmTBufSize],bx    ; save temporary buffer size
  349.     add    ax,bx            ; temporary buffer and volume table
  350.                     ; are in the same segment, with the
  351.                     ; buffer following the volume table
  352. @@notb:
  353.         ; allocate memory for volume table:
  354.         call    memAlloc LANG, ax, seg dsmVolTableMem offset dsmVolTableMem
  355.         test    ax,ax
  356.         jnz     @@err
  357.  
  358.         mov     dx,[word dsmVolTableMem+2]      ; point dx:ax to allocated
  359.         mov     ax,[word dsmVolTableMem]        ; block
  360.  
  361.     add    ax,15
  362.     shr    ax,4            ; calculate volume table segment
  363.     add    dx,ax            ; ( (off+15)/16 + seg )
  364.     mov    [dsmVolTableSeg],dx
  365.  
  366.     test    [dsmMode],sd8bit    ; is a temporary mixing buffer used?
  367.     jz    @@notb2
  368.     test    [dsmMode],sdLowQ
  369.     jnz    @@notb2
  370.  
  371.     mov    [word dsmTempBuffer],256*2*VOLLEVELS    ; temp buffer offset
  372.     mov    [word dsmTempBuffer+2],dx        ; and segment
  373.  
  374. @@notb2:
  375.     mov    [dsmMasterVolume],64    ; set master volume to maximum
  376.     mov    [dsmMixPos],0        ; start mixing from the beginning
  377.                     ; of the buffer
  378.     call    dsmSetUpdRate LANG, 5000 ; set the update rate to 50Hz
  379.         test    ax,ax
  380.         jnz     @@err
  381.  
  382.     ; Allocate memory for instrument structures:
  383.         call    memAlloc LANG, MAXINSTS * SIZE dsmInstrument, \
  384.                         seg dsmInstruments offset dsmInstruments
  385.         test    ax,ax
  386.         jnz     @@err
  387.  
  388.         les     di,[dsmInstruments]     ; point es:di to instrument structures
  389.     mov    cx,MAXINSTS
  390.  
  391.     ; initialize all instrument to reasonable states:
  392. @@instlp:
  393.     mov    [es:di+dsmInstrument.inuse],0    ; instrument not in use
  394.     mov    [es:di+dsmInstrument.sample],0    ; point sample to NULL
  395.     add    di,SIZE dsmInstrument        ; point es:di to next inst
  396.     loop    @@instlp
  397.  
  398.  
  399.     ; now clear the DMA playing buffer, as it may contain garbage
  400.         call    dsmClearBuffer
  401.  
  402.         jmp     @@done
  403.  
  404.  
  405. @@err:
  406.         ERROR   ID_dsmInit
  407.  
  408. @@done:
  409.     ret
  410. ENDP
  411.  
  412.  
  413.  
  414.  
  415.  
  416. ;/***************************************************************************\
  417. ;*
  418. ;* Function:     int dsmClose(void);
  419. ;*
  420. ;* Description:  Uninitializes DSM
  421. ;*
  422. ;* Returns:      MIDAS error code
  423. ;*
  424. ;\***************************************************************************/
  425.  
  426. PROC    dsmClose    FAR
  427.  
  428.     ; Deallocate mixing buffer:
  429.     call    dmaFreeBuffer LANG, seg dsmBuffer offset dsmBuffer
  430.         test    ax,ax
  431.         jnz     @@err
  432.  
  433.     ; Deallocate volume table and possible temporary buffer:
  434.     call    memFree LANG, [dsmVolTableMem]
  435.         test    ax,ax
  436.         jnz     @@err
  437.  
  438.     ; Deallocate instrument structures:
  439.     call    memFree LANG, [dsmInstruments]
  440.         test    ax,ax
  441.         jnz     @@err
  442.  
  443.         xor     ax,ax                   ; success
  444.         jmp     @@done
  445.  
  446. @@err:
  447.         ERROR   ID_dsmClose
  448.  
  449. @@done:
  450.     ret
  451. ENDP
  452.  
  453.  
  454.  
  455.  
  456. ;/***************************************************************************\
  457. ;*
  458. ;* Function:    int dsmGetMixRate(ushort *mixRate);
  459. ;*
  460. ;* Description: Reads the actual mixing rate
  461. ;*
  462. ;* Returns:     Midas error code.
  463. ;*              Mixing rate, in Hz, is stored in *mixRate
  464. ;*
  465. ;\***************************************************************************/
  466.  
  467. PROC    dsmGetMixRate   FAR     mixRate : dword
  468.  
  469.     mov    ax,[dsmMixRate]
  470.         les     bx,[mixRate]
  471.         mov     [es:bx],ax              ; store mixing rate to *mixRate
  472.  
  473.         xor     ax,ax                   ; always successful
  474.  
  475.     ret
  476. ENDP
  477.  
  478.  
  479.  
  480.  
  481. ;/***************************************************************************\
  482. ;*
  483. ;* Function:    int dsmGetMode(ushort *mode);
  484. ;*
  485. ;* Description: Reads the actual output mode
  486. ;*
  487. ;* Returns:     MIDAS error code.
  488. ;*              Output mode is stored in *mode.
  489. ;*
  490. ;\***************************************************************************/
  491.  
  492. PROC    dsmGetMode      FAR     mode : dword
  493.  
  494.     mov    ax,[dsmMode]
  495.         les     bx,[mode]
  496.         mov     [es:bx],ax              ; store output mode in *mode
  497.  
  498.         xor     ax,ax                   ; always successful
  499.  
  500.     ret
  501. ENDP
  502.  
  503.  
  504.  
  505.  
  506. ;/***************************************************************************\
  507. ;*
  508. ;* Function:     int dsmOpenChannels(unsigned channels);
  509. ;*
  510. ;* Description:  Opens channels for output
  511. ;*
  512. ;* Input:        unsigned channels      number of channels to open
  513. ;*
  514. ;* Returns:      MIDAS error code
  515. ;*
  516. ;\***************************************************************************/
  517.  
  518. PROC    dsmOpenChannels FAR    channels : word
  519. USES    di
  520.  
  521.         mov     [dsmMuted],0            ; not muted
  522.         mov     [dsmPaused],0           ; not paused
  523.  
  524.         ; calculate channel structure table size:
  525.     mov    ax,SIZE dsmChannel
  526.     mul    [channels]
  527.  
  528.         ; allocate memory for channel structures:
  529.         call    memAlloc LANG, ax, seg dsmChannels offset dsmChannels
  530.         test    ax,ax
  531.         jnz     @@err
  532.  
  533.         mov     ax,[channels]           ; save number of channels
  534.         mov     [dsmChOpen],ax
  535.  
  536.         ; Both 8 and 16-bit modes require a 16-bit signed volume table.
  537.         ; Now calculate the volume table:
  538.  
  539.     mov    es,[dsmVolTableSeg]
  540.     xor    edi,edi         ; index in table
  541.     mov    cx,256*VOLLEVELS    ; number of volume table entries
  542.  
  543. @@vtlp: mov    ax,di
  544.  
  545.         and     ax,0FFh                 ; ax = signed volume table entry
  546.         sub     ax,128                  ; at full volume (volume table is
  547.         shl     ax,8                    ; 16-bit signed)
  548.  
  549.     mov    bx,di
  550.     shr    bx,8            ; bx = volume
  551.         imul    bx                      ; multiply with volume
  552.     mov    bx,VOLLEVELS - 1
  553.         idiv    bx                      ; divide with maximum volume
  554.  
  555.         cwd
  556.         idiv    [dsmChOpen]             ; divide with number of channels
  557.  
  558.         mov     [es:edi+edi],ax         ; store value in volume table
  559.  
  560. @@vtlb: inc    edi            ; next value
  561.     loop    @@vtlp
  562.  
  563.  
  564.     call    dsmClearChannels LANG    ; clear all channels
  565.         test    ax,ax
  566.         jnz     @@err
  567.  
  568.         xor     ax,ax                   ; successful
  569.         jmp     @@done
  570.  
  571.  
  572. @@err:
  573.         ERROR   ID_dsmOpenChannels
  574.  
  575. @@done:
  576.     ret
  577. ENDP
  578.  
  579.  
  580.  
  581.  
  582.  
  583. ;/***************************************************************************\
  584. ;*
  585. ;* Function:     int dsmCloseChannels(void);
  586. ;*
  587. ;* Description:  Closes open channels
  588. ;*
  589. ;* Returns:      MIDAS error code
  590. ;*
  591. ;\***************************************************************************/
  592.  
  593. PROC    dsmCloseChannels FAR
  594.  
  595.         ; Check that channels have been opened
  596.         cmp     [dsmChOpen],0
  597.         jne     @@chok
  598.         mov     ax,errNoChannels
  599.         jmp     @@err
  600.  
  601. @@chok:
  602.         ; deallocate channel structures:
  603.         call    memFree LANG, [dsmChannels]
  604.         test    ax,ax
  605.         jnz     @@err
  606.  
  607.     mov    [dsmChOpen],0        ; no open channels
  608.  
  609.         call    dsmClearBuffer          ; clear DMA buffer
  610.         jmp     @@done
  611.  
  612. @@err:
  613.         ERROR   ID_dsmCloseChannels
  614.  
  615. @@done:
  616.     ret
  617. ENDP
  618.  
  619.  
  620.  
  621.  
  622.  
  623. ;/***************************************************************************\
  624. ;*
  625. ;* Function:     int dsmClearChannels(void);
  626. ;*
  627. ;* Description:  Clears open channels (removes all sounds)
  628. ;*
  629. ;* Returns:      MIDAS error code
  630. ;*
  631. ;\***************************************************************************/
  632.  
  633. PROC    dsmClearChannels  FAR
  634.  
  635.     mov    cx,[dsmChOpen]        ; number of open channels
  636.     test    cx,cx            ; if none open, error
  637.         jnz     @@chok
  638.         mov     ax,errNoChannels
  639.         jmp     @@err
  640.  
  641. @@chok:
  642.         les     bx,[dsmChannels]        ; point es:bx to channel structures
  643.  
  644. @@chlp:
  645.     mov    [es:bx+dsmChannel.hasData],0    ; no data to be played
  646.     mov    [es:bx+dsmChannel.muted],0    ; not muted
  647.     mov    [es:bx+dsmChannel.inst],0    ; no instrument selected
  648.         mov     [es:bx+dsmChannel.instChanged],0     ; instrument not changed
  649.         mov     [es:bx+dsmChannel.smpPos],smpNone       ; no sample
  650.         mov     [es:bx+dsmChannel.rate],0       ; no rate set
  651.     mov    [es:bx+dsmChannel.panning],panMiddle
  652.  
  653.         add     bx,SIZE dsmChannel      ; next channel
  654.     loop    @@chlp
  655.  
  656.         xor     ax,ax                   ; success
  657.         jmp     @@done
  658.  
  659.  
  660. @@err:
  661.         ERROR   ID_dsmClearChannels
  662.  
  663. @@done:
  664.     ret
  665. ENDP
  666.  
  667.  
  668.  
  669.  
  670.  
  671. ;/***************************************************************************\
  672. ;*
  673. ;* Function:     int dsmMute(int mute);
  674. ;*
  675. ;* Description:  Mutes all channels
  676. ;*
  677. ;* Input:        int mute               1 = mute, 0 = un-mute
  678. ;*
  679. ;* Returns:      MIDAS error code
  680. ;*
  681. ;\***************************************************************************/
  682.  
  683. PROC    dsmMute     FAR        mute : word
  684.  
  685.         mov     ax,[mute]
  686.         mov     [dsmMuted],ax
  687.  
  688.     ret
  689. ENDP
  690.  
  691.  
  692.  
  693.  
  694.  
  695. ;/***************************************************************************\
  696. ;*
  697. ;* Function:     int dsmPause(int pause);
  698. ;*
  699. ;* Description:  Pauses or resumes the playing
  700. ;*
  701. ;* Input:        int pause              1 = pause, 0 = resume
  702. ;*
  703. ;* Returns:      MIDAS error code
  704. ;*
  705. ;\***************************************************************************/
  706.  
  707. PROC    dsmPause    FAR        pause : word
  708.  
  709.         mov     ax,[pause]              ; copy paused flag
  710.         mov     [dsmPaused],ax
  711.  
  712.         call    dsmClearBuffer LANG     ; clear playing buffer
  713.  
  714.         ret
  715. ENDP
  716.  
  717.  
  718.  
  719.  
  720.  
  721. ;/***************************************************************************\
  722. ;*
  723. ;* Function:     int dsmSetMasterVolume(uchar masterVolume);
  724. ;*
  725. ;* Description:  Sets the master volume
  726. ;*
  727. ;* Input:        uchar masterVolume     master volume (0 - 64)
  728. ;*
  729. ;* Returns:      MIDAS error code
  730. ;*
  731. ;\***************************************************************************/
  732.  
  733. PROC    dsmSetMasterVolume FAR  masterVolume : byte
  734.  
  735.         mov     al,[masterVolume]
  736.         mov     [dsmMasterVolume],al
  737.  
  738.         xor     ax,ax                   ; always successful
  739.  
  740.         ret
  741. ENDP
  742.  
  743.  
  744.  
  745.  
  746.  
  747. ;/***************************************************************************\
  748. ;*
  749. ;* Function:     int dsmPlaySound(unsigned channel, ulong rate);
  750. ;*
  751. ;* Description:  Plays a sound
  752. ;*
  753. ;* Input:        unsigned channel       channel number
  754. ;*               ulong rate             playing rate in Hz
  755. ;*
  756. ;* Returns:      MIDAS error code
  757. ;*
  758. ;\***************************************************************************/
  759.  
  760. PROC    dsmPlaySound    FAR    channel : word, rate : dword
  761.  
  762.     call    dsmSetPosition LANG, [channel], 0    ; start from the
  763.     test    ax,ax                    ; beg. of the sample
  764.         jnz     @@err
  765.     call    dsmSetRate LANG, [channel], [rate]    ; set playing rate
  766.     test    ax,ax
  767.         jnz     @@err
  768.  
  769.         xor     ax,ax                   ; success
  770.         jmp     @@done
  771.  
  772. @@err:
  773.         ERROR   ID_dsmPlaySound
  774.  
  775. @@done:
  776.     ret
  777. ENDP
  778.  
  779.  
  780.  
  781.  
  782.  
  783. ;/***************************************************************************\
  784. ;*
  785. ;* Function:     int dsmStopSound(unsigned channel);
  786. ;*
  787. ;* Description:  Stops playing a sound
  788. ;*
  789. ;* Input:        unsigned channel       channel number
  790. ;*
  791. ;* Returns:      MIDAS error code
  792. ;*
  793. ;\***************************************************************************/
  794.  
  795. PROC    dsmStopSound    FAR    channel : word
  796.  
  797.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  798.     mov    [es:bx+dsmChannel.hasData],0    ; channel has no data to
  799.                         ; be played
  800.         xor     ax,ax
  801.         jmp     @@done
  802.  
  803. @@err:
  804.         ERROR   ID_dsmStopSound
  805.  
  806. @@done:
  807.     ret
  808. ENDP
  809.  
  810.  
  811.  
  812.  
  813.  
  814. ;/***************************************************************************\
  815. ;*
  816. ;* Function:     int dsmSetRate(unsigned channel, ulong rate);
  817. ;*
  818. ;* Description:  Sets the playing rate
  819. ;*
  820. ;* Input:        unsigned channel        channel number
  821. ;*         ulong rate         playing rate in Hz
  822. ;*
  823. ;* Returns:      MIDAS error code
  824. ;*
  825. ;\***************************************************************************/
  826.  
  827. PROC    dsmSetRate    FAR    channel : word, rate : dword
  828.  
  829.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  830.  
  831.     mov    eax,[rate]
  832.     mov    [es:bx+dsmChannel.rate],eax    ; set playing rate on channel
  833.  
  834.         xor     ax,ax                   ; success
  835.         jmp     @@done
  836.  
  837. @@err:
  838.         ERROR   ID_dsmSetRate
  839. @@done:
  840.     ret
  841. ENDP
  842.  
  843.  
  844.  
  845.  
  846.  
  847. ;/***************************************************************************\
  848. ;*
  849. ;* Function:     int dsmGetRate(unsigned channel, ulong *rate);
  850. ;*
  851. ;* Description:  Returns the playing rate or zero if nothing is being
  852. ;*         played
  853. ;*
  854. ;* Input:        unsigned channel       channel number
  855. ;*               ulong *rate            pointer to playing rate
  856. ;*
  857. ;* Returns:      MIDAS error code.
  858. ;*               Playing rate, in Hz, or zero, if nothing is being
  859. ;*               played, is stored in *rate
  860. ;*
  861. ;\***************************************************************************/
  862.  
  863. PROC    dsmGetRate      FAR     channel : word, rate : dword
  864. USES    si
  865.  
  866.         lgs     si,[rate]               ; point gs:si to rate variable
  867.  
  868.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  869.  
  870.     cmp    [es:bx+dsmChannel.hasData],0    ; data on channel?
  871.     je    @@nodata
  872.  
  873.         ; get playing rate:
  874.         mov     eax,[es:bx+dsmChannel.rate]
  875.         jmp     @@ok
  876.  
  877. @@nodata:
  878.         ; no data - return 0 in *rate:
  879.         xor     eax,eax
  880. @@ok:
  881.         mov     [gs:si],eax             ; store playing rate in *rate
  882.         xor     ax,ax                   ; success
  883.         jz      @@done
  884.  
  885. @@err:
  886.         ERROR   ID_dsmGetRate
  887. @@done:
  888.     ret
  889. ENDP
  890.  
  891.  
  892.  
  893.  
  894.  
  895. ;/***************************************************************************\
  896. ;*
  897. ;* Function:     int dsmSetVolume(unsigned channel, uchar volume);
  898. ;*
  899. ;* Description:  Sets the volume
  900. ;*
  901. ;* Input:        unsigned channel       channel number
  902. ;*               uchar volume           volume (0 - 64)
  903. ;*
  904. ;* Returns:      MIDAS error code
  905. ;*
  906. ;\***************************************************************************/
  907.  
  908. PROC    dsmSetVolume    FAR     channel : word, volume : byte
  909.  
  910.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  911.  
  912.         mov     al,[volume]             ; ax = new volume
  913.         cmp     al,64                   ; is volume > 64?
  914.     jbe    @@ok
  915.         mov     al,64                   ; volume limit is 64
  916.  
  917. @@ok:    mov    [es:bx+dsmChannel.volume],al    ; set new volume
  918.  
  919.         xor     ax,ax                   ; success
  920.         jmp     @@done
  921.  
  922. @@err:
  923.         ERROR   ID_dsmSetVolume
  924.  
  925. @@done:
  926.     ret
  927. ENDP
  928.  
  929.  
  930.  
  931.  
  932.  
  933. ;/***************************************************************************\
  934. ;*
  935. ;* Function:     int dsmSetInstrument(unsigned channel, ushort inst);
  936. ;*
  937. ;* Description:  Sets instrument number
  938. ;*
  939. ;* Input:        unsigned channel       channel number
  940. ;*               ushort inst            instrument number
  941. ;*
  942. ;* Returns:      MIDAS error code
  943. ;*
  944. ;\***************************************************************************/
  945.  
  946. PROC    dsmSetInstrument FAR    channel : word, inst : word
  947. USES    si
  948.  
  949.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  950.  
  951.     mov    ax,[inst]
  952.  
  953.         test    ax,ax
  954.         jns     @@1                     ; check that the instrument number
  955.         jz      @@badinst               ; is valid - 0 < inst <= MAXINSTS
  956.         cmp     ax,MAXINSTS
  957.         jbe     @@1
  958.  
  959. @@badinst:
  960.         mov     ax,errInvalidInstHandle ; invalid instrument handle
  961.         jmp     @@err
  962.  
  963. @@1:
  964.     dec    ax            ; instrument numbers start from 1
  965.     InstPtr gs, si, ax        ; point gs:si to instrument structure
  966.     cmp    [gs:si+dsmInstrument.inuse],1    ; is instrument in use?
  967.         je      @@2
  968.  
  969.         mov     ax,errInvalidInstHandle ; invalid instrument handle
  970.         jmp     @@err
  971.  
  972. @@2:
  973.         mov     ax,[inst]
  974.     mov    [es:bx+dsmChannel.inst],ax    ; set new instrument number
  975.  
  976.         mov     al,[gs:si+dsmInstrument.volume] ; set instrument default
  977.         mov     [es:bx+dsmChannel.volume],al    ; volume as the playing volume
  978.  
  979.         cmp     [ALE],1
  980.         je      @@ale
  981.  
  982.  
  983.         ; no Amiga Loop Emulation - copy instrument data (sample pointer etc.
  984.         ; to channel structure so that instrument will be used now):
  985.  
  986.         call    dsmUseInstrument
  987.  
  988.     cmp    [es:bx+dsmChannel.hasData],1
  989.     jne    @@nodata
  990.  
  991.         ; Data is being played on the channel - reset the playing position
  992.         ; to make sure playing does not continue past the end of the
  993.         ; instrument
  994.     call    dsmSetPosition LANG, [channel], [es:bx+dsmChannel.pos]
  995.         test    ax,ax
  996.         jnz     @@err
  997.  
  998. @@nodata:
  999.         xor     ax,ax                   ; success
  1000.         jmp     @@done
  1001.  
  1002.  
  1003. @@ale:
  1004.         ; Amiga Loop Emulation is active - do not set instrument values to
  1005.         ; channel structure. Just flag that the instrument has been changed.
  1006.         ; The values will be set when the current sample or sample loop ends
  1007.         ; or the playing position is set.
  1008.         mov     [es:bx+dsmChannel.instChanged],1        ; instrument has been
  1009.                                                         ; changed
  1010.  
  1011.         ; If data is being played, we are done.
  1012.         cmp     [es:bx+dsmChannel.hasData],1
  1013.         je      @@aledone
  1014.  
  1015.         ; Data is not being played - if the new sample is looping and a
  1016.         ; sampling rate has been set, start playing from the loop
  1017.         ; beginning
  1018.         cmp     [gs:si+dsmInstrument.looping],1
  1019.         jne     @@aledone
  1020.  
  1021.         ; Start playing from loop start: (dsmSetPosition() sets the
  1022.         ; instrument values to channel structure)
  1023.         call    dsmSetPosition LANG, [channel], \
  1024.                 [gs:si+dsmInstrument.loopStart]
  1025.         test    ax,ax
  1026.         jnz     @@err
  1027.  
  1028.  
  1029. @@aledone:
  1030.         xor     ax,ax
  1031.         jmp     @@done
  1032.  
  1033. @@err:
  1034.         ERROR   ID_dsmSetInstrument
  1035.  
  1036. @@done:
  1037.     ret
  1038. ENDP
  1039.  
  1040.  
  1041.  
  1042.  
  1043. ;/***************************************************************************\
  1044. ;*
  1045. ;* Function:    dsmUseInstrument
  1046. ;*
  1047. ;* Description: Sets the instrument values on a channel to the channel
  1048. ;*              structure so that the instrument specified by
  1049. ;*              dsmChannel.inst will be used for playing.
  1050. ;*
  1051. ;* Input:       es:bx                   pointer to channel structure
  1052. ;*
  1053. ;* Destroys:    eax, dx
  1054. ;*
  1055. ;\***************************************************************************/
  1056.  
  1057. PROC NOLANGUAGE dsmUseInstrument        NEAR
  1058.  
  1059.         push    gs si
  1060.  
  1061.         mov     ax,[es:bx+dsmChannel.inst]      ; ax = instrument number
  1062.         dec     ax                              ; (table starts from 0)
  1063.         InstPtr gs, si, ax                      ; point ds:si to inst struct
  1064.  
  1065.         mov     eax,[gs:si+dsmInstrument.sample]        ; copy sample
  1066.         mov     [es:bx+dsmChannel.sample],eax           ; pointer
  1067.  
  1068.         mov     al,[gs:si+dsmInstrument.smpType]        ; copy sample type
  1069.         mov     [es:bx+dsmChannel.smpType],al
  1070.  
  1071.         mov     al,[gs:si+dsmInstrument.smpPos]         ; copy sample position
  1072.         mov     [es:bx+dsmChannel.smpPos],al
  1073.  
  1074.         mov     ax,[gs:si+dsmInstrument.slength]        ; copy sample length
  1075.         mov     [es:bx+dsmChannel.slength],ax
  1076.  
  1077.         mov     ax,[gs:si+dsmInstrument.loopStart]      ; copy sample loop
  1078.         mov     [es:bx+dsmChannel.loopStart],ax         ; start
  1079.  
  1080.         mov     ax,[gs:si+dsmInstrument.loopEnd]        ; copy sample loop
  1081.         mov     [es:bx+dsmChannel.loopEnd],ax           ; end
  1082.  
  1083.         mov     al,[gs:si+dsmInstrument.looping]        ; copy inst looping
  1084.         mov     [es:bx+dsmChannel.looping],al           ; flag
  1085.  
  1086.         mov     [es:bx+dsmChannel.instChanged],0
  1087.  
  1088.         pop     si gs
  1089.  
  1090.         ret
  1091. ENDP
  1092.  
  1093.  
  1094.  
  1095.  
  1096.  
  1097. ;/***************************************************************************\
  1098. ;*
  1099. ;* Function:     int dsmSetPosition(unsigned channel, ushort pos);
  1100. ;*
  1101. ;* Description:  Sets the playing position from the beginning of instrument
  1102. ;*
  1103. ;* Input:        unsigned channel        channel number
  1104. ;*         ushort pos         new position
  1105. ;*
  1106. ;* Returns:      MIDAS error code
  1107. ;*
  1108. ;\***************************************************************************/
  1109.  
  1110. PROC    dsmSetPosition    FAR    channel : word, pos : word
  1111. USES    si
  1112.  
  1113.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  1114.  
  1115.         cmp     [es:bx+dsmChannel.instChanged],1        ; has instrument been
  1116.         jne     @@noinstch                              ; changed?
  1117.         call    dsmUseInstrument                        ; use new instrument
  1118.  
  1119. @@noinstch:
  1120.     mov    cx,[pos]        ; cx = new position
  1121.  
  1122.         mov     ax,[es:bx+dsmChannel.inst]      ; current instrument
  1123.         test    ax,ax                   ; is there a instrument selected?
  1124.     jz    @@noset         ; if not, then don't play
  1125.  
  1126.         cmp     [es:bx+dsmChannel.smpType],smpNone      ; is there a sample?
  1127.     je    @@noset
  1128.  
  1129.         cmp     [es:bx+dsmChannel.looping],1    ; is instrument looping?
  1130.     je    @@looping
  1131.  
  1132.         ; instrument is not looping - stop playing if new position is past
  1133.         ; sample length:
  1134.         cmp     cx,[es:bx+dsmChannel.slength]
  1135.         jb      @@set
  1136.         call    dsmStopSound LANG, [channel]
  1137.         test    ax,ax
  1138.         jnz     @@err
  1139.     jmp    @@noset
  1140.  
  1141. @@looping:
  1142.         ; instrument is looping - if new position is past loop end, set it to
  1143.         ; loop start:
  1144.         cmp     cx,[es:bx+dsmChannel.loopEnd]
  1145.         jb      @@set
  1146.         mov     cx,[es:bx+dsmChannel.loopStart]
  1147.  
  1148. @@set:
  1149.     mov    [es:bx+dsmChannel.pos],cx    ; set position
  1150.     mov    [es:bx+dsmChannel.posl],0    ; set position fraction to 0
  1151.     mov    [es:bx+dsmChannel.hasData],1    ; channel has data
  1152.  
  1153. @@noset:
  1154.         xor     ax,ax                   ; success
  1155.         jmp     @@done
  1156.  
  1157. @@err:
  1158.         ERROR   ID_dsmSetPosition
  1159.  
  1160. @@done:
  1161.     ret
  1162. ENDP
  1163.  
  1164.  
  1165.  
  1166.  
  1167.  
  1168. ;/***************************************************************************\
  1169. ;*
  1170. ;* Function:     int dsmGetPosition(unsigned channel, ushort *pos);
  1171. ;*
  1172. ;* Description:  Gets the playing position
  1173. ;*
  1174. ;* Input:        unsigned channel       channel number
  1175. ;*               ushort *pos            pointer to the position variable
  1176. ;*
  1177. ;* Returns:      MIDAS error code.
  1178. ;*               Playing position from the beginning of instrument is stored
  1179. ;*               in *pos.
  1180. ;*
  1181. ;\***************************************************************************/
  1182.  
  1183. PROC    dsmGetPosition  FAR     channel : word, pos : dword
  1184.  
  1185.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  1186.     mov    ax,[es:bx+dsmChannel.pos]
  1187.  
  1188.         les     bx,[pos]
  1189.         mov     [es:bx],ax              ; store playing position in *pos
  1190.  
  1191.         xor     ax,ax
  1192.         jmp     @@done
  1193.  
  1194. @@err:
  1195.         ERROR   ID_dsmGetPosition
  1196.  
  1197. @@done:
  1198.     ret
  1199. ENDP
  1200.  
  1201.  
  1202.  
  1203.  
  1204.  
  1205. ;/***************************************************************************\
  1206. ;*
  1207. ;* Function:    int dsmSetPanning(unsigned channel, short panning);
  1208. ;*
  1209. ;* Description: Sets the panning status of a channel
  1210. ;*
  1211. ;* Input:       unsigned channel      channel number
  1212. ;*              short panning         panning information (see enum sdPanning)
  1213. ;*
  1214. ;* Returns:     MIDAS error code
  1215. ;*
  1216. ;\***************************************************************************/
  1217.  
  1218. PROC    dsmSetPanning    FAR    channel : word, panning : word
  1219.  
  1220.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  1221.     mov    ax,[panning]
  1222.         mov     [es:bx+dsmChannel.panning],al
  1223.  
  1224.         xor     ax,ax                   ; success
  1225.         jmp     @@done
  1226.  
  1227. @@err:
  1228.         ERROR   ID_dsmSetPanning
  1229.  
  1230. @@done:
  1231.     ret
  1232. ENDP
  1233.  
  1234.  
  1235.  
  1236.  
  1237. ;/***************************************************************************\
  1238. ;*
  1239. ;* Function:    int dsmGetPanning(unsigned channel, short *panning);
  1240. ;*
  1241. ;* Description: Returns the panning status of a channel
  1242. ;*
  1243. ;* Input:       unsigned channel        channel number
  1244. ;*              short *panning          pointer to panning variable
  1245. ;*
  1246. ;* Returns:     MIDAS error code.
  1247. ;*              Panning information is stored in *panning
  1248. ;*
  1249. ;\***************************************************************************/
  1250.  
  1251. PROC    dsmGetPanning   FAR     channel : word, panning : dword
  1252.  
  1253.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  1254.         movsx   ax,[es:bx+dsmChannel.panning]   ; ax = panning value
  1255.  
  1256.         cmp     al,panSurround          ; if panning is panSurround, clear
  1257.         jne     @@panok                 ; upper nybble, as panSurround is a
  1258.         mov     ax,panSurround          ; positive value even if bit 7 is 1
  1259.  
  1260. @@panok:
  1261.         les     bx,[panning]
  1262.         mov     [es:bx],ax              ; store panning info in *panning
  1263.  
  1264.         xor     ax,ax                   ; success
  1265.     jmp    @@done
  1266.  
  1267. @@err:
  1268.         ERROR   ID_dsmGetPanning
  1269.  
  1270. @@done:
  1271.     ret
  1272. ENDP
  1273.  
  1274.  
  1275.  
  1276.  
  1277. ;/***************************************************************************\
  1278. ;*
  1279. ;* Function:     int dsmMuteChannel(unsigned channel, int mute);
  1280. ;*
  1281. ;* Description:  Mutes/un-mutes a channel
  1282. ;*
  1283. ;* Input:     ushort channel      channel number
  1284. ;*         ushort mute         1 = mute, 0 = un-mute
  1285. ;*
  1286. ;* Returns:      MIDAS error code
  1287. ;*
  1288. ;\***************************************************************************/
  1289.  
  1290. PROC    dsmMuteChannel    FAR    channel : word, mute : word
  1291.  
  1292.     ChanPtr es, bx, [channel]    ; point es:bx to channel structure
  1293.     mov    ax,[mute]
  1294.     mov    [es:bx+dsmChannel.muted],al
  1295.  
  1296.         xor     ax,ax                   ; success
  1297.     jmp    @@done
  1298.  
  1299. @@err:
  1300.         ERROR   ID_dsmMuteChannel
  1301.  
  1302. @@done:
  1303.     ret
  1304. ENDP
  1305.  
  1306.  
  1307.  
  1308.  
  1309. ;/***************************************************************************\
  1310. ;*
  1311. ;* Function:    int dsmAddInstrument(void far *sample, int smpType,
  1312. ;*                      ushort length, ushort loopStart, ushort loopEnd,
  1313. ;*                      uchar volume,  int loop, ushort *instHandle);
  1314. ;*
  1315. ;* Description:  Adds a new instrument to the instrument list
  1316. ;*
  1317. ;* Input:        void far *sample       Pointer to sample data. MUST be
  1318. ;*                                      in conventional memory. Sample
  1319. ;*                                      data is copied into another memory
  1320. ;*                                      location and so sample should be
  1321. ;*                                      deallocated after this function
  1322. ;*                                      call.
  1323. ;*               int smpType            sample type (see enum smpTypes)
  1324. ;*               ushort length          sample length
  1325. ;*               ushort loopStart       sample loop start
  1326. ;*               ushort loopEnd         sample loop end
  1327. ;*               uchar volume           sample default volume (0 - 64)
  1328. ;*               int loop               looping (1 = looping sample, 0 = not)
  1329. ;*               ushort *instHandle     pointer to variable to store the SD
  1330. ;*                                      instrument handle
  1331. ;*
  1332. ;* Returns:      MIDAS error code
  1333. ;*
  1334. ;\***************************************************************************/
  1335.  
  1336. PROC    dsmAddInstrument FAR    sample : dword, smpType : word, \
  1337.         slength : word, loopStart : word, loopEnd : word,\
  1338.                 volume : byte, sloop : word, instHandle : dword
  1339. USES    si
  1340. LOCAL    instNum : word
  1341.  
  1342.     les    si,[dsmInstruments]    ; point es:si to instrument structures
  1343.     xor    bx,bx            ; bx = instrument number
  1344.     mov    cx,MAXINSTS
  1345.  
  1346.     ; Attempt to find first unused instrument:
  1347. @@ilp:    cmp    [es:si+dsmInstrument.inuse],0
  1348.     je    @@inst
  1349.     add    si,SIZE dsmInstrument    ; point es:si to next inst struct
  1350.     inc    bx            ; next instrument
  1351.     loop    @@ilp
  1352.  
  1353.         mov     ax,errNoInstHandles     ; no free instrument handles
  1354.         jmp     @@err
  1355.  
  1356.  
  1357. @@inst:
  1358.     ; Unused instrument found. bx contains the instrument number and
  1359.     ; es:si points to the instrument structure
  1360.  
  1361.     mov    [instNum],bx
  1362.  
  1363.     mov    [es:si+dsmInstrument.inuse],1    ; instrument is in use
  1364.  
  1365.     cmp    [smpType],smpNone    ; is there a sample?
  1366.     je    @@nosmp
  1367.     cmp    [slength],0
  1368.     je    @@nosmp
  1369.  
  1370.     cmp    [useEMS],0        ; should EMS memory be used?
  1371.     je    @@conv
  1372.  
  1373.         lea     ax,[si+dsmInstrument.sample]    ; point es:ax to current
  1374.                                                 ; dsmInstrument.sample
  1375.     push    es
  1376.         call    emsAlloc LANG, [slength], es ax ; allocate EMS for sample
  1377.     pop    es
  1378.         test    ax,ax
  1379.         jz      @@emsok
  1380.  
  1381.         cmp     ax,errOutOfEMS          ; check if the error was about lack
  1382.         jne     @@err                   ; of EMS or something else
  1383.  
  1384.         ; Not enough EMS memory. If forceEMS == 1, only EMS memory
  1385.         ; should be used.
  1386.         cmp     [forceEMS],1            ; use conventional memory if
  1387.         jne     @@conv                  ; forceEMS != 1
  1388.  
  1389.         mov     ax,errOutOfEMS          ; out of EMS memory
  1390.         jmp     @@err
  1391.  
  1392. @@emsok:
  1393.         ; map EMS block to conventional memory:
  1394.         push    es
  1395.         call    emsMap LANG, [es:si+dsmInstrument.sample], \
  1396.                 seg dsmSamplePtr offset dsmSamplePtr
  1397.         pop     es
  1398.         test    ax,ax
  1399.         jnz     @@err
  1400.  
  1401.         push    ds es si di
  1402.         les     di,[dsmSamplePtr]       ; point es:di to EMS block in memory
  1403.         lds     si,[sample]             ; point ds:si to sample data
  1404.     mov    cx,[slength]
  1405.     cld
  1406.         rep     movsb                   ; copy sample data to EMS memory block
  1407.     pop    di si es ds
  1408.  
  1409.     mov    [es:si+dsmInstrument.smpPos],sdSmpEMS    ; sample is in EMS
  1410.         jmp     @@smpok
  1411.  
  1412.  
  1413. @@conv:
  1414.         ; allocate conventional memory for sample:
  1415.         lea     ax,[si+dsmInstrument.sample]    ; point es:ax to current
  1416.                                                 ; dsmInstrument.sample
  1417.         push    es
  1418.         call    memAlloc LANG, [slength], es ax
  1419.     pop    es
  1420.         test    ax,ax
  1421.         jnz     @@err
  1422.  
  1423.     push    si di ds es
  1424.         les     di,[es:si+dsmInstrument.sample] ; point es:di to memory
  1425.                                                 ; allocated for sample
  1426.         lds     si,[sample]             ; point ds:si to sample data
  1427.         mov     cx,[slength]
  1428.     cld
  1429.         rep     movsb                   ; copy sample data to new memory area
  1430.     pop    es ds di si
  1431.  
  1432.         ; sample is in conventional memory:
  1433.         mov     [es:si+dsmInstrument.smpPos],sdSmpConv
  1434.  
  1435.     jmp    @@smpok
  1436.  
  1437. @@nosmp:
  1438.         ; no sample:
  1439.         mov     [es:si+dsmInstrument.sample],0
  1440.     mov    [es:si+dsmInstrument.smpType],smpNone
  1441.     mov    [es:si+dsmInstrument.smpPos],sdSmpNone
  1442.  
  1443. @@smpok:
  1444.         mov     ax,[smpType]
  1445.     mov    [es:si+dsmInstrument.smpType],al    ; copy sample type
  1446.  
  1447.         ; copy instrument data: length, loop and volume:
  1448.         mov     ax,[slength]
  1449.     mov    [es:si+dsmInstrument.slength],ax
  1450.     mov    ax,[loopStart]
  1451.     mov    [es:si+dsmInstrument.loopStart],ax
  1452.     mov    ax,[loopEnd]
  1453.     mov    [es:si+dsmInstrument.loopEnd],ax
  1454.         mov     al,[volume]
  1455.     mov    [es:si+dsmInstrument.volume],al
  1456.     mov    ax,[sloop]
  1457.     mov    [es:si+dsmInstrument.looping],al
  1458.  
  1459.     mov    ax,[instNum]
  1460.         inc     ax                      ; instrument handle numbers start at 1
  1461.         les     bx,[instHandle]         ; store instrument handle in
  1462.         mov     [es:bx],ax              ; *instHandle
  1463.  
  1464.         xor     ax,ax                   ; success
  1465.     jmp    @@done
  1466.  
  1467.  
  1468. @@err:
  1469.         ERROR   ID_dsmAddInstrument
  1470.  
  1471. @@done:
  1472.     ret
  1473. ENDP
  1474.  
  1475.  
  1476.  
  1477.  
  1478.  
  1479. ;/***************************************************************************\
  1480. ;*
  1481. ;* Function:    int dsmRemInstrument(ushort inst);
  1482. ;*
  1483. ;* Description: Removes an instrument from the instrument list, and
  1484. ;*              deallocates sample memory
  1485. ;*
  1486. ;* Input:    ushort inst        instrument number
  1487. ;*
  1488. ;* Returns:     MIDAS error code
  1489. ;*
  1490. ;\***************************************************************************/
  1491.  
  1492. PROC    dsmRemInstrument FAR    inst : word
  1493.  
  1494.         mov     ax,[inst]
  1495.  
  1496.         test    ax,ax
  1497.         jnz     @@1                     ; check that the instrument number
  1498.         cmp     ax,MAXINSTS             ; is valid - 0 < inst <= MAXINSTS
  1499.         jbe     @@1
  1500.  
  1501.         mov     ax,errInvalidInstHandle ; invalid instrument handle
  1502.         jmp     @@err
  1503.  
  1504. @@1:
  1505.     dec    ax
  1506.     InstPtr es, bx, ax        ; point es:bx to inst data structure
  1507.  
  1508.         cmp     [es:bx+dsmInstrument.inuse],1   ; is instrument in use?
  1509.         je      @@2
  1510.  
  1511.         mov     ax,errInvalidInstHandle ; invalid instrument handle
  1512.         jmp     @@err
  1513.  
  1514. @@2:
  1515.         cmp     [es:bx+dsmInstrument.smpPos],sdSmpConv
  1516.         je      @@conv
  1517.  
  1518.         cmp     [es:bx+dsmInstrument.smpPos],sdSmpNone
  1519.         je      @@dealloc
  1520.  
  1521.         ; sample is in EMS - deallocate
  1522.         push    es bx
  1523.         call    emsFree LANG, [es:bx+dsmInstrument.sample]
  1524.         pop     bx es
  1525.         test    ax,ax
  1526.         jnz     @@err
  1527.  
  1528.         jmp     @@dealloc
  1529.  
  1530. @@conv:
  1531.         ; sample is in conventional memory - deallocate
  1532.         push    es bx
  1533.     call    memFree LANG, [es:bx+dsmInstrument.sample]
  1534.         pop     bx es
  1535.         test    ax,ax
  1536.         jnz     @@err
  1537.  
  1538.  
  1539. @@dealloc:
  1540.     mov    [es:bx+dsmInstrument.inuse],0    ; instrument not in use
  1541.  
  1542.         xor     ax,ax                   ; success
  1543.         jmp     @@done
  1544.  
  1545. @@err:
  1546.         ERROR   ID_dsmRemInstrument
  1547.  
  1548. @@done:
  1549.     ret
  1550. ENDP
  1551.  
  1552.  
  1553.  
  1554.  
  1555.  
  1556. ;/***************************************************************************\
  1557. ;*
  1558. ;* Function:     int dsmSetUpdRate(ushort updRate);
  1559. ;*
  1560. ;* Description:  Set channel updating rate (depends on song tempo)
  1561. ;*
  1562. ;* Input:     ushort updRate      updating rate in 100*Hz
  1563. ;*
  1564. ;* Returns:      MIDAS error code
  1565. ;*
  1566. ;\***************************************************************************/
  1567.  
  1568. PROC    dsmSetUpdRate    FAR    updRate : word
  1569.  
  1570.     mov    ax,100
  1571.     mul    [dsmMixRate]        ; ax = amount of data between two
  1572.     div    [updRate]        ; updates
  1573.  
  1574.     test    [dsmMode],sd16bit
  1575.         jz      @@no16                  ; multiply amount by 2 if 16-bit
  1576.     shl    ax,1
  1577.  
  1578. @@no16: test    [dsmMode],sdStereo
  1579.         jz      @@nostereo              ; multiply amount by 2 if stereo
  1580.     shl    ax,1
  1581.  
  1582. @@nostereo:
  1583.     mov    [dsmUpdateMix],ax
  1584.     mov    [dsmMixLeft],ax
  1585.  
  1586.         xor     ax,ax                   ; always successful
  1587.  
  1588.     ret
  1589. ENDP
  1590.  
  1591.  
  1592.  
  1593.  
  1594.  
  1595. ;/***************************************************************************\
  1596. ;*
  1597. ;* Function:     int dsmPlay(int *callMP);
  1598. ;*
  1599. ;* Description:  Updates sound device registers or mixes data
  1600. ;*
  1601. ;* Returns:      MIDAS error code.
  1602. ;*               *callMP contains 1 if registers were updated or data mixed
  1603. ;*               so that new values can be set by, for example, calling the
  1604. ;*               music player.
  1605. ;*
  1606. ;\***************************************************************************/
  1607.  
  1608. PROC    dsmPlay         FAR     callMP : dword
  1609. LOCAL    mixBytes : word, mixCount : word
  1610. USES    si,di
  1611.  
  1612.     cld
  1613.  
  1614.         cmp     [dsmPaused],1           ; is playing paused?
  1615.         je      @@paused                ; if yes, skip mixing
  1616.  
  1617.     mov    ax,[dsmDMAPos]
  1618.  
  1619.     mov    bx,[dsmMixPos]        ; mixing position
  1620.     cmp    bx,ax            ; is dsmMixPos < dmaGetPos()?
  1621.     jae    @@1
  1622.  
  1623.     mov    cx,ax            ; cx = maximum amout to mix
  1624.     sub    cx,bx            ; = dmaGetPos() - dsmMixPos
  1625.     jmp    @@2
  1626.  
  1627. @@1:    mov    cx,[dsmBuffer.blength]    ; cx = maximum amount to mix
  1628.     sub    cx,bx            ; = (dsmBufferSize - dsmMixPos)
  1629.     add    cx,ax            ;   + dmaGetPos()
  1630.  
  1631. @@2:    sub    cx,16            ; keep 16 bytes of safety distance
  1632.                     ; between mixing pos and DMA pos
  1633.     cmp    cx,16
  1634.     jl    @@stopmix        ; skip if < 16 bytes space in buffer
  1635.  
  1636.     cmp    cx,[dsmMixLeft]     ; don't mix more data than there is
  1637.     jbe    @@3            ; to mix before the next update
  1638.     mov    cx,[dsmMixLeft]
  1639.  
  1640. @@3:    test    [dsmMode],sd16bit    ; 16-bit?
  1641.     jz    @@no16            ; if yes, mix only an integral number
  1642.     and    cx,not 1        ; of words
  1643.     test    [dsmMode],sdStereo    ; 16-bit stereo?
  1644.     jz    @@cok            ; if yes, mix only an integral number
  1645.     and    cx,not 2        ; of dwords
  1646.     jmp    @@cok
  1647.  
  1648. @@no16:
  1649.     test    [dsmMode],sdStereo    ; 8-bit stereo?
  1650.     jz    @@cok            ; if yes, mix only an integral number
  1651.     and    cx,not 1        ; of dwords
  1652.  
  1653. @@cok:
  1654.     mov    [mixBytes],cx
  1655.     mov    [mixCount],cx
  1656.     or    cx,cx
  1657.     jz    @@endmix
  1658.  
  1659.  
  1660.     test    [dsmMode],sd8bit
  1661.     jnz    @@8norm
  1662.     jmp    @@16norm
  1663.  
  1664.  
  1665. @@8norm:
  1666.     test    [dsmMode],sdStereo
  1667.     jz    @@8nmono
  1668.  
  1669. @@8nstereo:
  1670.     mov    ax,[mixCount]        ; number of bytes to be mixed
  1671.     shl    ax,1            ; number of bytes of temp buffer
  1672.     cmp    ax,[dsmTBufSize]    ; needed (16-bit!)
  1673.     jb    @@8ns1            ; don't mix more than there is space
  1674.     mov    ax,[dsmTBufSize]    ; for in the temp mixing buffer
  1675. @@8ns1:
  1676.     shr    ax,1            ; number of bytes to mix
  1677.     sub    [mixCount],ax
  1678.     shr    ax,1            ; actual amount to mix (stereo)
  1679.  
  1680.     call    dsmMixData LANG, [dsmTempBuffer], ax, \
  1681.             offset dsm_Mix8StereoNormal    ; mix the data
  1682.         test    ax,ax
  1683.         jnz     @@err
  1684.  
  1685.     cmp    [mixCount],0
  1686.     jnz    @@8nstereo
  1687.     jmp    @@endmix
  1688.  
  1689.  
  1690. @@8nmono:
  1691.     mov    si,[mixCount]        ; number of bytes to be mixed
  1692.     shl    si,1            ; number of bytes of temp buffer
  1693.     cmp    si,[dsmTBufSize]    ; needed (16-bit!)
  1694.     jb    @@8nm1            ; don't mix more than there is space
  1695.     mov    si,[dsmTBufSize]    ; for in the temp mixing buffer
  1696. @@8nm1:
  1697.     shr    si,1
  1698.  
  1699.     call    dsmMixData LANG, [dsmTempBuffer], si, \
  1700.             offset dsm_Mix8MonoNormal    ; mix the data
  1701.         test    ax,ax
  1702.         jnz     @@err
  1703.  
  1704.     sub    [mixCount],si
  1705.     jnz    @@8nmono
  1706.     jmp    @@endmix
  1707.  
  1708.  
  1709. @@16norm:
  1710.     test    [dsmMode],sdStereo
  1711.     jz    @@16nmono
  1712.  
  1713.     mov    ax,[mixCount]        ; 16-bit stereo - convert mixCount
  1714.     shr    ax,2            ; into number of dwords
  1715.     call    dsmMixData LANG, [dsmBuffer.bsegment] [dsmMixPos], ax, \
  1716.             offset dsm_Mix16StereoNormal
  1717.         test    ax,ax
  1718.         jnz     @@err
  1719.     jmp    @@endmix
  1720.  
  1721.  
  1722. @@16nmono:
  1723.     mov    ax,[mixCount]        ; convert mixCount into number of
  1724.     shr    ax,1            ; words
  1725.     call    dsmMixData LANG, [dsmBuffer.bsegment] [dsmMixPos], ax, \
  1726.             offset dsm_Mix16MonoNormal
  1727.         test    ax,ax
  1728.         jnz     @@err
  1729.     jmp    @@endmix
  1730.  
  1731.  
  1732. @@endmix:
  1733.     mov    ax,[mixBytes]        ; mixBytes bytes were mixed
  1734.  
  1735.     sub    [dsmMixLeft],ax     ; is the next update due?
  1736.     jz    @@update
  1737.  
  1738.     jmp    @@stopmix
  1739.  
  1740. @@update:
  1741.     mov    ax,[dsmUpdateMix]
  1742.     mov    [dsmMixLeft],ax     ; set bytes to mix before next update
  1743.  
  1744.         les     bx,[callMP]
  1745.         mov     [word es:bx],1          ; music-player should be called now
  1746.         xor     ax,ax                   ; success
  1747.         jmp     @@done
  1748.  
  1749. @@stopmix:
  1750. @@paused:
  1751.         les     bx,[callMP]
  1752.         mov     [word es:bx],0          ; do not call music player
  1753.  
  1754.         xor     ax,ax                   ; success
  1755.         jmp     @@done
  1756.  
  1757.  
  1758. @@err:
  1759.         ERROR   ID_dsmPlay
  1760.  
  1761. @@done:
  1762.     ret
  1763. ENDP
  1764.  
  1765.  
  1766.  
  1767.  
  1768.  
  1769. ;/***************************************************************************\
  1770. ;*
  1771. ;* Function:    int dsmMixData(uchar *mixBuffer, ushort mixLength,
  1772. ;*                void (near mixRoutine)(void));
  1773. ;*
  1774. ;* Description: Mixes data from all channels
  1775. ;*
  1776. ;* Input:    uchar *mixBuffer    pointer to mixing buffer
  1777. ;*        ushort mixLength    amount of data to be mixed
  1778. ;*        void (near mixRoutine)(void)    pointer to actual data mixing
  1779. ;*                    function, which must be in current
  1780. ;*                    code segment
  1781. ;*
  1782. ;* Returns:     MIDAS error code
  1783. ;*
  1784. ;* Destroys:    eax, ebx, ecx, edx, es, gs
  1785. ;*
  1786. ;* Note:    DSM internal use only, do not call from outside!
  1787. ;*
  1788. ;\***************************************************************************/
  1789.  
  1790. PROC    dsmMixData    FAR    mixBuffer : dword, mixLength : word, \
  1791.                 mixRoutine : word
  1792. USES    si,di
  1793. LOCAL    chan : word, mlen : word, incr : dword, mixPtr : dword, vol : byte, \
  1794.     smp : dword, panning : byte
  1795.  
  1796.     mov    [chan],0        ; channel number to be mixed
  1797.  
  1798. @@chnlp:
  1799.     mov    ax,[mixLength]        ; mlen = amount of data to be mixed
  1800.     mov    [mlen],ax        ; for the channel
  1801.     mov    eax,[mixBuffer]     ; mixPtr = position where data will
  1802.     mov    [mixPtr],eax        ; be mixed
  1803.  
  1804.         cmp     [dsmChOpen],0           ; are any channels open?
  1805.         je      @@cdone                 ; if not, simply clear the buffer
  1806.  
  1807. @@contmix:
  1808.     ChanPtr es, bx, [chan]        ; point es:bx to channel struct
  1809.     cmp    [es:bx+dsmChannel.hasData],0    ; data to be mixed?
  1810.     je    @@cdone
  1811.  
  1812.         mov     al,[es:bx+dsmChannel.panning]
  1813.     mov    [panning],al        ; save panning information
  1814.  
  1815.         cmp     [dsmMuted],1            ; is DSM muted?
  1816.         je      @@muted
  1817.     cmp    [es:bx+dsmChannel.muted],0    ; is channel muted?
  1818.     je    @@nom
  1819. @@muted:
  1820.     xor    al,al            ; if is, play at zero volume
  1821.     jmp    @@vok
  1822. @@nom:
  1823.     movzx    ax,[es:bx+dsmChannel.volume]
  1824.     mul    [dsmMasterVolume]    ; calculate actual playing volume
  1825.     shr    ax,6            ; (volume * masterVolume) / 64
  1826. @@vok:
  1827.     mov    [vol],al
  1828.  
  1829.     mov    ax,[es:bx+dsmChannel.inst]
  1830.         test    ax,ax                   ; no mixing if no instrument set on
  1831.     jz    @@cdone         ; channel
  1832.     dec    ax            ; instrument numbers start from 1
  1833.     InstPtr gs, si, ax        ; point gs:si to instrument struct
  1834.  
  1835.     cmp    [gs:si+dsmInstrument.inuse],0
  1836.     je    @@cdone         ; skip if no legal instrument
  1837.         cmp     [es:bx+dsmChannel.smpType],smp8bit
  1838.     jne    @@cdone         ; or sample not of supported type
  1839.  
  1840.         cmp     [es:bx+dsmChannel.smpPos],sdSmpEMS      ; is sample in EMS?
  1841.     jne    @@smpconv
  1842.  
  1843.         push    es bx                   ; map sample into conventional memory
  1844.         call    emsMap LANG, [es:bx+dsmChannel.sample], \
  1845.                 seg dsmSamplePtr offset dsmSamplePtr
  1846.         pop     bx es
  1847.         test    ax,ax
  1848.         jnz     @@err
  1849.  
  1850.         mov     eax,[dsmSamplePtr]      ; save sample pointer in conventional
  1851.         mov     [smp],eax               ; memory to smp
  1852.     jmp    @@smpok
  1853.  
  1854. @@smpconv:
  1855.         ; sample in conventional memory - point smp to sample data
  1856.         mov     eax,[es:bx+dsmChannel.sample]
  1857.     mov    [smp],eax
  1858.     jmp    @@smpok
  1859.  
  1860. @@smpok:
  1861.     push    bx
  1862.     mov    eax,[es:bx+dsmChannel.rate]    ; playing rate
  1863.     xor    edx,edx
  1864.     shld    edx,eax,16        ; eax = sample pos increment =
  1865.     shl    eax,16            ; rate / dsmMixRate
  1866.     movzx    ebx,[dsmMixRate]    ; (16.16 bit fixed point number)
  1867.     div    ebx
  1868.     mov    [incr],eax        ; store position increment
  1869.     pop    bx
  1870.  
  1871.         cmp     [es:bx+dsmChannel.looping],1    ; looping instrument?
  1872.     je    @@cloop
  1873.  
  1874.  
  1875.         ; non-looping sample:
  1876.  
  1877.     mov    dx,[es:bx+dsmChannel.pos]
  1878.     shl    edx,16            ; edx = playing position in channel
  1879.     mov    dx,[es:bx+dsmChannel.posl]    ; (16.16 fixed point)
  1880.         mov     ax,[es:bx+dsmChannel.slength]
  1881.     shl    eax,16            ; eax = sample length
  1882.     sub    eax,edx         ; eax = amount of data before sample
  1883.                     ; end
  1884.     xor    edx,edx         ; eax = number of destination bytes
  1885.     div    [incr]            ; before sample end
  1886.  
  1887.     movzx    ecx,[mixLength]     ; amount of data to be mixed
  1888.     cmp    ecx,eax         ; will sample end be reached
  1889.     jbe    @@cnl1            ; before the end of mixing?
  1890.     mov    ecx,eax         ; if so, don't mix past sample end
  1891.  
  1892. @@cnl1: sub    [mlen],cx        ; decrease amount of data to be mixed
  1893.         test    cx,cx                   ; if zero bytes do not mix, we are at
  1894.     jz    @@cnsend        ; end of sample
  1895.  
  1896.         push    es bx
  1897.  
  1898.     lgs    si,[smp]            ; es = sample segment
  1899.     add    si,[es:bx+dsmChannel.pos]    ; esi = sample mixing position
  1900.     shl    esi,16                ; from the beginning of the
  1901.     mov    si,[es:bx+dsmChannel.posl]    ; segment, 16.16 fixed point
  1902.  
  1903.     mov    al,[vol]        ; mixing volume
  1904.     les    di,[mixPtr]        ; mixing buffer
  1905.     mov    edx,[incr]        ; mixing position increment
  1906.     mov    ah,[byte chan]        ; channel number
  1907.     mov    bl,1            ; channel has data to be mixed
  1908.     mov    bh,[panning]        ; panning information
  1909.     call    [word mixRoutine]    ; mix the sound!
  1910.     mov    edx,esi         ; edx = new mixing position
  1911.     mov    [word mixPtr],di
  1912.  
  1913.         pop     bx es
  1914.  
  1915.     mov    [es:bx+dsmChannel.posl],dx    ; new position fraction
  1916.     shr    edx,16                ; substract sample start from
  1917.     sub    dx,[word smp]            ; whole part to get
  1918.     mov    [es:bx+dsmChannel.pos],dx    ; mixing position whole part
  1919.  
  1920.         cmp     dx,[es:bx+dsmChannel.slength]   ; past sample end?
  1921.     jae    @@cnsend
  1922.     jmp    @@cdone
  1923.  
  1924. @@cnsend:
  1925.         ; sample end has been reached
  1926.         cmp     [ALE],1                 ; is Amiga Loop Emulation active?
  1927.         je      @@nlale
  1928.  
  1929.         ; no Amiga Loop emulation - no data to be mixed:
  1930.         mov     [es:bx+dsmChannel.hasData],0
  1931.     jmp    @@cdone
  1932.  
  1933. @@nlale:
  1934.         ; Sample end was reached and Amiga Loop Emulation is active. If
  1935.         ; instrument has been changed, set new instrument values to channel
  1936.         ; structure and check if playing should be continued with new
  1937.         ; instrument. If instrument has not been changed, stop playing
  1938.         cmp     [es:bx+dsmChannel.instChanged],1
  1939.         je      @@alenewinst
  1940.         mov     [es:bx+dsmChannel.hasData],0
  1941.     jmp    @@cdone
  1942.  
  1943.  
  1944. @@cloop:    ; looping instrument
  1945.     mov    dx,[es:bx+dsmChannel.pos]
  1946.     shl    edx,16            ; edx = playing position in channel
  1947.     mov    dx,[es:bx+dsmChannel.posl]    ; (16.16 fixed point)
  1948.         mov     ax,[es:bx+dsmChannel.loopEnd]
  1949.     shl    eax,16            ; eax = sample loop end
  1950.     sub    eax,edx         ; eax = amount of data before sample
  1951.                     ; loop end
  1952.     xor    edx,edx         ; eax = number of destination bytes
  1953.     div    [incr]            ; before sample loop end
  1954.     or    edx,edx         ; if modulus is not zero, one more
  1955.     jz    @@cl2            ; byte must be mixed in order to
  1956.     inc    eax            ; actually reach loop end
  1957.  
  1958. @@cl2:
  1959.     movzx    ecx,[mlen]        ; amount of data to be mixed
  1960.     cmp    ecx,eax         ; will sample loop end be reached
  1961.     jbe    @@cl1            ; before the end of mixing?
  1962.     mov    ecx,eax         ; if so, don't mix past loop end
  1963.  
  1964. @@cl1:    sub    [mlen],cx        ; decrease amount of data to be mixed
  1965.     or    cx,cx            ; if zero bytes do mix, we are at
  1966.     jz    @@cnsend        ; end of sample loop
  1967.  
  1968.         push    es bx
  1969.  
  1970.     lgs    si,[smp]            ; es = sample segment
  1971.     add    si,[es:bx+dsmChannel.pos]    ; esi = sample mixing position
  1972.     shl    esi,16                ; from the beginning of the
  1973.     mov    si,[es:bx+dsmChannel.posl]    ; segment, 16.16 fixed point
  1974.  
  1975.     mov    al,[vol]        ; mixing volume
  1976.     les    di,[mixPtr]        ; mixing buffer
  1977.     mov    edx,[incr]        ; mixing position increment
  1978.     mov    ah,[byte chan]        ; channel number
  1979.     mov    bl,1            ; channel has data to be mixed
  1980.     mov    bh,[panning]        ; panning information
  1981.     call    [word mixRoutine]    ; mix the sound!
  1982.     mov    edx,esi         ; edx = new mixing position
  1983.     mov    [word mixPtr],di
  1984.  
  1985.         pop     bx es
  1986.  
  1987.     mov    [es:bx+dsmChannel.posl],dx    ; new position fraction
  1988.     shr    edx,16                ; substract sample start from
  1989.     sub    dx,[word smp]            ; whole part to get
  1990.     mov    [es:bx+dsmChannel.pos],dx    ; mixing position whole part
  1991.  
  1992.         mov     ax,[es:bx+dsmChannel.loopEnd]           ; have we reached
  1993.     cmp    [es:bx+dsmChannel.pos],ax        ; loop end?
  1994.     jb    @@clne
  1995.  
  1996.  
  1997.         ; loop end has been reached.
  1998.         cmp     [ALE],1                 ; is Amiga Loop Emulation active?
  1999.         je      @@lale
  2000.  
  2001.         ; Amiga Loop Emulation not active - just substract loop length from
  2002.         ; position to get to loop start
  2003. @@loopcurrent:
  2004.         mov     ax,[es:bx+dsmChannel.loopEnd]
  2005.         sub     ax,[es:bx+dsmChannel.loopStart]
  2006.         sub     [es:bx+dsmChannel.pos],ax
  2007.         jmp     @@clne
  2008.  
  2009. @@lale:
  2010.         ; Sample loop end has been reached and Amiga Loop Emulation is
  2011.         ; active. If instrument has been changed, set new instrument values
  2012.         ; to channel structure and check if playing should be continued
  2013.         ; with new instrument. If instrument has not been changed, just loop
  2014.         ; as usual
  2015.         cmp     [es:bx+dsmChannel.instChanged],1
  2016.         je      @@alenewinst
  2017.         jmp     @@loopcurrent
  2018.  
  2019. @@clne:
  2020.     cmp    [mlen],0        ; more data to be mixed?
  2021.     je    @@cdone         ; skip if not
  2022.     jmp    @@cloop
  2023.  
  2024.  
  2025. @@alenewinst:
  2026.         ; Sample loop end or sample end has been reached, Amiga Loop
  2027.         ; Emulation is active and instrument has been changed. Set new
  2028.         ; instrument values to channel structure:
  2029.         call    dsmUseInstrument
  2030.  
  2031.         ; if new instrument is not looping, playing should be stopped:
  2032.         cmp     [es:bx+dsmChannel.looping],1
  2033.         je      @@alelp
  2034.         mov     [es:bx+dsmChannel.hasData],0
  2035.         jmp     @@cdone
  2036.  
  2037. @@alelp:
  2038.         ; looping instrument - continue playing from new instrument loop
  2039.         ; start:
  2040.         mov     ax,[es:bx+dsmChannel.loopStart]
  2041.         mov     [es:bx+dsmChannel.pos],ax
  2042.         mov     [es:bx+dsmChannel.posl],0
  2043.  
  2044.         cmp     [mlen],0                ; more data to be mixed?
  2045.         jne     @@contmix               ; if yes, continue mixing
  2046.         jmp     @@cdone
  2047.  
  2048.  
  2049. @@cdone:
  2050.     mov    cx,[mlen]        ; Mixed enough? Even if sample has
  2051.     or    cx,cx            ; ended, the mixing routine must be
  2052.     jz    @@nomix         ; called to ensure that the buffer
  2053.                     ; is cleared properly, data moved to
  2054.                     ; the DMA buffer etc.
  2055.  
  2056.     les    di,[mixPtr]        ; mixing buffer
  2057.     mov    ah,[byte chan]        ; channel number
  2058.     xor    bl,bl            ; channel has no data to be mixed
  2059.     xor    bh,bh
  2060.     call    [word mixRoutine]    ; call the mixing routine
  2061.  
  2062. @@nomix:
  2063.     mov    ax,[chan]
  2064.     inc    ax            ; next channel
  2065.     cmp    ax,[dsmChOpen]        ; are there more channels?
  2066.     jae    @@chdn
  2067.     mov    [chan],ax
  2068.     jmp    @@chnlp
  2069.  
  2070. @@chdn:
  2071.         xor     ax,ax                   ; success
  2072.         jmp     @@done
  2073.  
  2074. @@err:
  2075.         ERROR   ID_dsmMixData
  2076.  
  2077. @@done:
  2078.     ret
  2079. ENDP
  2080.  
  2081.  
  2082.  
  2083.  
  2084. ; 8-bit mono normal mixing, add to temporary buffer
  2085. MACRO    _m8mna        num
  2086.     mov    bl,[gs:si]        ; take byte from source
  2087.     add    esi,edx         ; point to next sample byte
  2088.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2089.     adc    si,0            ; add the carry to mixing position
  2090.                     ; whole part
  2091.     add    [di+2*num],ax        ; add word into destination
  2092. ENDM
  2093.  
  2094. MixLoop m8mna, _m8mna, 32, 0, cx
  2095.  
  2096.  
  2097.  
  2098. ; 8-bit mono normal mixing, move to temporary buffer (first channel)
  2099. MACRO    _m8mnm        num
  2100.     mov    bl,[gs:si]        ; take byte from source
  2101.     add    esi,edx         ; point to next sample byte
  2102.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2103.     adc    si,0            ; add the carry to mixing position
  2104.                     ; whole part
  2105.     add    ax,8000h
  2106.     mov    [di+2*num],ax        ; move word byte into destination
  2107. ENDM
  2108.  
  2109. MixLoop m8mnm, _m8mnm, 32, 0, cx
  2110.  
  2111.  
  2112. ; 8-bit mono normal mixing, move data to DMA buffer (final channel)
  2113. MACRO    _m8mnf        num
  2114.     mov    bl,[gs:si]        ; take byte from source
  2115.     add    esi,edx         ; point to next sample byte
  2116.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2117.     adc    si,0            ; add the carry to mixing position
  2118.                     ; whole part
  2119.     add    ax,[di+2*num]        ; add to word the values from previous
  2120.                     ; channels
  2121.     mov    [es:bp+num],ah        ; store byte to DMA buffer
  2122. ENDM
  2123.  
  2124. MixLoop m8mnf, _m8mnf, 32, 16, cx
  2125.  
  2126.  
  2127.  
  2128. ;/***************************************************************************\
  2129. ;*
  2130. ;* Function:    dsm_Mix8MonoNormal
  2131. ;*
  2132. ;* Description: The actual normal-quality 8-bit mono mixing routine
  2133. ;*
  2134. ;* Input:    gs        sample data segment
  2135. ;*        esi        sample mixing position from the beginning of
  2136. ;*                the segment, in 16.16 fixed point format
  2137. ;*        edx        sample mixing position increment for each
  2138. ;*                destination byte, 16.16 fixed point format
  2139. ;*        di        pointer to (temporary) mixing buffer in
  2140. ;*                volume table segment
  2141. ;*        cx        number of bytes to mix
  2142. ;*        al        volume to be used
  2143. ;*        ah        current channel number
  2144. ;*        bl        1 if data to be mixed, 0 if not (even if there
  2145. ;*                is no data to be mixed, the mixing routine
  2146. ;*                must be called anyway - the buffer might not
  2147. ;*                be cleared etc.)
  2148. ;*
  2149. ;* Returns:    esi        new mixing position
  2150. ;*        di        new destination position
  2151. ;*
  2152. ;* Destroys:    ax, ebx, cx, edx, esi, di
  2153. ;*
  2154. ;\***************************************************************************/
  2155.  
  2156. PROC    dsm_Mix8MonoNormal    NEAR
  2157. LOCAL    chan : byte, destOffs : word, destLen : word
  2158.  
  2159.     mov    [destOffs],di        ; store destination offset
  2160.     mov    [destLen],cx        ; and mixing length
  2161.     mov    [chan],ah
  2162.     or    cx,cx            ; don't mix zero bytes
  2163.     jz    @@done
  2164.  
  2165.     or    bl,bl            ; is there data to be mixed?
  2166.     jnz    @@hasdata
  2167.  
  2168.     or    ah,ah            ; no data to be mixed - first channel?
  2169.     jnz    @@nodata
  2170.  
  2171.     mov    ax,8000h        ; first channel - clear buffer
  2172.     rep    stosw
  2173.     jmp    @@nodata
  2174.  
  2175.  
  2176. @@hasdata:
  2177.     add    al,VOLADD        ; convert volume rounding up
  2178.     shr    al,VOLSHIFT
  2179.     xor    ebx,ebx         ; bh contains volume, bl sample and
  2180.     mov    bh,al            ; upper word of ebx is zero
  2181.  
  2182.     rol    edx,16            ; reverse fractional and whole parts
  2183.     rol    esi,16            ; in mixing position and increment
  2184.  
  2185.     mov    al,[chan]
  2186.     inc    al            ; last channel to be mixed?
  2187.     cmp    al,[byte dsmChOpen]    ; if is, also move data to DMA buffer
  2188.     jae    @@final
  2189.  
  2190.     cmp    [chan],0        ; the first channel?
  2191.     jne    @@add
  2192.     mov    ax,offset m8mnm     ; yes, move to mixing buffer
  2193.     jmp    @@mix
  2194.  
  2195. @@add:    mov    ax,offset m8mna     ; not the first channel - add to buf
  2196.  
  2197. @@mix:
  2198.     push    ds
  2199.     mov    ds,[dsmVolTableSeg]    ; point ds to volume table
  2200.  
  2201.     push    bp
  2202.     push    ax
  2203.  
  2204.     mov    ax,cx            ; ax = number of bytes to mix
  2205.     and    ax,15            ; in the first loop
  2206.     shl    ax,1
  2207.     mov    bp,32            ; bp = jump table offset
  2208.     sub    bp,ax
  2209.  
  2210.     sub    di,bp            ; undo di incrementing in loop
  2211.  
  2212.     shr    cx,4            ; cx = number of loops to mix
  2213.     inc    cx
  2214.  
  2215.     pop    ax
  2216.     add    bp,ax
  2217.     call    [word cs:bp]
  2218.  
  2219.     pop    bp
  2220.     pop    ds
  2221.  
  2222.     rol    esi,16            ; destore mixing position to its
  2223.     jmp    @@done            ; original form
  2224.  
  2225.  
  2226.  
  2227. @@final:    ; final channel - move data into DMA buffer
  2228.  
  2229. @@flp1:
  2230.     mov    ax,[dsmBuffer.blength]    ; ax = number of bytes before
  2231.     sub    ax,[dsmMixPos]        ; buffer end
  2232.  
  2233.     mov    cx,[destLen]
  2234.     cmp    cx,ax            ; do not copy data over the buffer
  2235.     jbe    @@fi1            ; end
  2236.     mov    cx,ax
  2237.  
  2238. @@fi1:    sub    [destLen],cx        ; decrease number of bytes left
  2239.  
  2240.     push    bp
  2241.  
  2242.     mov    ax,cx            ; ax = number of bytes to mix
  2243.     and    ax,15            ; in the first loop
  2244.     shl    ax,1
  2245.     mov    bp,32            ; bp = jump table offset
  2246.     sub    bp,ax
  2247.  
  2248.     mov    ax,[word m8mnf+bp]    ; ax = call destination
  2249.  
  2250.     sub    di,bp            ; undo di incrementing in loop
  2251.     shr    bp,1
  2252.     neg    bp            ; bp = DMA buffer position - incr
  2253.     add    bp,[dsmMixPos]
  2254.  
  2255.     shr    cx,4            ; cx = number of loops to mix
  2256.     inc    cx
  2257.  
  2258.     push    ds
  2259.     mov    es,[dsmBuffer.bsegment] ; point es to DMA buffer
  2260.     mov    ds,[dsmVolTableSeg]    ; point ds to voltbl & mixing buffer
  2261.  
  2262.     call    ax
  2263.  
  2264.     pop    ds
  2265.     mov    [dsmMixPos],bp
  2266.     pop    bp
  2267.  
  2268.     mov    ax,[dsmMixPos]
  2269.     cmp    ax,[dsmBuffer.blength]    ; did we reach DMA buffer end?
  2270.     jb    @@fi2
  2271.     xor    ax,ax            ; if so, jump to the beginning
  2272. @@fi2:
  2273.     mov    [dsmMixPos],ax
  2274.     cmp    [destLen],0        ; any more data left to move?
  2275.     jne    @@flp1
  2276.  
  2277.     rol    esi,16            ; restore mixing position into
  2278.                     ; its original form
  2279.     jmp    @@done
  2280.  
  2281.  
  2282. @@nodata:    ; no data to be mixed on this channel
  2283.     mov    al,[chan]
  2284.     inc    al            ; is this the last channel? If is,
  2285.     cmp    al,[byte dsmChOpen]    ; data must be moved to DMA buffer
  2286.         jb      @@done
  2287.  
  2288.  
  2289.     push    es di esi        ; save registers that contain
  2290.                     ; meaningful return values
  2291.  
  2292.     mov    di,[destOffs]        ; es:di points to temporary buffer
  2293.     mov    si,[dsmMixPos]        ; point si to mixing position
  2294.                     ; (ds is set later)
  2295.  
  2296. @@mvlp:
  2297.     mov    bx,[dsmBuffer.blength]    ; bx = number of bytes before
  2298.     sub    bx,si            ; buffer end
  2299.  
  2300.     mov    cx,[destLen]
  2301.     cmp    cx,bx            ; do not copy data over the buffer
  2302.     jbe    @@mv1            ; end
  2303.     mov    cx,bx
  2304.  
  2305. @@mv1:    sub    [destLen],cx        ; decrease number of bytes left
  2306.  
  2307.     push    ds
  2308.     mov    ds,[dsmBuffer.bsegment] ; point ds to mixing buffer
  2309.  
  2310. @@l1:    mov    al,[es:di+1]        ; take MSB of word from temp buffer
  2311.     add    di,2            ; next word in temp buffer
  2312.     mov    [ds:si],al        ; and move it to DMA buffer
  2313.     inc    si            ; next byte in DMA buffer
  2314.     loop    @@l1
  2315.  
  2316.     pop    ds
  2317.  
  2318.     cmp    si,[dsmBuffer.blength]    ; did we reach DMA buffer end?
  2319.     jb    @@mv2
  2320.     xor    si,si            ; if so, jump to the beginning
  2321. @@mv2:
  2322.     cmp    [destLen],0        ; any more data left to move?
  2323.     jne    @@mvlp
  2324.  
  2325.     mov    [dsmMixPos],si        ; store new mixing position
  2326.  
  2327.     pop    esi di es        ; restore registers with return values
  2328.  
  2329.  
  2330. @@done:
  2331.     ret
  2332. ENDP
  2333.  
  2334.  
  2335.  
  2336.  
  2337.  
  2338. ; 8-bit stereo normal mixing - middle, add to temporary buffer
  2339. MACRO    _m8snma        num
  2340.     mov    bl,[gs:si]        ; take byte from source
  2341.     add    esi,edx         ; point to next sample byte
  2342.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2343.     adc    si,0            ; add the carry to mixing position
  2344.                     ; whole part
  2345.     add    [di+4*num],ax        ; add word into dest left channel
  2346.     add    [di+4*num+2],ax     ; add word into dest right channel
  2347. ENDM
  2348.  
  2349. MixLoop m8snma, _m8snma, 64, 0, [cs:_mixCount]
  2350.  
  2351.  
  2352.  
  2353. ; 8-bit stereo normal mixing - middle, move to DMA buffer (final channel)
  2354. MACRO    _m8snmf        num
  2355.     mov    bl,[gs:si]        ; take byte from source
  2356.     add    esi,edx         ; point to next sample byte
  2357.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2358.     adc    si,0            ; add the carry to mixing position
  2359.                     ; whole part
  2360.     mov    cx,ax            ; cx = ax = sample word
  2361.     add    ax,[di+4*num]
  2362.     mov    al,ah            ; al = left channel DMA buffer data
  2363.     add    cx,[di+4*num+2]
  2364.     mov    ah,ch            ; ah = right channel DMA buffer data
  2365.     mov    [es:bp+2*num],ax    ; store word to DMA buffer
  2366. ENDM
  2367.  
  2368. MixLoop m8snmf, _m8snmf, 64, 32, [cs:_mixCount]
  2369.  
  2370.  
  2371.  
  2372. ; 8-bit stereo normal mixing - surround, add to temporary buffer
  2373. MACRO    _m8snsa     num
  2374.     mov    bl,[gs:si]        ; take byte from source
  2375.     add    esi,edx         ; point to next sample byte
  2376.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2377.     adc    si,0            ; add the carry to mixing position
  2378.                     ; whole part
  2379.     add    [di+4*num],ax        ; add word into dest left channel
  2380.     sub    [di+4*num+2],ax     ; add with 180 degrees phase shift
  2381. ENDM
  2382.  
  2383. MixLoop m8snsa, _m8snsa, 64, 0, [cs:_mixCount]
  2384.  
  2385.  
  2386.  
  2387. ; 8-bit stereo normal mixing - surround, move to DMA buffer (final)
  2388. MACRO    _m8snsf     num
  2389.     mov    bl,[gs:si]        ; take byte from source
  2390.     add    esi,edx         ; point to next sample byte
  2391.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2392.     adc    si,0            ; add the carry to mixing position
  2393.                     ; whole part
  2394.     mov    cx,ax            ; cx = ax = sample word
  2395.     add    ax,[di+4*num]
  2396.     mov    al,ah            ; al = left channel DMA data
  2397.     neg    cx            ; phase shift right chan 180 degrees
  2398.     add    cx,[di+4*num+2]
  2399.     mov    ah,ch            ; ah = right channel DMA data
  2400.     mov    [es:bp+2*num],ax    ; store word into DMA buffer
  2401. ENDM
  2402.  
  2403. MixLoop m8snsf, _m8snsf, 64, 32, [cs:_mixCount]
  2404.  
  2405.  
  2406.  
  2407. ; 8-bit stereo normal mixing - left, add to temporary buffer
  2408. MACRO    _m8snla        num
  2409.     mov    bl,[gs:si]        ; take byte from source
  2410.     add    esi,edx         ; point to next sample byte
  2411.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2412.     adc    si,0            ; add the carry to mixing position
  2413.                     ; whole part
  2414.     add    [di+4*num],ax        ; add word into dest left channel
  2415. ENDM
  2416.  
  2417. MixLoop m8snla, _m8snla, 64, 0, [cs:_mixCount]
  2418.  
  2419.  
  2420.  
  2421. ; 8-bit stereo normal mixing - left, move to DMA buffer (final channel)
  2422. MACRO    _m8snlf        num
  2423.     mov    bl,[gs:si]        ; take byte from source
  2424.     add    esi,edx         ; point to next sample byte
  2425.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2426.     adc    si,0            ; add the carry to mixing position
  2427.                     ; whole part
  2428.     add    ax,[di+4*num]
  2429.     mov    al,ah            ; al = left channel DMA data
  2430.     mov    ah,[di+4*num+3]     ; ah = right channel DMA data
  2431.     mov    [es:bp+2*num],ax    ; store word into DMA buffer
  2432. ENDM
  2433.  
  2434. MixLoop m8snlf, _m8snlf, 64, 32, [cs:_mixCount]
  2435.  
  2436.  
  2437.  
  2438. ; 8-bit stereo normal mixing - right, add to temporary buffer
  2439. MACRO    _m8snra     num
  2440.     mov    bl,[gs:si]        ; take byte from source
  2441.     add    esi,edx         ; point to next sample byte
  2442.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2443.     adc    si,0            ; add the carry to mixing position
  2444.                     ; whole part
  2445.     add    [di+4*num+2],ax     ; add word into dest right channel
  2446. ENDM
  2447.  
  2448. MixLoop m8snra, _m8snra, 64, 0, [cs:_mixCount]
  2449.  
  2450.  
  2451.  
  2452. ; 8-bit stereo normal mixing - right, move to DMA buffer (final channel)
  2453. MACRO    _m8snrf     num
  2454.     mov    bl,[gs:si]        ; take byte from source
  2455.     add    esi,edx         ; point to next sample byte
  2456.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2457.     adc    si,0            ; add the carry to mixing position
  2458.                     ; whole part
  2459.     add    ax,[di+4*num+2]     ; ah = right channel DMA data
  2460.     mov    al,[di+4*num+1]     ; al = left channel DMA data
  2461.     mov    [es:bp+2*num],ax    ; store word into DMA buffer
  2462. ENDM
  2463.  
  2464. MixLoop m8snrf, _m8snrf, 64, 32, [cs:_mixCount]
  2465.  
  2466.  
  2467.  
  2468. ; 8-bit stereo normal mixing - smooth panning, add to buffer
  2469. MACRO    _m8snpa     num
  2470.     mov    bl,[gs:si]        ; take byte from source
  2471.     add    esi,edx         ; point to next sample byte
  2472.     mov    ax,[ebx+ebx]        ; take left channel value from vol tbl
  2473.     adc    si,0            ; add carry to mixing pos whole part
  2474.     add    [di+4*num],ax        ; add word to destination left channel
  2475.     mov    cl,bl
  2476.     mov    ax,[ecx+ecx]        ; take right ch value from volume tbl
  2477.     add    [di+4*num+2],ax     ; add word to dest right channel
  2478. ENDM
  2479.  
  2480. MixLoop m8snpa, _m8snpa, 64, 0, [cs:_mixCount]
  2481.  
  2482.  
  2483.  
  2484. ; 8-bit stereo normal mixing - smooth panning, move to DMA buffer (final ch.)
  2485. MACRO    _m8snpf     num
  2486.     mov    bl,[gs:si]        ; take byte from source
  2487.     add    esi,edx         ; point to next sample byte
  2488.     mov    ax,[ebx+ebx]        ; take left channel value from vol tbl
  2489.     adc    si,0            ; add carry to mixing pos whole part
  2490.  
  2491.     mov    cl,bl
  2492.     mov    ax,[ebx+ebx]
  2493.     add    ax,[di+4*num]
  2494.     mov    bl,ah            ; bl = left channel DMA data
  2495.  
  2496.     mov    ax,[ecx+ecx]
  2497.     add    ax,[di+4*num+2]     ; ah = right channel DMA data
  2498.     mov    al,bl
  2499.     mov    [es:bp+2*num],ax    ; store word into DMA buffer
  2500. ENDM
  2501.  
  2502. MixLoop m8snpf, _m8snpf, 64, 32, [cs:_mixCount]
  2503.  
  2504.  
  2505.  
  2506. mix8sna     DW    offset m8snma        ; middle, add
  2507.         DW    offset m8snsa        ; surround, add
  2508.         DW    offset m8snla        ; left, add
  2509.         DW    offset m8snra        ; right, add
  2510.         DW    offset m8snpa        ; panning, add
  2511. mix8snf     DW    offset m8snmf        ; middle, add
  2512.         DW    offset m8snsf        ; surround, add
  2513.         DW    offset m8snlf        ; left, add
  2514.         DW    offset m8snrf        ; right, add
  2515.         DW    offset m8snpf        ; panning, add
  2516.  
  2517.  
  2518. ;/***************************************************************************\
  2519. ;*
  2520. ;* Function:    dsm_Mix8StereoNormal
  2521. ;*
  2522. ;* Description: The actual normal-quality 8-bit stereo mixing routine
  2523. ;*
  2524. ;* Input:    gs        sample data segment
  2525. ;*        esi        sample mixing position from the beginning of
  2526. ;*                the segment, in 16.16 fixed point format
  2527. ;*        edx        sample mixing position increment for each
  2528. ;*                destination byte, 16.16 fixed point format
  2529. ;*        di        pointer to (temporary) mixing buffer in
  2530. ;*                volume table segment
  2531. ;*        cx        number of bytes to mix
  2532. ;*        al        volume to be used
  2533. ;*        ah        current channel number
  2534. ;*        bl        1 if data to be mixed, 0 if not (even if there
  2535. ;*                is no data to be mixed, the mixing routine
  2536. ;*                must be called anyway - the buffer might not
  2537. ;*                be cleared etc.)
  2538. ;*        bh        panning information
  2539. ;*
  2540. ;* Returns:    esi        new mixing position
  2541. ;*        di        new destination position
  2542. ;*
  2543. ;* Destroys:    ax, ebx, cx, edx, esi, di
  2544. ;*
  2545. ;\***************************************************************************/
  2546.  
  2547.  
  2548. PROC    dsm_Mix8StereoNormal    NEAR
  2549. LOCAL    chan : byte,  destOffs : word, destLen : word, mixlp : word, \
  2550.     panning : byte, volume : byte, lastChan : byte
  2551.  
  2552.     mov    [destOffs],di        ; store destination offset
  2553.     mov    [destLen],cx        ; and mixing length
  2554.     mov    [chan],ah        ; store channel number
  2555.     mov    [panning],bh        ; store panning information
  2556.     add    al,VOLADD        ; convert volume rounding up
  2557.     shr    al,VOLSHIFT
  2558.     mov    [volume],al        ; store volume
  2559.     or    cx,cx            ; don't mix zero bytes
  2560.     jz    @@done
  2561.  
  2562.         test    ah,ah                   ; first channel?
  2563.     jnz    @@notfirst
  2564.  
  2565.     mov    ax,8000h
  2566.     shl    cx,1            ; first channel - clear temp. buffer
  2567.     rep    stosw
  2568.     mov    di,[destOffs]
  2569.     mov    cx,[destLen]
  2570.  
  2571. @@notfirst:
  2572.         mov     al,[chan]
  2573.         inc     al
  2574.         cmp     al,[byte dsmChOpen]     ; the last channel to be mixed?
  2575.         jae     @@lchan
  2576.  
  2577.         mov     [lastChan],0            ; no
  2578.     jmp    @@nlc
  2579.  
  2580. @@lchan:
  2581.     mov    [lastChan],1        ; yes
  2582.  
  2583. @@nlc:
  2584.     or    bl,bl            ; is there data to be mixed?
  2585.     jz    @@nodata
  2586.  
  2587.     push    es
  2588.  
  2589.     xor    ebx,ebx         ; bh contains volume, bl sample and
  2590.                     ; upper word of ebx is zero
  2591.  
  2592.     rol    edx,16            ; reverse fractional and whole parts
  2593.     rol    esi,16            ; in mixing position and increment
  2594.  
  2595.     mov    es,[dsmBuffer.bsegment] ; point es to DMA buffer
  2596.  
  2597.  
  2598. @@buflp:
  2599.     cmp    [lastChan],0        ; last channel to be mixed?
  2600.     je    @@nlast         ; if not, do not check if there is
  2601.                     ; enough space in DMA buffer - data
  2602.                     ; will not end up there anyway
  2603.  
  2604.     mov    ax,[dsmBuffer.blength]    ; ax = number of bytes of space before
  2605.     sub    ax,[dsmMixPos]        ; buffer end
  2606.     shr    ax,1            ; number of words (stereo)
  2607.     cmp    cx,ax            ; enough space in buffer?
  2608.     jbe    @@cxok
  2609.     mov    cx,ax            ; if not, don't mix past buffer end
  2610. @@cxok:
  2611.     mov    ax,[dsmMixPos]
  2612.     mov    [_bpvalue],ax        ; bp points to DMA buffer position
  2613.  
  2614.     mov    ax,offset mix8snf    ; last channel - move data to DMA
  2615.                     ; buffer
  2616.  
  2617.     jmp    @@mixok
  2618.  
  2619. @@nlast:
  2620.     mov    ax,offset mix8sna    ; not the last channel - add data to
  2621.                     ; temporary buffer
  2622.  
  2623. @@mixok:
  2624.     sub    [destLen],cx        ; decrease amount of data left
  2625.  
  2626. @@mix:
  2627.     mov    [_mixCount],cx
  2628.  
  2629.     cmp    [panning],panMiddle
  2630.     je    @@middle
  2631.     cmp    [panning],panSurround
  2632.     je    @@surround
  2633.         cmp     [panning],panLeft and 0FFh
  2634.     je    @@left
  2635.     cmp    [panning],panRight
  2636.     je    @@right
  2637.     jmp    @@smoothp        ; smooth panning
  2638.  
  2639.  
  2640. @@middle:    ; use middle mixing routine (the first one)
  2641.     mov    bh,[volume]        ; divide volume with two - sound is
  2642.     shr    bh,1            ; played from both left and right
  2643.     jmp    @@panok
  2644.  
  2645. @@surround:
  2646.     add    ax,2            ; use surround mixing routine
  2647.     mov    bh,[volume]        ; divide volume with two - sound is
  2648.     shr    bh,1            ; played from both left and right
  2649.     jmp    @@panok
  2650.  
  2651.  
  2652. @@left: add    ax,4            ; use left mixing routine
  2653.     mov    bh,[volume]        ; don't divide volume
  2654.     jmp    @@panok
  2655.  
  2656. @@right:
  2657.     add    ax,6            ; use right mixing routine
  2658.     mov    bh,[volume]        ; don't divide volume
  2659.     jmp    @@panok
  2660.  
  2661. @@smoothp:    ; smooth panning
  2662.     add    ax,8            ; use smooth panning mixing routine
  2663.     push    ax
  2664.  
  2665.     xor    ecx,ecx
  2666.  
  2667.     mov    al,[panning]
  2668.     add    al,64
  2669.     mul    [volume]
  2670.     shr    ax,7
  2671.     mov    ch,al            ; ch = right channel volume
  2672.     mov    bh,[volume]
  2673.     sub    bh,ch            ; bh = left channel volume
  2674.  
  2675.     pop    ax
  2676.  
  2677. @@panok:
  2678.     push    bp
  2679.     push    ds
  2680.  
  2681.     mov    ds,[dsmVolTableSeg]    ; point ds to volume table
  2682.  
  2683.     mov    bp,ax
  2684.     mov    ax,[cs:bp]        ; point ax to mixing routine jump tbl
  2685.     push    ax
  2686.  
  2687.     mov    ax,[_mixCount]        ; ax = number of words to mix
  2688.     and    ax,15            ; in the first loop
  2689.     shl    ax,1
  2690.     mov    bp,32            ; bp = jump table offset
  2691.     sub    bp,ax
  2692.  
  2693.     shl    bp,1
  2694.     sub    di,bp            ; undo di incrementing in loop
  2695.     shr    bp,1
  2696.     sub    [_bpvalue],bp        ; undo bp incrementing in loop
  2697.  
  2698.     shr    [_mixCount],4        ; _mixCount = number of loops to mix
  2699.     inc    [_mixCount]
  2700.  
  2701.     pop    ax
  2702.     add    bp,ax
  2703.     mov    ax,[cs:bp]
  2704.     mov    bp,[_bpvalue]
  2705.     call    ax            ; call mixing routine
  2706.  
  2707.     pop    ds
  2708.     mov    [_bpvalue],bp
  2709.     pop    bp
  2710.  
  2711.  
  2712.     cmp    [lastChan],0        ; is this the last channel?
  2713.     je    @@mixdone        ; if not, we are finished
  2714.  
  2715.     mov    ax,[_bpvalue]        ; store new mixing position
  2716.     mov    [dsmMixPos],ax
  2717.  
  2718.     mov    ax,[dsmMixPos]
  2719.     cmp    ax,[dsmBuffer.blength]    ; are we at buffer end?
  2720.     jb    @@nowrap
  2721.     mov    [dsmMixPos],0        ; move to buffer beginning
  2722. @@nowrap:
  2723.     cmp    [destLen],0        ; still data to mix?
  2724.     je    @@mixdone
  2725.  
  2726.     mov    cx,[destLen]        ; mix the rest
  2727.     jmp    @@buflp
  2728.  
  2729.  
  2730. @@mixdone:
  2731.     rol    esi,16            ; restore mixing position into
  2732.                     ; its original form
  2733.     pop    es
  2734.     jmp    @@done
  2735.  
  2736.  
  2737. @@nodata:    ; no data to be mixed on this channel
  2738.  
  2739.     cmp    [lastChan],0        ; is this the last channel?
  2740.     je    @@done            ; if not, there is no need to do
  2741.                     ; anything
  2742.  
  2743.     ; no data on the final channel - just move the data to DMA buffer
  2744.  
  2745.     push    es esi            ; save registers that contain
  2746.                     ; meaningful return values
  2747.  
  2748.     mov    si,[destOffs]        ; point si to temporary buffer pos
  2749.     mov    di,[dsmMixPos]        ; point es:di to mixing buffer pos
  2750.     mov    es,[dsmBuffer.bsegment]
  2751.  
  2752.  
  2753. @@mvlp:
  2754.     mov    bx,[dsmBuffer.blength]    ; bx = number of bytes before
  2755.     sub    bx,di            ; buffer end
  2756.     shr    bx,1            ; number of words (stereo)
  2757.  
  2758.     mov    cx,[destLen]
  2759.     cmp    cx,bx            ; do not copy data over the buffer
  2760.     jbe    @@mv1            ; end
  2761.     mov    cx,bx
  2762.  
  2763. @@mv1:    sub    [destLen],cx        ; decrease number of bytes left
  2764.  
  2765.     push    ds
  2766.     mov    ds,[dsmVolTableSeg]    ; temporary buffer is in volume table
  2767.                     ; segment
  2768.  
  2769. @@l1:    mov    al,[si+1]        ; al = DMA data for left channel
  2770.     mov    ah,[si+3]        ; ah = DMA data for right channel
  2771.     add    si,4
  2772.     mov    [es:di],ax        ; move word to DMA buffer
  2773.     add    di,2            ; next word in DMA buffer
  2774.     loop    @@l1
  2775.  
  2776.     pop    ds
  2777.  
  2778.     cmp    di,[dsmBuffer.blength]    ; did we reach DMA buffer end?
  2779.     jb    @@mv2
  2780.     xor    di,di            ; if so, jump to the beginning
  2781. @@mv2:
  2782.     cmp    [destLen],0        ; any more data left to move?
  2783.     jne    @@mvlp
  2784.  
  2785.     mov    [dsmMixPos],di        ; store new mixing position
  2786.  
  2787.     mov    di,si            ; new temp. buffer position is
  2788.                     ; returned in di
  2789.  
  2790.     pop    esi es            ; restore registers with return values
  2791.  
  2792. @@done:
  2793.     ret
  2794. ENDP
  2795.  
  2796.  
  2797.  
  2798.  
  2799.  
  2800.  
  2801.  
  2802. ; 16-bit mono normal mixing - add to buffer
  2803. MACRO    _m16mna     num
  2804.     mov    bl,[gs:si]        ; take byte from source
  2805.     add    esi,edx         ; point to next sample byte
  2806.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2807.     adc    si,0            ; add the carry to mixing position
  2808.                     ; whole part
  2809.     add    [es:di+2*num],ax    ; add byte into destination
  2810. ENDM
  2811.  
  2812. MixLoop m16mna, _m16mna, 32, 0, cx
  2813.  
  2814.  
  2815.  
  2816. ; 16-bit mono normal mixing - move to buffer (first channel)
  2817. MACRO    _m16mnm     num
  2818.     mov    bl,[gs:si]        ; take byte from source
  2819.     add    esi,edx         ; point to next sample byte
  2820.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2821.     adc    si,0            ; add the carry to mixing position
  2822.                     ; whole part
  2823.     mov    [es:di+2*num],ax    ; add byte into destination
  2824. ENDM
  2825.  
  2826. MixLoop m16mnm, _m16mnm, 32, 0, cx
  2827.  
  2828.  
  2829.  
  2830. ;/***************************************************************************\
  2831. ;*
  2832. ;* Function:    dsm_Mix16MonoNormal
  2833. ;*
  2834. ;* Description: The actual normal-quality 16-bit mono mixing routine
  2835. ;*
  2836. ;* Input:    gs        sample data segment
  2837. ;*        esi        sample mixing position from the beginning of
  2838. ;*                the segment, in 16.16 fixed point format
  2839. ;*        edx        sample mixing position increment for each
  2840. ;*                destination byte, 16.16 fixed point format
  2841. ;*        es:di        pointer to mixing buffer (assumed to be in
  2842. ;*                dsmBuffer)
  2843. ;*        cx        number of bytes to mix
  2844. ;*        al        volume to be used
  2845. ;*        ah        current channel number
  2846. ;*        bl        1 if data to be mixed, 0 if not (even if there
  2847. ;*                is no data to be mixed, the mixing routine
  2848. ;*                must be called anyway - the buffer might not
  2849. ;*                be cleared etc.)
  2850. ;*
  2851. ;* Returns:    esi        new mixing position
  2852. ;*        di        new destination position
  2853. ;*
  2854. ;* Destroys:    ax, ebx, cx, edx, esi, di
  2855. ;*
  2856. ;\***************************************************************************/
  2857.  
  2858. PROC    dsm_Mix16MonoNormal     NEAR
  2859. LOCAL    chan : byte,  destOffs : word, destLen : word, mixlp : word
  2860.  
  2861.     mov    [destOffs],di        ; store destination offset
  2862.     mov    [destLen],cx        ; and mixing length
  2863.     mov    [chan],ah        ; store channel number
  2864.     or    cx,cx            ; don't mix zero bytes
  2865.     jz    @@done
  2866.  
  2867.     or    bl,bl            ; is there data to be mixed?
  2868.     jnz    @@hasdata
  2869.  
  2870.     or    ah,ah            ; no data to be mixed - first channel?
  2871.     jz    @@first
  2872.  
  2873.     ; not the first channel - just update di as if data was mixed
  2874.  
  2875.     shl    cx,1            ; cx = number of bytes
  2876.     add    di,cx            ; di = new mixing position
  2877.     cmp    di,[dsmBuffer.blength]    ; past buffer end?
  2878.     jb    @@1
  2879.     sub    di,[dsmBuffer.blength]
  2880. @@1:    jmp    @@nodata
  2881.  
  2882. @@first:
  2883.     ; this is the first channel and must therefore be cleared even if
  2884.     ; there is no data to be mixed
  2885.  
  2886.     mov    bx,[dsmBuffer.blength]    ; bx = number of bytes before buffer
  2887.     sub    bx,di            ; end
  2888.     shr    bx,1            ; number of words
  2889.     cmp    bx,cx            ; if all data fits to the buffer,
  2890.     jae    @@clrok         ; just clear it.
  2891.  
  2892.     mov    cx,bx            ; clear buffer to its end
  2893.     xor    ax,ax
  2894.     rep    stosw
  2895.  
  2896.     xor    di,di            ; jump to buffer beginning
  2897.     mov    cx,[destLen]        ; and clear required amount of bytes
  2898.     sub    cx,bx            ; from the buffer beginning
  2899.  
  2900. @@clrok:
  2901.     xor    ax,ax
  2902.     rep    stosw            ; clear the rest of buffer
  2903.     jmp    @@nodata
  2904.  
  2905.  
  2906.  
  2907. @@hasdata:
  2908.     add    al,VOLADD        ; convert volume rounding up
  2909.     shr    al,VOLSHIFT
  2910.     xor    ebx,ebx         ; bh contains volume, bl sample and
  2911.     mov    bh,al            ; upper word of ebx is zero
  2912.  
  2913.     rol    edx,16            ; reverse fractional and whole parts
  2914.     rol    esi,16            ; in mixing position and increment
  2915.  
  2916.  
  2917. @@buflp:
  2918.     mov    ax,[dsmBuffer.blength]    ; ax = number of bytes of space before
  2919.     sub    ax,di            ; buffer end
  2920.     shr    ax,1            ; number of words
  2921.     cmp    cx,ax            ; enough space in buffer?
  2922.     jbe    @@mixok
  2923.     mov    cx,ax            ; if not, don't mix past buffer end
  2924.  
  2925. @@mixok:
  2926.     sub    [destLen],cx        ; decrease number of words left
  2927.  
  2928.     cmp    [chan],0        ; first channel?
  2929.     je    @@move
  2930.     mov    ax,offset m16mna    ; no, add data to buffer
  2931.     jmp    @@mix
  2932.  
  2933. @@move: mov    ax,offset m16mnm    ; yes, move data to buffer
  2934.  
  2935. @@mix:
  2936.     push    ds
  2937.  
  2938.     mov    ds,[dsmVolTableSeg]    ; point ds to volume table
  2939.  
  2940.     push    bp
  2941.     push    ax
  2942.  
  2943.     mov    ax,cx            ; ax = number of words to mix
  2944.     and    ax,15            ; in the first loop
  2945.     shl    ax,1
  2946.     mov    bp,32            ; bp = jump table offset
  2947.     sub    bp,ax
  2948.  
  2949.     sub    di,bp            ; undo di incrementing in loop
  2950.  
  2951.     shr    cx,4            ; cx = number of loops to mix
  2952.     inc    cx
  2953.  
  2954.     pop    ax
  2955.     add    bp,ax
  2956.     call    [word cs:bp]        ; call mixing routine
  2957.  
  2958.     pop    bp
  2959.     pop    ds
  2960.  
  2961.     cmp    [destLen],0        ; still data to mix?
  2962.     je    @@mixdone
  2963.  
  2964.     ; there is still data to mix - apparently we are at the buffer end
  2965.     ; and must continue from the beginning
  2966.  
  2967.     xor    di,di            ; move to buffer beginning
  2968.     mov    cx,[destLen]        ; mix the rest
  2969.     jmp    @@buflp
  2970.  
  2971. @@mixdone:
  2972.     rol    esi,16            ; restore mixing position into
  2973.                     ; its original form
  2974.     jmp    @@done
  2975.  
  2976.  
  2977. @@nodata:    ; no data to be mixed on this channel
  2978.  
  2979. @@done:
  2980.     mov    al,[chan]
  2981.     inc    al            ; last channel to be mixed?
  2982.     cmp    al,[byte dsmChOpen]
  2983.     jb    @@nofinal
  2984.  
  2985.     mov    [dsmMixPos],di        ; if is, record new mixing position
  2986.  
  2987. @@nofinal:
  2988.     ret
  2989. ENDP
  2990.  
  2991.  
  2992.  
  2993.  
  2994. ; 16-bit stereo normal mixing - middle, add to buffer
  2995. MACRO    _m16snma    num
  2996.     mov    bl,[gs:si]        ; take byte from source
  2997.     add    esi,edx         ; point to next sample byte
  2998.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  2999.     adc    si,0            ; add the carry to mixing position
  3000.                     ; whole part
  3001.     add    [es:di+4*num],ax    ; add word into dest left channel
  3002.     add    [es:di+4*num+2],ax    ; add word into dest right channel
  3003. ENDM
  3004.  
  3005. MixLoop m16snma, _m16snma, 64, 0, cx
  3006.  
  3007.  
  3008.  
  3009. ; 16-bit stereo normal mixing - middle, move to buffer (first channel)
  3010. MACRO    _m16snmm    num
  3011.     mov    bl,[gs:si]        ; take byte from source
  3012.     add    esi,edx         ; point to next sample byte
  3013.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  3014.     adc    si,0            ; add the carry to mixing position
  3015.                     ; whole part
  3016.     mov    [es:di+4*num],ax    ; move word into dest left channel
  3017.     mov    [es:di+4*num+2],ax    ; move word into dest right channel
  3018. ENDM
  3019.  
  3020. MixLoop m16snmm, _m16snmm, 64, 0, cx
  3021.  
  3022.  
  3023.  
  3024. ; 16-bit stereo normal mixing - surround, add to buffer
  3025. MACRO    _m16snsa    num
  3026.     mov    bl,[gs:si]        ; take byte from source
  3027.     add    esi,edx         ; point to next sample byte
  3028.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  3029.     adc    si,0            ; add the carry to mixing position
  3030.                     ; whole part
  3031.     add    [es:di+4*num],ax    ; add word into dest left channel
  3032.     sub    [es:di+4*num+2],ax    ; add with 180 degrees phase shift
  3033. ENDM
  3034.  
  3035. MixLoop m16snsa, _m16snsa, 64, 0, cx
  3036.  
  3037.  
  3038.  
  3039. ; 16-bit stereo normal mixing - surround, move to buffer (first channel)
  3040. MACRO    _m16snsm    num
  3041.     mov    bl,[gs:si]        ; take byte from source
  3042.     add    esi,edx         ; point to next sample byte
  3043.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  3044.     adc    si,0            ; add the carry to mixing position
  3045.                     ; whole part
  3046.     mov    [es:di+4*num],ax    ; move word into dest left channel
  3047.     neg    ax            ; 180 degrees phase shift
  3048.     mov    [es:di+4*num+2],ax    ; move word into dest right channel
  3049. ENDM
  3050.  
  3051. MixLoop m16snsm, _m16snsm, 64, 0, cx
  3052.  
  3053.  
  3054.  
  3055. ; 16-bit stereo normal mixing - left, add to buffer
  3056. MACRO    _m16snla    num
  3057.     mov    bl,[gs:si]        ; take byte from source
  3058.     add    esi,edx         ; point to next sample byte
  3059.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  3060.     adc    si,0            ; add the carry to mixing position
  3061.                     ; whole part
  3062.     add    [es:di+4*num],ax    ; add word into dest left channel
  3063. ENDM
  3064.  
  3065. MixLoop m16snla, _m16snla, 64, 0, cx
  3066.  
  3067.  
  3068.  
  3069. ; 16-bit stereo normal mixing - left, move to buffer (first channel)
  3070. MACRO    _m16snlm    num
  3071.     mov    bl,[gs:si]        ; take byte from source
  3072.     add    esi,edx         ; point to next sample byte
  3073.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  3074.     adc    si,0            ; add the carry to mixing position
  3075.                     ; whole part
  3076.     mov    [es:di+4*num],ax    ; move word into dest left channel
  3077.     mov    [word es:di+4*num+2],0    ; move word into dest right channel
  3078. ENDM
  3079.  
  3080. MixLoop m16snlm, _m16snlm, 64, 0, cx
  3081.  
  3082.  
  3083.  
  3084. ; 16-bit stereo normal mixing - right, add to buffer
  3085. MACRO    _m16snra    num
  3086.     mov    bl,[gs:si]        ; take byte from source
  3087.     add    esi,edx         ; point to next sample byte
  3088.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  3089.     adc    si,0            ; add the carry to mixing position
  3090.                     ; whole part
  3091.     add    [es:di+4*num+2],ax    ; add word into dest right channel
  3092. ENDM
  3093.  
  3094. MixLoop m16snra, _m16snra, 64, 0, cx
  3095.  
  3096.  
  3097.  
  3098. ; 16-bit stereo normal mixing - right, move to buffer (first channel)
  3099. MACRO    _m16snrm    num
  3100.     mov    bl,[gs:si]        ; take byte from source
  3101.     add    esi,edx         ; point to next sample byte
  3102.     mov    ax,[ebx+ebx]        ; take correct value from volume tbl
  3103.     adc    si,0            ; add the carry to mixing position
  3104.                     ; whole part
  3105.     mov    [word es:di+4*num],0    ; move word into dest left channel
  3106.     mov    [es:di+4*num+2],ax    ; move word into dest right channel
  3107. ENDM
  3108.  
  3109. MixLoop m16snrm, _m16snrm, 64, 0, cx
  3110.  
  3111.  
  3112.  
  3113. ; 16-bit stereo normal mixing - smooth panning, add to buffer
  3114. MACRO    _m16snpa    num
  3115.     mov    bl,[gs:si]        ; take byte from source
  3116.     add    esi,edx         ; point to next sample byte
  3117.     mov    ax,[ebx+ebx]        ; take left channel value from vol tbl
  3118.     adc    si,0            ; add carry to mixing pos whole part
  3119.     add    [es:di+4*num],ax    ; add word to destination left channel
  3120.     mov    cl,bl
  3121.     mov    ax,[ecx+ecx]        ; take right ch value from volume tbl
  3122.     add    [es:di+4*num+2],ax    ; add word to dest right channel
  3123. ENDM
  3124.  
  3125. MixLoop m16snpa, _m16snpa, 64, 0, [cs:_mixCount]
  3126.  
  3127.  
  3128.  
  3129. ; 16-bit stereo normal mixing - smooth panning, add to buffer
  3130. MACRO    _m16snpm    num
  3131.     mov    bl,[gs:si]        ; take byte from source
  3132.     add    esi,edx         ; point to next sample byte
  3133.     mov    ax,[ebx+ebx]        ; take left channel value from vol tbl
  3134.     adc    si,0            ; add carry to mixing pos whole part
  3135.     mov    [es:di+4*num],ax    ; move word to dest left channel
  3136.     mov    cl,bl
  3137.     mov    ax,[ecx+ecx]        ; take right ch value from volume tbl
  3138.     mov    [es:di+4*num+2],ax    ; move word to dest right channel
  3139. ENDM
  3140.  
  3141. MixLoop m16snpm, _m16snpm, 64, 0, [cs:_mixCount]
  3142.  
  3143.  
  3144.  
  3145.  
  3146. mix16sna    DW    offset m16snma        ; middle, add
  3147.         DW    offset m16snsa        ; surround, add
  3148.         DW    offset m16snla        ; left, add
  3149.         DW    offset m16snra        ; right, add
  3150.         DW    offset m16snpa        ; panning, add
  3151. mix16snm    DW    offset m16snmm        ; middle, move
  3152.         DW    offset m16snsm        ; surround, move
  3153.         DW    offset m16snlm        ; left, move
  3154.         DW    offset m16snrm        ; right, move
  3155.         DW    offset m16snpm        ; panning, move
  3156.  
  3157.  
  3158. ;/***************************************************************************\
  3159. ;*
  3160. ;* Function:    dsm_Mix16StereoNormal
  3161. ;*
  3162. ;* Description: The actual normal-quality 16-bit stereo mixing routine
  3163. ;*
  3164. ;* Input:    gs        sample data segment
  3165. ;*        esi        sample mixing position from the beginning of
  3166. ;*                the segment, in 16.16 fixed point format
  3167. ;*        edx        sample mixing position increment for each
  3168. ;*                destination byte, 16.16 fixed point format
  3169. ;*        es:di        pointer to mixing buffer (assumed to be in
  3170. ;*                dsmBuffer)
  3171. ;*        cx        number of bytes to mix
  3172. ;*        al        volume to be used
  3173. ;*        ah        current channel number
  3174. ;*        bl        1 if data to be mixed, 0 if not (even if there
  3175. ;*                is no data to be mixed, the mixing routine
  3176. ;*                must be called anyway - the buffer might not
  3177. ;*                be cleared etc.)
  3178. ;*        bh        panning information
  3179. ;*
  3180. ;* Returns:    esi        new mixing position
  3181. ;*        di        new destination position
  3182. ;*
  3183. ;* Destroys:    ax, ebx, cx, edx, esi, di
  3184. ;*
  3185. ;\***************************************************************************/
  3186.  
  3187. PROC    dsm_Mix16StereoNormal    NEAR
  3188. LOCAL    chan : byte,  destOffs : word, destLen : word, mixlp : word, \
  3189.     panning : byte, volume : byte
  3190.  
  3191.     mov    [destOffs],di        ; store destination offset
  3192.     mov    [destLen],cx        ; and mixing length
  3193.     mov    [chan],ah        ; store channel number
  3194.     mov    [panning],bh        ; store panning information
  3195.     add    al,VOLADD        ; convert volume rounding up
  3196.     shr    al,VOLSHIFT
  3197.     mov    [volume],al        ; store volume
  3198.     or    cx,cx            ; don't mix zero bytes
  3199.     jz    @@done
  3200.  
  3201.     or    bl,bl            ; is there data to be mixed?
  3202.     jnz    @@hasdata
  3203.  
  3204.     or    ah,ah            ; no data to be mixed - first channel?
  3205.     jz    @@first
  3206.  
  3207.     ; not the first channel - just update di as if data was mixed
  3208.  
  3209.     shl    cx,2            ; cx = number of bytes
  3210.     add    di,cx            ; di = new mixing position
  3211.     cmp    di,[dsmBuffer.blength]    ; past buffer end?
  3212.     jb    @@1
  3213.     sub    di,[dsmBuffer.blength]
  3214. @@1:    jmp    @@nodata
  3215.  
  3216. @@first:
  3217.     ; this is the first channel and must therefore be cleared even if
  3218.     ; there is no data to be mixed
  3219.  
  3220.     mov    bx,[dsmBuffer.blength]    ; bx = number of bytes before buffer
  3221.     sub    bx,di            ; end
  3222.     shr    bx,2            ; number of words / 2 (stereo)
  3223.     cmp    bx,cx            ; if all data fits to the buffer,
  3224.     jae    @@clrok         ; just clear it.
  3225.  
  3226.     mov    cx,bx            ; clear buffer to its end
  3227.     xor    eax,eax
  3228.     rep    stosd
  3229.  
  3230.     xor    di,di            ; jump to buffer beginning
  3231.     mov    cx,[destLen]        ; and clear required amount of bytes
  3232.     sub    cx,bx            ; from the buffer beginning
  3233.  
  3234. @@clrok:
  3235.     xor    eax,eax
  3236.     rep    stosd            ; clear the rest of buffer
  3237.     jmp    @@nodata
  3238.  
  3239.  
  3240.  
  3241. @@hasdata:
  3242.     xor    ebx,ebx         ; bh contains volume, bl sample and
  3243.                     ; upper word of ebx is zero
  3244.  
  3245.     rol    edx,16            ; reverse fractional and whole parts
  3246.     rol    esi,16            ; in mixing position and increment
  3247.  
  3248.  
  3249. @@buflp:
  3250.     mov    ax,[dsmBuffer.blength]    ; ax = number of bytes of space before
  3251.     sub    ax,di            ; buffer end
  3252.     shr    ax,2            ; number of words / 2 (stereo)
  3253.     cmp    cx,ax            ; enough space in buffer?
  3254.     jbe    @@mixok
  3255.     mov    cx,ax            ; if not, don't mix past buffer end
  3256.  
  3257. @@mixok:
  3258.     sub    [destLen],cx        ; decrease amount of data left
  3259.  
  3260.     cmp    [chan],0        ; first channel?
  3261.     je    @@move
  3262.     mov    ax,offset mix16sna    ; no, add data to buffer
  3263.     jmp    @@mix
  3264.  
  3265. @@move: mov    ax,offset mix16snm    ; yes, move data to buffer
  3266.  
  3267. @@mix:
  3268.     cmp    [panning],panMiddle
  3269.     je    @@middle
  3270.     cmp    [panning],panSurround
  3271.     je    @@surround
  3272.         cmp     [panning],panLeft and 0FFh
  3273.     je    @@left
  3274.     cmp    [panning],panRight
  3275.     je    @@right
  3276.     jmp    @@smoothp        ; smooth panning
  3277.  
  3278.  
  3279. @@middle:    ; use middle mixing routine (the first one)
  3280.     mov    bh,[volume]        ; divide volume with two - sound is
  3281.     shr    bh,1            ; played from both left and right
  3282.     jmp    @@panok
  3283.  
  3284. @@surround:
  3285.     add    ax,2            ; use surround mixing routine
  3286.     mov    bh,[volume]        ; divide volume with two - sound is
  3287.     shr    bh,1            ; played from both left and right
  3288.     jmp    @@panok
  3289.  
  3290.  
  3291. @@left: add    ax,4            ; use left mixing routine
  3292.     mov    bh,[volume]        ; don't divide volume
  3293.     jmp    @@panok
  3294.  
  3295. @@right:
  3296.     add    ax,6            ; use right mixing routine
  3297.     mov    bh,[volume]        ; don't divide volume
  3298.     jmp    @@panok
  3299.  
  3300. @@panok:
  3301.     push    ds
  3302.  
  3303.     mov    ds,[dsmVolTableSeg]    ; point ds to volume table
  3304.  
  3305.     push    bp
  3306.     mov    bp,ax
  3307.     mov    ax,[cs:bp]        ; point ax to mixing routine jump tbl
  3308.  
  3309.     push    ax
  3310.  
  3311.     mov    ax,cx            ; ax = number of words to mix
  3312.     and    ax,15            ; in the first loop
  3313.     shl    ax,1
  3314.     mov    bp,32            ; bp = jump table offset
  3315.     sub    bp,ax
  3316.  
  3317.     shl    bp,1
  3318.     sub    di,bp            ; undo di incrementing in loop
  3319.     shr    bp,1
  3320.  
  3321.     shr    cx,4            ; cx = number of loops to mix
  3322.     inc    cx
  3323.  
  3324.     pop    ax
  3325.     add    bp,ax
  3326.     call    [word cs:bp]        ; call mixing routine
  3327.  
  3328.     pop    bp
  3329.     pop    ds
  3330.     jmp    @@mixd
  3331.  
  3332.  
  3333. @@smoothp:    ; smooth panning
  3334.     mov    [_mixCount],cx        ; save mix counter
  3335.  
  3336.     push    ds
  3337.     push    bp
  3338.  
  3339.     add    ax,8            ; use smooth panning mixing routine
  3340.     mov    bx,ax
  3341.     mov    ax,[cs:bx]        ; point ax to mixing routine jump tbl
  3342.     push    ax            ; save jump table
  3343.  
  3344.     xor    ecx,ecx
  3345.  
  3346.     mov    al,[panning]
  3347.     add    al,64
  3348.     mul    [volume]
  3349.     shr    ax,7
  3350.     mov    ch,al            ; ch = right channel volume
  3351.     mov    bh,[volume]
  3352.     sub    bh,ch            ; bh = left channel volume
  3353.  
  3354.  
  3355.     mov    ds,[dsmVolTableSeg]    ; point ds to volume table
  3356.  
  3357.     mov    ax,[_mixCount]        ; ax = number of words to mix
  3358.     and    ax,15            ; in the first loop
  3359.     shl    ax,1
  3360.     mov    bp,32            ; bp = jump table offset
  3361.     sub    bp,ax
  3362.  
  3363.     shl    bp,1
  3364.     sub    di,bp            ; undo di incrementing in loop
  3365.     shr    bp,1
  3366.  
  3367.     shr    [_mixCount],4        ; _mixCount = number of loops to mix
  3368.     inc    [_mixCount]
  3369.  
  3370.     pop    ax
  3371.     add    bp,ax
  3372.     call    [word cs:bp]        ; call mixing routine
  3373.  
  3374.     pop    bp
  3375.     pop    ds
  3376.  
  3377.  
  3378. @@mixd:
  3379.     cmp    [destLen],0        ; still data to mix?
  3380.     je    @@mixdone
  3381.  
  3382.     ; there is still data to mix - apparently we are at the buffer end
  3383.     ; and must continue from the beginning
  3384.  
  3385.     xor    di,di            ; move to buffer beginning
  3386.     mov    cx,[destLen]        ; mix the rest
  3387.     jmp    @@buflp
  3388.  
  3389. @@mixdone:
  3390.     rol    esi,16            ; restore mixing position into
  3391.                     ; its original form
  3392.     jmp    @@done
  3393.  
  3394.  
  3395. @@nodata:    ; no data to be mixed on this channel
  3396.  
  3397. @@done:
  3398.     mov    al,[chan]
  3399.     inc    al            ; last channel to be mixed?
  3400.     cmp    al,[byte dsmChOpen]
  3401.     jb    @@nofinal
  3402.  
  3403.     mov    [dsmMixPos],di        ; if is, record new mixing position
  3404.  
  3405. @@nofinal:
  3406.     ret
  3407. ENDP
  3408.  
  3409.  
  3410.  
  3411.  
  3412. END
  3413.