Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. ; UFMOD.ASM
  2. ; ---------
  3. ; uFMOD public source code release. Provided as-is.
  4.  
  5. SOUND_VERSION     equ 100h ; required Infinity sound driver version
  6. FSOUND_Block      equ 10
  7. FSOUND_BlockSize  equ 1024 ; 1 << FSOUND_Block
  8.  
  9. if DEBUG
  10.  
  11. ; Debug messages:
  12. sDBGMSG1 db "uFMOD: XM track loaded",13,10,0
  13. sDBGMSG2 db "uFMOD: Infinity driver loaded",13,10,0
  14. sDBGMSG3 db "uFMOD: Buffer created",13,10,0
  15. sDBGMSG4 db "uFMOD: Sound buffer destroyed",13,10,0
  16. sDBGMSG5 db "uFMOD: Infinity version: ",0
  17.  
  18. ; DEBUG board: print a string.
  19. DBG_print_s:
  20. ; EDX = msg (trailing 0 is required!)
  21.         pushad
  22. DBG_print_s_loop:
  23.         mov eax,63
  24.         mov ebx,1
  25.         mov cl,[edx]
  26.         test cl,cl
  27.         jz DBG_print_s_R
  28.         int 40h
  29.         inc edx
  30.         jmp DBG_print_s_loop
  31. DBG_print_s_R:
  32.         popad
  33.         ret
  34.  
  35. ; DEBUG board: print the hex value in EAX.
  36. DBG_print_x:
  37. ; EAX = val
  38.         pushad
  39.         mov esi,eax
  40.         mov edx,OFFSET MixBuf
  41.         mov ecx,7
  42.         mov DWORD PTR [edx+8],0A0Dh
  43. print_eax_loop:
  44.         mov eax,esi
  45.         and al,0Fh
  46.         cmp al,10
  47.         sbb al,69h
  48.         das
  49.         mov [edx+ecx],al
  50.         shr esi,4
  51.         dec ecx
  52.         jns print_eax_loop
  53.         call DBG_print_s
  54.         popad
  55.         ret
  56. endif ; DEBUG
  57.  
  58. if RAMP_STRONG
  59.         volumerampsteps   equ 128
  60.         volumeramps_pow   equ 7
  61. endif
  62.  
  63. if RAMP_WEAK
  64.         volumerampsteps   equ 16
  65.         volumeramps_pow   equ 4
  66. endif
  67.  
  68. if RAMP_NONE
  69.         volumerampsteps   equ 64
  70.         volumeramps_pow   equ 6
  71. endif
  72.  
  73. XM_MEMORY                 equ 1
  74. XM_FILE                   equ 2
  75. XM_NOLOOP                 equ 8
  76. XM_SUSPENDED              equ 16
  77. FMUSIC_ENVELOPE_SUSTAIN   equ 2
  78. FMUSIC_ENVELOPE_LOOP      equ 4
  79. FMUSIC_FREQ               equ 1
  80. FMUSIC_VOLUME             equ 2
  81. FMUSIC_PAN                equ 4
  82. FMUSIC_TRIGGER            equ 8
  83. FMUSIC_VOLUME_OR_FREQ     equ 3
  84. FMUSIC_VOLUME_OR_PAN      equ 6
  85. FMUSIC_VOL_OR_FREQ_OR_TR  equ 11
  86. FMUSIC_FREQ_OR_TRIGGER    equ 9
  87. NOT_FMUSIC_TRIGGER        equ 0F7h
  88. NOT_FMUSIC_TRIGGER_OR_FRQ equ 0F6h
  89.  
  90. ; FMUSIC_XMCOMMANDS enum:
  91. FMUSIC_XM_PORTAUP         equ 1
  92. FMUSIC_XM_PORTADOWN       equ 2
  93. FMUSIC_XM_PORTATO         equ 3
  94. FMUSIC_XM_VIBRATO         equ 4
  95. FMUSIC_XM_PORTATOVOLSLIDE equ 5
  96. FMUSIC_XM_VIBRATOVOLSLIDE equ 6
  97. FMUSIC_XM_TREMOLO         equ 7
  98. FMUSIC_XM_SETPANPOSITION  equ 8
  99. FMUSIC_XM_SETSAMPLEOFFSET equ 9
  100. FMUSIC_XM_VOLUMESLIDE     equ 10
  101. FMUSIC_XM_PATTERNJUMP     equ 11
  102. FMUSIC_XM_SETVOLUME       equ 12
  103. FMUSIC_XM_PATTERNBREAK    equ 13
  104. FMUSIC_XM_SPECIAL         equ 14
  105. FMUSIC_XM_SETSPEED        equ 15
  106. FMUSIC_XM_SETGLOBALVOLUME equ 16
  107. FMUSIC_XM_GLOBALVOLSLIDE  equ 17
  108. FMUSIC_XM_KEYOFF          equ 20
  109. FMUSIC_XM_PANSLIDE        equ 25
  110. FMUSIC_XM_MULTIRETRIG     equ 27
  111. FMUSIC_XM_TREMOR          equ 29
  112. FMUSIC_XM_EXTRAFINEPORTA  equ 33
  113.  
  114. ; FMUSIC_XMCOMMANDSSPECIAL enum:
  115. FMUSIC_XM_FINEPORTAUP      equ 1
  116. FMUSIC_XM_FINEPORTADOWN    equ 2
  117. FMUSIC_XM_SETGLISSANDO     equ 3
  118. FMUSIC_XM_SETVIBRATOWAVE   equ 4
  119. FMUSIC_XM_SETFINETUNE      equ 5
  120. FMUSIC_XM_PATTERNLOOP      equ 6
  121. FMUSIC_XM_SETTREMOLOWAVE   equ 7
  122. FMUSIC_XM_SETPANPOSITION16 equ 8
  123. FMUSIC_XM_RETRIG           equ 9
  124. FMUSIC_XM_NOTECUT          equ 12
  125. FMUSIC_XM_NOTEDELAY        equ 13
  126. FMUSIC_XM_PATTERNDELAY     equ 14
  127.  
  128. if AC97SND_ON
  129.  
  130.         file_read:
  131.         ; buf  in EAX
  132.         ; size in EDX
  133.                 push ebx
  134.                 push esi
  135.                 push edi
  136.                 push ebp
  137.                 xchg eax,edi
  138.         file_read_begin:
  139.                 test edx,edx
  140.                 jg file_read_chk_cache
  141.         file_read_done:
  142.                 pop ebp
  143.                 pop edi
  144.                 pop esi
  145.                 pop ebx
  146.                 ret
  147.                 ; *** CHECK IN THE CACHE
  148.         file_read_chk_cache:
  149.                 mov ebp,OFFSET file_struct
  150.                 mov esi,[ebp-24]
  151.                 sub esi,[ebp+28] ; cache_offset
  152.                 js file_read_cache_done
  153.                 mov ecx,8192
  154.                 sub ecx,esi
  155.                 jle file_read_cache_done
  156.                 add esi,OFFSET MixBuf
  157.                 sub edx,ecx
  158.                 jns file_read_do_cache
  159.                 add ecx,edx
  160.         file_read_do_cache:
  161.                 add [ebp-24],ecx
  162.                 rep movsb
  163.                 test edx,edx
  164.                 jle file_read_done ; data read from the cache (no need to access the FS)
  165.         file_read_cache_done:
  166.                 ; *** FS BATCH READ OPERATION
  167.                 mov eax,[ebp-24]
  168.                 mov ecx,edx
  169.                 add ecx,eax
  170.                 and ecx,0FFFFE000h
  171.                 sub ecx,eax
  172.                 jle file_read_fs_done ; Too few data requested for a FS batch operation
  173.                 sub edx,ecx
  174.                 mov [ebp+4],eax  ; file offset
  175.                 mov [ebp+12],ecx ; NumberOfBytesToRead
  176.                 mov [ebp+16],edi ; lpBuffer
  177.                 mov ebx,ebp
  178.                 add edi,ecx
  179.                 push 70
  180.                 add [ebp-24],ecx
  181.                 pop eax
  182.                 int 40h
  183.         file_read_fs_done:
  184.                 ; *** UPDATE THE CACHE
  185.                 mov ecx,[ebp-24]
  186.                 and ecx,0FFFFE000h
  187.                 mov [ebp+4],ecx           ; file offset
  188.                 mov [ebp+28],ecx          ; cache_offset
  189.                 mov DWORD PTR [ebp+12],8192 ; NumberOfBytesToRead
  190.                 mov DWORD PTR [ebp+16],OFFSET MixBuf ; lpBuffer
  191.                 mov ebx,ebp
  192.                 push 70
  193.                 pop eax
  194.                 int 40h
  195.                 jmp file_read_begin
  196.  
  197.         if INFO_API_ON
  198.                 PUBLIC _uFMOD_GetTitle
  199.                 _uFMOD_GetTitle:
  200.                         mov eax,OFFSET szTtl
  201.                         ret
  202.         endif
  203.  
  204. else
  205.                 uFMOD_mem dd mem_open, mem_read
  206.         if XM_FILE_ON
  207.                 uFMOD_fs  dd file_open, file_read
  208.         endif
  209.  
  210.         szInfinity db "INFINITY",0
  211.  
  212.         if JUMP_TO_PAT_ON
  213.  
  214.                 ; Jump to the given pattern
  215.         PUBLIC _uFMOD_Jump2Pattern
  216.         _uFMOD_Jump2Pattern:
  217.                 mov eax,[esp+4]
  218.                 mov ecx,OFFSET _mod+36
  219.                 movzx eax,ax
  220.                 and DWORD PTR [ecx+FMUSIC_MODULE.nextrow-36],0
  221.                 cmp ax,[ecx+FMUSIC_MODULE.numorders-36]
  222.                 sbb edx,edx
  223.                 and eax,edx
  224.                 mov [ecx+FMUSIC_MODULE.nextorder-36],eax
  225.                 ret
  226.         endif
  227.  
  228.         if VOL_CONTROL_ON
  229.  
  230.                 ; Set global volume [0: silence, 25: max. volume]
  231.                 vol_scale dw 1     ; -45 dB
  232.                           dw 130   ; -24
  233.                           dw 164   ; -23
  234.                           dw 207   ; -22
  235.                           dw 260   ; -21
  236.                           dw 328   ; -20
  237.                           dw 413   ; -19
  238.                           dw 519   ; -18
  239.                           dw 654   ; -17
  240.                           dw 823   ; -16
  241.                           dw 1036  ; -15
  242.                           dw 1305  ; -14
  243.                           dw 1642  ; -13
  244.                           dw 2068  ; -12
  245.                           dw 2603  ; -11
  246.                           dw 3277  ; -10
  247.                           dw 4125  ; -9
  248.                           dw 5193  ; -8
  249.                           dw 6538  ; -7
  250.                           dw 8231  ; -6
  251.                           dw 10362 ; -5
  252.                           dw 13045 ; -4
  253.                           dw 16423 ; -3
  254.                           dw 20675 ; -2
  255.                           dw 26029 ; -1
  256.                           dw 32768 ; 0 dB
  257.                 PUBLIC _uFMOD_SetVolume
  258.                 _uFMOD_SetVolume:
  259.                         mov eax,[esp+4]
  260.                         cmp eax,25
  261.                         jna get_vol_scale
  262.                         push 25
  263.                         pop eax
  264.                 get_vol_scale:
  265.                         mov ax,[vol_scale+eax*2]
  266.                         mov [ufmod_vol],eax
  267.                         ret
  268.         endif
  269.  
  270.         if PAUSE_RESUME_ON
  271.  
  272.                         ; Pause the currently playing song.
  273.                 PUBLIC _uFMOD_Pause
  274.                 _uFMOD_Pause:
  275.                         mov al,1
  276.                         jmp $+4
  277.  
  278.                         ; Resume the currently paused song.
  279.                 PUBLIC _uFMOD_Resume
  280.                 _uFMOD_Resume:
  281.                         xor eax,eax
  282.                         mov BYTE PTR [ufmod_pause_],al
  283.                         ret
  284.         endif
  285.  
  286.         if INFO_API_ON
  287.  
  288.                 ; Return currently playing signal stats:
  289.                 ;    lo word : RMS volume in R channel
  290.                 ;    hi word : RMS volume in L channel
  291.                 PUBLIC _uFMOD_GetStats
  292.                 _uFMOD_GetStats:
  293.                         push 4
  294.                         jmp _uFMOD_InfoApi
  295.  
  296.                 ; Return currently playing row and order:
  297.                 ;    lo word : row
  298.                 ;    hi word : order
  299.                 PUBLIC _uFMOD_GetRowOrder
  300.                 _uFMOD_GetRowOrder:
  301.                         push 8
  302.                         jmp _uFMOD_InfoApi
  303.  
  304.                 ; Return the time in milliseconds since the song was started.
  305.                 PUBLIC _uFMOD_GetTime
  306.                 _uFMOD_GetTime:
  307.                         push 0
  308.                 _uFMOD_InfoApi:
  309.                         pop edx
  310.                         mov eax,[time_ms+edx]
  311.                         ret
  312.         endif
  313.  
  314.         ; ***********************
  315.         ; * XM_MEMORY CALLBACKS *
  316.         ; ***********************
  317.         mem_read:
  318.         ; buf in EAX
  319.         ; size in EDX
  320.                 push edi
  321.                 push esi
  322.                 xchg eax,edi ; buf
  323.                 mov esi,OFFSET mmf
  324.                 lodsd
  325.                 mov ecx,edx
  326.                 add edx,[esi]
  327.                 cmp edx,eax
  328.                 jl copy
  329.                 sub eax,[esi]
  330.                 xchg eax,ecx
  331.         copy:
  332.                 test ecx,ecx
  333.                 jle mem_read_R
  334.                 lodsd
  335.                 add eax,[esi]
  336.                 mov [esi-4],edx
  337.         mem_do_copy:
  338.                 mov dl,[eax]
  339.                 mov [edi],dl
  340.                 inc eax
  341.                 inc edi
  342.                 dec ecx
  343.                 jnz mem_do_copy
  344.         mem_read_R:
  345.                 pop esi
  346.                 pop edi
  347.         if INFO_API_ON
  348.                 PUBLIC _uFMOD_GetTitle
  349.                 _uFMOD_GetTitle:
  350.                         mov eax,OFFSET szTtl
  351.         endif
  352.         mem_open:
  353.                 ret
  354.  
  355.         ; *********************
  356.         ; * XM_FILE CALLBACKS *
  357.         ; *********************
  358.         if XM_FILE_ON
  359.                 file_open:
  360.                 ; pszName in ESI
  361.                         ; Prepare the FILE struct for subsecuent I/O:
  362.                         lea eax,[ebp+8]  ; file_struct
  363.                         xor edx,edx
  364.                         mov [eax],edx    ;  +0 subfunction: 0 = read
  365.                         mov [eax+8],edx  ;  +8 Reserved
  366.                                          ; +12 NumberOfBytesToRead
  367.                                          ; +16 lpBuffer
  368.                         push -1
  369.                         push 1
  370.                         mov [eax+20],dl  ; +20 db 0
  371.                         mov [eax+21],esi ; +21 lpFileName
  372.                         pop DWORD PTR [eax+28] ; cache_offset
  373.                         pop DWORD PTR [eax-28] ; [mmf] = maximum size
  374.                         ret
  375.  
  376.                 file_read:
  377.                 ; buf  in EAX
  378.                 ; size in EDX
  379.                         push ebx
  380.                         push esi
  381.                         push edi
  382.                         push ebp
  383.                         xchg eax,edi
  384.                 file_read_begin:
  385.                         test edx,edx
  386.                         jg file_read_chk_cache
  387.                 file_read_done:
  388.                         pop ebp
  389.                         pop edi
  390.                         pop esi
  391.                         pop ebx
  392.                         ret
  393.                         ; *** CHECK IN THE CACHE
  394.                 file_read_chk_cache:
  395.                         mov ebp,OFFSET file_struct
  396.                         mov esi,[ebp-24]
  397.                         sub esi,[ebp+28] ; cache_offset
  398.                         js file_read_cache_done
  399.                         mov ecx,8192
  400.                         sub ecx,esi
  401.                         jle file_read_cache_done
  402.                         add esi,OFFSET MixBuf
  403.                         sub edx,ecx
  404.                         jns file_read_do_cache
  405.                         add ecx,edx
  406.                 file_read_do_cache:
  407.                         add [ebp-24],ecx
  408.                         rep movsb
  409.                         test edx,edx
  410.                         jle file_read_done ; data read from the cache (no need to access the FS)
  411.                 file_read_cache_done:
  412.                         ; *** FS BATCH READ OPERATION
  413.                         mov eax,[ebp-24]
  414.                         mov ecx,edx
  415.                         add ecx,eax
  416.                         and ecx,0FFFFE000h
  417.                         sub ecx,eax
  418.                         jle file_read_fs_done ; Too few data requested for a FS batch operation
  419.                         sub edx,ecx
  420.                         mov [ebp+4],eax  ; file offset
  421.                         mov [ebp+12],ecx ; NumberOfBytesToRead
  422.                         mov [ebp+16],edi ; lpBuffer
  423.                         mov ebx,ebp
  424.                         add edi,ecx
  425.                         push 70
  426.                         add [ebp-24],ecx
  427.                         pop eax
  428.                         int 40h
  429.                 file_read_fs_done:
  430.                         ; *** UPDATE THE CACHE
  431.                         mov ecx,[ebp-24]
  432.                         and ecx,0FFFFE000h
  433.                         mov [ebp+4],ecx           ; file offset
  434.                         mov [ebp+28],ecx          ; cache_offset
  435.                         mov DWORD PTR [ebp+12],8192 ; NumberOfBytesToRead
  436.                         mov DWORD PTR [ebp+16],OFFSET MixBuf ; lpBuffer
  437.                         mov ebx,ebp
  438.                         push 70
  439.                         pop eax
  440.                         int 40h
  441.                         jmp file_read_begin
  442.         endif
  443.  
  444. endif ; AC97SND_ON = 0
  445.  
  446. uFMOD_lseek:
  447. ; pos  in EAX
  448. ; org  in ECX
  449. ; !org in Z
  450.         mov edx,OFFSET mmf+4
  451.         jz mem_ok
  452.         add eax,[edx]
  453. mem_ok:
  454.         test eax,eax
  455.         js mem_seek_R
  456.         cmp eax,[edx-4]
  457.         ja mem_seek_R
  458.         mov [edx],eax
  459. mem_seek_R:
  460.         ret
  461.  
  462. ; Dynamic memory allocation
  463. alloc:
  464. ; EAX: how many bytes to allocate
  465.         add eax,3
  466.         and eax,-4
  467.         jle alloc_error2
  468.         mov ecx,OFFSET ufmod_heap
  469. alloc_lookup:
  470.         cmp DWORD PTR [ecx],0
  471.         je do_alloc
  472.         mov ecx,[ecx]
  473.         cmp [ecx+4],eax
  474.         jl alloc_lookup
  475.         sub [ecx+4],eax
  476.         mov eax,[ecx+4]
  477.         lea eax,[eax+ecx+8]
  478.         ret
  479. do_alloc:
  480.         add eax,8
  481.         push ebx
  482.         push edi
  483.         mov ebx,eax
  484.         add ebx,8191
  485.         neg eax
  486.         and ebx,-8192
  487.         push ecx
  488.         add eax,ebx
  489.         xchg eax,edi
  490.         push 12
  491.         push 68
  492.         mov ecx,ebx
  493.         pop eax
  494.         pop ebx
  495.         int 40h
  496.         ; Test for error condition
  497.         test eax,eax
  498.         pop ebx
  499.         mov edx,edi ; free space
  500.         jz alloc_error1
  501.         mov [ebx],eax
  502.         mov edi,eax
  503.         lea eax,[eax+edx+8]
  504.         mov [edi+4],edx
  505.         pop edi
  506.         pop ebx
  507.         ret
  508. alloc_error1:
  509.         pop edi
  510.         pop ebx
  511. alloc_error2:
  512.         xor eax,eax
  513.         pop edx ; EIP
  514.         pop ebx
  515.         leave
  516. _alloc_R:
  517.         ret
  518.  
  519. ; Starts playing a song.
  520. PUBLIC _uFMOD_LoadSong
  521. _uFMOD_LoadSong:
  522.  
  523.         ; *** FREE PREVIOUS TRACK, IF ANY
  524.         call _uFMOD_StopSong
  525.  
  526.         if AC97SND_ON
  527.                 mov ecx,[esp+4]
  528.                 push ebx
  529.                 push esi
  530.                 push edi
  531.                 push ebp
  532.                 mov ebp,OFFSET uFMOD_fopen
  533.                 ; Prepare the FILE struct for subsecuent I/O:
  534.                 lea eax,[ebp+8]  ; file_struct
  535.                 xor edx,edx
  536.                 mov [eax],edx    ;  +0 subfunction: 0 = read
  537.                 mov [eax+8],edx  ;  +8 Reserved
  538.                                  ; +12 NumberOfBytesToRead
  539.                                  ; +16 lpBuffer
  540.                 mov [eax+20],dl  ; +20 db 0
  541.                 mov [eax+21],ecx ; +21 lpFileName
  542.                 push -1
  543.                 push 1
  544.                 mov DWORD PTR [ebp+4],OFFSET file_read ; uFMOD_fread
  545.                 pop DWORD PTR [eax+28]          ; cache_offset
  546.                 mov [eax-24],edx
  547.                 pop DWORD PTR [eax-28]          ; [mmf] = maximum size
  548.         else
  549.                 mov eax,[esp+8]  ; param
  550.                 mov ecx,[esp+12] ; fdwSong
  551.                 mov edx,[esp+4]  ; lpXM
  552.                 test edx,edx
  553.                 jz _alloc_R
  554.                 ; *** SET I/O CALLBACKS
  555.                 push ebx
  556.                 push esi
  557.                 push edi
  558.                 push ebp
  559.                 mov ebp,OFFSET uFMOD_fopen
  560.                 mov [ebp-20],eax ; mmf
  561.                 xor eax,eax
  562.                 mov [ebp-16],eax ; mmf+4
  563.                 test cl,XM_MEMORY
  564.                 mov esi,OFFSET uFMOD_mem
  565.         if XM_FILE_ON
  566.                 jnz set_callbacks
  567.                 test cl,XM_FILE
  568.                 lea esi,[esi+(uFMOD_fs-uFMOD_mem)]
  569.         endif
  570.                 jz goto_StopSong
  571.         set_callbacks:
  572.         if NOLOOP_ON
  573.                 test cl,XM_NOLOOP
  574.                 setnz [ebp-24] ; ufmod_noloop
  575.         endif
  576.         if PAUSE_RESUME_ON
  577.                 and cl,XM_SUSPENDED
  578.                 mov [ebp-23],cl ; ufmod_pause_
  579.         endif
  580.                 mov edi,ebp ; uFMOD_fopen
  581.                 movsd
  582.                 movsd
  583.                 mov esi,edx ; uFMOD_fopen:lpXM <= ESI
  584.         if VOL_CONTROL_ON
  585.                 cmp [ebp-4],eax ; ufmod_vol
  586.                 jne play_vol_ok
  587.                 mov WORD PTR [ebp-4],32768
  588.         play_vol_ok:
  589.         endif
  590.                 xor edi,edi
  591.                 ; *** INIT THE INFINITY DRIVER
  592.                 lea eax,[edi+68]
  593.                 lea ebx,[edi+16]
  594.                 mov ecx,OFFSET szInfinity
  595.                 int 40h
  596.                 test eax,eax
  597.                 mov [hSound],eax
  598.                 jz goto_StopSong
  599.         if DEBUG
  600.                 mov edx,OFFSET sDBGMSG2
  601.                 call DBG_print_s
  602.         endif
  603.                 ; *** CHECK THE DRIVER VERSION
  604.                 push edi ; ver = 0
  605.                 push esp ; &ver
  606.                 mov edx,esp
  607.                 push 4   ; .out_size
  608.                 push edx ; .output = &&ver
  609.                 push edi ; .inp_size
  610.                 push edi ; .input
  611.                 push edi ; .code   = SRV_GETVERSION
  612.                 push eax ; .handle = [hSound]
  613.                 lea ebx,[edi+17]
  614.                 lea eax,[edi+68]
  615.                 mov ecx,esp
  616.                 int 40h
  617.                 add esp,28
  618.                 pop eax ; ver
  619.         if DEBUG
  620.                 mov edx,OFFSET sDBGMSG5
  621.                 call DBG_print_s
  622.                 call DBG_print_x
  623.         endif
  624.                 shr eax,16
  625.                 cmp eax,SOUND_VERSION
  626.                 ja _uFMOD_StopSong+4 ; obsolete program version (Hint: try adjusting SOUND_VERSION!)
  627.                 ; *** ALLOCATE A HEAP OBJECT
  628.                 lea eax,[edi+68]
  629.                 lea ebx,[edi+11]
  630.                 int 40h
  631.                 test eax,eax
  632.                 jz goto_StopSong
  633.                 ; *** LOAD THE TRACK
  634.                 mov [ebp-12],esi ; mmf+8 <= pMem
  635.         if XM_FILE_ON
  636.                 call DWORD PTR [ebp] ; uFMOD_fopen
  637.         endif
  638.  
  639.         endif ; AC97SND_ON = 0
  640.  
  641.         call LoadXM
  642.         test eax,eax
  643. goto_StopSong:
  644.         jz _uFMOD_StopSong+4
  645. if DEBUG
  646.         mov edx,OFFSET sDBGMSG1
  647.         call DBG_print_s
  648. endif
  649.  
  650.         if AC97SND_ON
  651.         else
  652.                 xor edi,edi
  653.                 ; *** CREATE THE PCM BUFFER
  654.                 push edi        ; size (default is 64Kb)
  655.                 push PCM_format ; format: 16-bit / stereo / sampling rate
  656.                 mov edx,esp
  657.                 push OFFSET hBuff
  658.                 mov eax,esp
  659.                 push 4              ; .out_size
  660.                 push eax            ; .output = &&hBuff
  661.                 push 8              ; .inp_size
  662.                 push edx            ; .input
  663.                 push 1              ; .code   = SND_CREATE_BUFF
  664.                 push DWORD PTR [hSound] ; .handle
  665.                 lea eax,[edi+68]
  666.                 lea ebx,[edi+17]
  667.                 mov ecx,esp
  668.                 int 40h
  669.                 pop esi ; <- hSound
  670.                 add esp,32
  671.                 test eax,eax
  672.                 jnz _uFMOD_StopSong+4 ; buffer not created
  673.         if DEBUG
  674.                 mov edx,OFFSET sDBGMSG3
  675.                 call DBG_print_s
  676.         endif
  677.                 xchg eax,esi ; return the driver handle
  678.         endif ; AC97SND_ON = 0
  679.  
  680.         ; *** ENABLE PCM OUTPUT
  681.         mov [SW_Exit],eax
  682.         pop ebp
  683.         pop edi
  684.         pop esi
  685.         pop ebx
  686.         ret
  687.  
  688. ; Stop the currently playing song, if any, and free all resources allocated for that song.
  689. PUBLIC _uFMOD_StopSong
  690. _uFMOD_StopSong:
  691.         push ebx
  692.         push esi
  693.         push edi
  694.         push ebp
  695. ; _uFMOD_StopSong+4
  696.         xor edi,edi
  697.         mov ebp,OFFSET ufmod_heap
  698.         ; *** DISABLE PCM OUTPUT
  699.         mov [ebp+16],edi ; SW_Exit
  700.  
  701.         if AC97SND_ON
  702.         else
  703.                 ; *** STOP AND DESTROY THE PCM BUFFER
  704.                 mov eax,[ebp+12] ; hBuff
  705.                 test eax,eax
  706.                 jz SND_buffer_free
  707.                 push eax             ; buffer
  708.                 mov edx,esp
  709.                 push edi             ; .out_size
  710.                 push edi             ; .output
  711.                 push 4               ; .inp_size
  712.                 push edx             ; .input
  713.                 push 11              ; .code   = SND_STOP
  714.                 push DWORD PTR [ebp+8]   ; .handle = [hSound]
  715.                 lea eax,[edi+68]
  716.                 lea ebx,[edi+17]
  717.                 mov ecx,esp
  718.                 int 40h
  719.                 mov DWORD PTR [esp+4],2  ; .code = SND_DESTROY_BUFF
  720.                 lea eax,[edi+68]
  721.                 int 40h
  722.                 add esp,28
  723.         if DEBUG
  724.                 mov edx,OFFSET sDBGMSG4
  725.                 call DBG_print_s
  726.         endif
  727.         SND_buffer_free:
  728.                 mov [ebp+12],edi ; hBuff
  729.         endif ; AC97SND_ON = 0
  730.  
  731.         ; *** FREE THE HEAP
  732.         mov esi,[ebp]    ; ufmod_heap
  733. heapfree:
  734.         test esi,esi
  735.         jz free_R
  736.         mov ecx,esi
  737.         mov esi,[esi]
  738.         lea eax,[edi+68]
  739.         lea ebx,[edi+13]
  740.         int 40h
  741.         jmp heapfree
  742. free_R:
  743.         xor eax,eax
  744.  
  745.         if AC97SND_ON
  746.         else
  747.                 if INFO_API_ON
  748.                         ; *** CLEAR THE INFO API DATA
  749.                         lea ecx,[eax+4]
  750.                         mov edi,OFFSET time_ms
  751.                         rep stosd
  752.                 endif
  753.         endif ; AC97SND_ON = 0
  754.  
  755.         mov DWORD PTR [ebp],eax ; ufmod_heap
  756.         pop ebp
  757.         pop edi
  758.         pop esi
  759.         pop ebx
  760.         ret
  761.  
  762. PUBLIC _uFMOD_WaveOut
  763. _uFMOD_WaveOut:
  764.         push edi
  765.         push ebp
  766.         xor edi,edi
  767.  
  768.         if AC97SND_ON
  769.                 ; *** PCM OUTPUT ENABLED?
  770.                 cmp DWORD PTR [SW_Exit],edi
  771.                 lea eax,[edi+1] ; return error if output not enabled
  772.                 je _uFMOD_WaveOut_R
  773.                 ; *** COMPUTE THE NUMBER OF FREE BLOCKS AVAILABLE
  774.                 lea ecx,[esp+12]    ; &hBuff
  775.                 push edi            ; space = 0
  776.                 mov edx,esp
  777.                 push 4              ; .out_size
  778.                 push edx            ; .output = &space
  779.                 push 4              ; .inp_size
  780.                 push ecx            ; .input
  781.                 push 17             ; .code   = SND_GETFREESPACE
  782.                 mov ecx,[ecx]
  783.                 push DWORD PTR [hSound] ; .handle
  784.                 mov [hBuff],ecx
  785.         else
  786.                 mov ebp,OFFSET hSound
  787.                 ; *** PCM OUTPUT ENABLED?
  788.                 cmp [ebp+8],edi ; SW_Exit
  789.                 lea eax,[edi+1] ; return error if output not enabled
  790.                 je _uFMOD_WaveOut_R
  791.                 ; *** COMPUTE THE NUMBER OF FREE BLOCKS AVAILABLE
  792.                 push edi         ; space = 0
  793.                 mov edx,esp
  794.                 push 4           ; .out_size
  795.                 lea ecx,[ebp+4]  ; &hBuff
  796.                 push edx         ; .output = &space
  797.                 push 4           ; .inp_size
  798.                 push ecx         ; .input
  799.                 push 17          ; .code   = SND_GETFREESPACE
  800.                 push DWORD PTR [ebp] ; .handle = [hSound]
  801.         endif ; AC97SND_ON = 0
  802.  
  803.         lea ebx,[edi+17]
  804.         lea eax,[edi+68]
  805.         mov ecx,esp
  806.         int 40h
  807.         add esp,24
  808.         pop edi ; <- space
  809.         shr edi,FSOUND_Block+2  ; / (FSOUND_BlockSize * 4)
  810.         jz _uFMOD_WaveOut_R     ; no free blocks available
  811. _uFMOD_WaveOut_loop:
  812.         call uFMOD_do_WaveOut
  813.         neg eax
  814.         dec edi
  815.         ja _uFMOD_WaveOut_loop
  816. _uFMOD_WaveOut_R:
  817.         pop ebp
  818.         pop edi
  819.         ret
  820.  
  821. uFMOD_do_WaveOut:
  822.         mov ecx,FSOUND_BlockSize*2
  823.         push ebx
  824.         push esi
  825.         push edi
  826.         mov edi,OFFSET MixBuf
  827.         xor eax,eax
  828.         push edi ; mixbuffer <= MixBuf
  829.         push edi ; <- MixPtr
  830.         ; MIXBUFFER CLEAR
  831.         mov esi,OFFSET _mod+36
  832.         rep stosd
  833.  
  834.         if AC97SND_ON
  835.         else
  836.                 if PAUSE_RESUME_ON
  837.                         cmp [ufmod_pause_],al
  838.                         xchg eax,ebp
  839.                         jne do_swfill
  840.                 endif
  841.         endif ; AC97SND_ON = 0
  842.  
  843.         mov ebp,FSOUND_BlockSize
  844.         ; UPDATE MUSIC
  845.         mov ebx,[esi+FMUSIC_MODULE.mixer_samplesleft-36]
  846. fill_loop_1:
  847.         test ebx,ebx
  848.         jnz mixedleft_nz
  849.         ; UPDATE XM EFFECTS
  850.         cmp [esi+FMUSIC_MODULE.tick-36],ebx ; new note
  851.         mov ecx,[esi+FMUSIC_MODULE.pattern-36]
  852.         jne update_effects
  853.         dec ebx
  854.         ; process any rows commands to set the next order/row
  855.         mov edx,[esi+FMUSIC_MODULE.nextorder-36]
  856.         mov eax,[esi+FMUSIC_MODULE.nextrow-36]
  857.         mov [esi+FMUSIC_MODULE.nextorder-36],ebx
  858.         test edx,edx
  859.         mov [esi+FMUSIC_MODULE.nextrow-36],ebx
  860.         jl fill_nextrow
  861.         mov [esi+FMUSIC_MODULE.order-36],edx
  862. fill_nextrow:
  863.         test eax,eax
  864.         jl update_note
  865.         mov [esi+FMUSIC_MODULE.row-36],eax
  866. update_note:
  867.         ; mod+36 : ESI
  868.         call DoNote
  869. if ROWCOMMANDS_ON
  870.         cmp DWORD PTR [esi+FMUSIC_MODULE.nextrow-36],-1
  871.         jne inc_tick
  872. endif
  873.         mov eax,[esi+FMUSIC_MODULE.row-36]
  874.         inc eax
  875.         ; if end of pattern
  876.         ; "if(mod->nextrow >= mod->pattern[mod->orderlist[mod->order]].rows)"
  877.         cmp ax,[ebx]
  878.         jl set_nextrow
  879.         mov edx,[esi+FMUSIC_MODULE.order-36]
  880.         movzx ecx,WORD PTR [esi+FMUSIC_MODULE.numorders-36]
  881.         inc edx
  882.         xor eax,eax
  883.         cmp edx,ecx
  884.         jl set_nextorder
  885.  
  886.         if AC97SND_ON
  887.         else
  888.                 ; We've reached the end of the order list. So, stop playing, unless looping is enabled.
  889.                 if NOLOOP_ON
  890.                         cmp [ufmod_noloop],al
  891.                         je set_restart
  892.                         pop eax ; skip MixPtr
  893.                         pop edx ; skip mixbuffer
  894.                         pop edi
  895.                         inc eax ; end of loop reached while XM_NOLOOP flag is enabled
  896.                         pop esi
  897.                         pop ebx
  898.                         ret
  899.                 set_restart:
  900.                 endif
  901.         endif ; AC97SND_ON = 0
  902.  
  903.         movzx edx,WORD PTR [esi+FMUSIC_MODULE.restart-36]
  904.         cmp edx,ecx
  905.         sbb ecx,ecx
  906.         and edx,ecx
  907. set_nextorder:
  908.         mov [esi+FMUSIC_MODULE.nextorder-36],edx
  909. set_nextrow:
  910.         mov [esi+FMUSIC_MODULE.nextrow-36],eax
  911.         jmp inc_tick
  912. update_effects:
  913.         ; mod+36 : ESI
  914.         call DoEffs
  915. inc_tick:
  916.         mov eax,[esi+FMUSIC_MODULE.speed-36]
  917.         mov ebx,[esi+FMUSIC_MODULE.mixer_samplespertick-36]
  918.         inc DWORD PTR [esi+FMUSIC_MODULE.tick-36]
  919. if PATTERNDELAY_ON
  920.         add eax,[esi+FMUSIC_MODULE.patterndelay-36]
  921. endif
  922.         cmp [esi+FMUSIC_MODULE.tick-36],eax
  923.         jl mixedleft_nz
  924. if PATTERNDELAY_ON
  925.         and DWORD PTR [esi+FMUSIC_MODULE.patterndelay-36],0
  926. endif
  927.         and DWORD PTR [esi+FMUSIC_MODULE.tick-36],0
  928. mixedleft_nz:
  929.         mov edi,ebp
  930.         cmp ebx,edi
  931.         jae fill_ramp
  932.         mov edi,ebx
  933. fill_ramp:
  934.         pop edx  ; <- MixPtr
  935.         sub ebp,edi
  936.         lea eax,[edx+edi*8]
  937.         push eax ; MixPtr += (SamplesToMix<<3)
  938.         ; tail    : [arg0]
  939.         ; len     : EDI
  940.         ; mixptr  : EDX
  941.         ; _mod+36 : ESI
  942.         call Ramp
  943.  
  944.         if AC97SND_ON
  945.         else
  946.                 if INFO_API_ON
  947.                         lea eax,[edi+edi*4]
  948.                         cdq
  949.                         shl eax,2
  950.                         mov ecx,FSOUND_MixRate/50
  951.                         div ecx
  952.                         ; time_ms += SamplesToMix*FSOUND_OOMixRate*1000
  953.                         add [time_ms],eax
  954.                 endif
  955.         endif ; AC97SND_ON = 0
  956.  
  957.         sub ebx,edi ; MixedLeft -= SamplesToMix
  958.         test ebp,ebp
  959.         jnz fill_loop_1
  960.         mov [esi+FMUSIC_MODULE.mixer_samplesleft-36],ebx ; <= MixedLeft
  961.  
  962.         if AC97SND_ON
  963.         else
  964.                 if INFO_API_ON
  965.                         mov ecx,[esi + FMUSIC_MODULE.row-36]
  966.                         or ecx,[esi + FMUSIC_MODULE.order-2-36]
  967.                         mov DWORD PTR [s_row],ecx
  968.                 endif
  969.         endif ; AC97SND_ON = 0
  970.  
  971. do_swfill:
  972.         ; *** CLIP AND COPY BLOCK TO OUTPUT BUFFER
  973.         pop eax ; skip MixPtr
  974.         pop esi ; <- mixbuffer
  975.  
  976.         if AC97SND_ON
  977.         else
  978.                 if INFO_API_ON
  979.                         ; ebx : L channel RMS volume
  980.                         ; ebp : R channel RMS volume
  981.                         xor ebx,ebx
  982.                 endif
  983.         endif ; AC97SND_ON = 0
  984.  
  985.         mov edi,esi
  986.         mov ecx,FSOUND_BlockSize*2
  987.         align 4
  988. fill_loop_2:
  989.         lodsd
  990.  
  991.         if AC97SND_ON
  992.                 mov ebx,eax
  993.                 cdq
  994.                 xor eax,edx
  995.                 sub eax,edx
  996.                 mov ebp,255*volumerampsteps/2
  997.                 xor edx,edx
  998.                 div ebp
  999.                 cmp edx,255*volumerampsteps/4
  1000.                 sbb eax,-1
  1001.                 cmp eax,8000h
  1002.                 sbb edx,edx
  1003.                 not edx
  1004.                 or eax,edx
  1005.                 sar ebx,31
  1006.                 and eax,7FFFh
  1007.                 xor eax,ebx
  1008.                 sub eax,ebx
  1009.         else
  1010.                 if INFO_API_ON
  1011.                         push edi
  1012.                         cdq
  1013.                         mov edi,eax
  1014.                         push esi
  1015.                         xor eax,edx
  1016.                         mov esi,255*volumerampsteps/2
  1017.                         sub eax,edx
  1018.                         xor edx,edx
  1019.                         div esi
  1020.                         cmp edx,255*volumerampsteps/4
  1021.                         pop esi
  1022.                         sbb eax,-1
  1023.                         cmp eax,8000h
  1024.                         sbb edx,edx
  1025.                         not edx
  1026.                         or eax,edx
  1027.                         sar edi,31
  1028.                         and eax,7FFFh
  1029.                 if VOL_CONTROL_ON
  1030.                         mul DWORD PTR [ufmod_vol]
  1031.                         shr eax,15
  1032.                 endif
  1033.                         ; sum. the L and R channel RMS volume
  1034.                         ror ecx,1
  1035.                         sbb edx,edx
  1036.                         and edx,eax
  1037.                         add ebp,edx ; += |vol|
  1038.                         rol ecx,1
  1039.                         sbb edx,edx
  1040.                         not edx
  1041.                         and edx,eax
  1042.                         add ebx,edx ; += |vol|
  1043.                         xor eax,edi
  1044.                         sub eax,edi
  1045.                         pop edi
  1046.                 else
  1047.                         mov ebx,eax
  1048.                         cdq
  1049.                         xor eax,edx
  1050.                         sub eax,edx
  1051.                         mov ebp,255*volumerampsteps/2
  1052.                         xor edx,edx
  1053.                         div ebp
  1054.                         cmp edx,255*volumerampsteps/4
  1055.                         sbb eax,-1
  1056.                         cmp eax,8000h
  1057.                         sbb edx,edx
  1058.                         not edx
  1059.                         or eax,edx
  1060.                         sar ebx,31
  1061.                         and eax,7FFFh
  1062.                 if VOL_CONTROL_ON
  1063.                         mul DWORD PTR [ufmod_vol]
  1064.                         shr eax,15
  1065.                 endif
  1066.                         xor eax,ebx
  1067.                         sub eax,ebx
  1068.                 endif
  1069.         endif ; AC97SND_ON = 0
  1070.  
  1071.         dec ecx
  1072.         stosw
  1073.         jnz fill_loop_2
  1074.  
  1075.         if AC97SND_ON
  1076.         else
  1077.                 if INFO_API_ON
  1078.                         shr ebp,FSOUND_Block      ; R_vol / FSOUND_BlockSize
  1079.                         shl ebx,16-FSOUND_Block   ; (L_vol / FSOUND_BlockSize) << 16
  1080.                         mov bx,bp
  1081.                         mov DWORD PTR [L_vol],ebx
  1082.                 endif
  1083.         endif ; AC97SND_ON = 0
  1084.  
  1085.         ; *** DISPATCH DATA TO THE AC97 DRIVER
  1086.         push FSOUND_BlockSize*4 ; size
  1087.         push OFFSET MixBuf      ; &src
  1088.         push DWORD PTR [hBuff]  ; buffer
  1089.         mov edx,esp
  1090.         push ecx                ; .out_size
  1091.         push ecx                ; .output
  1092.         push 12                 ; .inp_size
  1093.         push edx                ; .input
  1094.         push 9                  ; .code = SND_OUT
  1095.         push DWORD PTR [hSound] ; .handle
  1096.         lea eax,[ecx+68]
  1097.         lea ebx,[ecx+17]
  1098.         mov ecx,esp
  1099.         int 40h
  1100.         add esp,36
  1101.         pop edi
  1102.         pop esi
  1103.         pop ebx
  1104.         ret
  1105.