forked from KolibriOS/kolibrios
22602ae43d
git-svn-id: svn://kolibrios.org@1917 a494cfbc-eb01-0410-851d-a64ba20cac60
1436 lines
28 KiB
NASM
1436 lines
28 KiB
NASM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;; ;;
|
|
;; Copyright (C) KolibriOS team 2006-2008. All rights reserved. ;;
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
;; ;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; Serge 2006-2008
|
|
; email: infinity_sound@mail.ru
|
|
|
|
format MS COFF
|
|
|
|
DEBUG equ 1
|
|
|
|
|
|
include 'proc32.inc'
|
|
include 'main.inc'
|
|
include 'imports.inc'
|
|
|
|
|
|
CURRENT_API equ 0x0101 ;1.01
|
|
COMPATIBLE_API equ 0x0100 ;1.00
|
|
|
|
API_VERSION equ (COMPATIBLE_API shl 16) or CURRENT_API
|
|
SOUND_VERSION equ CURRENT_API
|
|
|
|
|
|
FORCE_MMX equ 0 ;set to 1 to force use mmx or
|
|
FORCE_MMX_128 equ 0 ;integer sse2 extensions
|
|
;and reduce driver size
|
|
|
|
;USE_SSE equ 0
|
|
|
|
USE_SSE2_MIXER equ 0 ;floating point mixer. Disabled by default
|
|
|
|
OS_BASE equ 0x80000000
|
|
|
|
CAPS_SSE2 equ 26
|
|
PG_SW equ 0x003
|
|
|
|
public START
|
|
public service_proc
|
|
public version
|
|
|
|
RT_INP_EMPTY equ 0xFF000001
|
|
RT_OUT_EMPTY equ 0xFF000002
|
|
RT_INP_FULL equ 0xFF000003
|
|
RT_OUT_FULL equ 0xFF000004
|
|
|
|
EVENT_WATCHED equ 0x10000000
|
|
EVENT_SIGNALED equ 0x20000000
|
|
MANUAL_RESET equ 0x40000000
|
|
MANUAL_DESTROY equ 0x80000000
|
|
|
|
DEV_PLAY equ 1
|
|
DEV_STOP equ 2
|
|
DEV_CALLBACK equ 3
|
|
DEV_GET_POS equ 9
|
|
|
|
struc IOCTL
|
|
{ .handle dd ?
|
|
.io_code dd ?
|
|
.input dd ?
|
|
.inp_size dd ?
|
|
.output dd ?
|
|
.out_size dd ?
|
|
}
|
|
|
|
virtual at 0
|
|
IOCTL IOCTL
|
|
end virtual
|
|
|
|
section '.flat' code readable align 16
|
|
|
|
proc START stdcall, state:dword
|
|
|
|
cmp [state], 1
|
|
jne .exit
|
|
|
|
stdcall GetService, szSound
|
|
test eax, eax
|
|
jz .fail
|
|
mov [hSound], eax
|
|
|
|
stdcall KernelAlloc, 16*512
|
|
test eax, eax
|
|
jz .out_of_mem
|
|
mov [mix_buff], eax
|
|
|
|
mov eax, str.fd-FD_OFFSET
|
|
mov [str.fd], eax
|
|
mov [str.bk], eax
|
|
|
|
if FORCE_MMX
|
|
if FORCE_MMX_128
|
|
display 'Use only FORCE_MMX or FORCE_MMX_128 not both together',13,10
|
|
stop
|
|
end if
|
|
mov [mix_2_core], mmx_mix_2
|
|
mov [mix_3_core], mmx_mix_3
|
|
mov [mix_4_core], mmx_mix_4
|
|
end if
|
|
|
|
if FORCE_MMX_128
|
|
if FORCE_MMX
|
|
display 'Use only FORCE_MMX or FORCE_MMX_128 not both together',13,10
|
|
stop
|
|
end if
|
|
mov [mix_2_core], mmx128_mix_2
|
|
mov [mix_3_core], mmx128_mix_3
|
|
mov [mix_4_core], mmx128_mix_4
|
|
end if
|
|
|
|
if 0
|
|
|
|
if ~(FORCE_MMX or FORCE_MMX_128) ;autodetect
|
|
mov eax, 1
|
|
cpuid
|
|
bt edx, CAPS_SSE2
|
|
jc .mmx128
|
|
;old 64-bit mmx
|
|
mov [mix_2_core], mmx_mix_2
|
|
mov [mix_3_core], mmx_mix_3
|
|
mov [mix_4_core], mmx_mix_4
|
|
jmp @F
|
|
.mmx128: ;128-bit integer sse2 extensions
|
|
mov [mix_2_core], mmx128_mix_2
|
|
mov [mix_3_core], mmx128_mix_3
|
|
mov [mix_4_core], mmx128_mix_4
|
|
@@:
|
|
end if
|
|
|
|
end if
|
|
stdcall set_handler, [hSound], new_mix
|
|
mov [eng_state], SND_STOP
|
|
stdcall RegService, szInfinity, service_proc
|
|
ret
|
|
.fail:
|
|
if DEBUG
|
|
mov esi, msgFail
|
|
call SysMsgBoardStr
|
|
end if
|
|
.exit:
|
|
xor eax, eax
|
|
ret
|
|
|
|
.out_of_mem:
|
|
if DEBUG
|
|
mov esi, msgMem
|
|
call SysMsgBoardStr
|
|
end if
|
|
xor eax, eax
|
|
ret
|
|
endp
|
|
|
|
handle equ IOCTL.handle
|
|
io_code equ IOCTL.io_code
|
|
input equ IOCTL.input
|
|
inp_size equ IOCTL.inp_size
|
|
output equ IOCTL.output
|
|
out_size equ IOCTL.out_size
|
|
|
|
|
|
|
|
align 4
|
|
|
|
srv_calls dd service_proc.srv_getversion ; 0
|
|
dd service_proc.snd_create_buff ; 1
|
|
dd service_proc.snd_destroy_buff ; 2
|
|
dd service_proc.snd_setformat ; 3
|
|
dd service_proc.snd_getformat ; 4
|
|
dd service_proc.snd_reset ; 5
|
|
dd service_proc.snd_setpos ; 6
|
|
dd service_proc.snd_getpos ; 7
|
|
dd service_proc.snd_setbuff ; 8
|
|
dd service_proc.snd_out ; 9
|
|
dd service_proc.snd_play ; 10
|
|
dd service_proc.snd_stop ; 11
|
|
dd service_proc.snd_setvolume ; 12
|
|
dd service_proc.snd_getvolume ; 13
|
|
dd service_proc.snd_setpan ; 14
|
|
dd service_proc.snd_getpan ; 15
|
|
dd service_proc.snd_getbuffsize ; 16
|
|
dd service_proc.snd_getfreespace ; 17
|
|
dd service_proc.snd_settimebase ; 18
|
|
dd service_proc.snd_gettimestamp ; 19
|
|
srv_calls_end:
|
|
|
|
proc service_proc stdcall, ioctl:dword
|
|
|
|
mov edi, [ioctl]
|
|
mov eax, [edi+io_code]
|
|
|
|
cmp eax, (srv_calls_end-srv_calls)/4
|
|
ja .fail
|
|
|
|
cmp eax, SND_DESTROY_BUFF
|
|
jb @F
|
|
|
|
; cmp [edi+inp_size], 4
|
|
; jb .fali
|
|
|
|
mov ebx, [edi+input]
|
|
mov edx, [ebx]
|
|
|
|
cmp [edx+STREAM.magic], 'WAVE'
|
|
jne .fail
|
|
|
|
cmp [edx+STREAM.size], STREAM.sizeof
|
|
jne .fail
|
|
|
|
@@:
|
|
jmp [srv_calls+eax*4]
|
|
|
|
|
|
.fail:
|
|
mov eax, -1
|
|
ret
|
|
|
|
align 4
|
|
.srv_getversion:
|
|
mov eax, [edi+output]
|
|
cmp [edi+out_size], 4
|
|
jne .fail
|
|
mov eax, [eax]
|
|
mov [eax], dword API_VERSION
|
|
xor eax, eax
|
|
ret
|
|
|
|
align 4
|
|
.snd_create_buff:
|
|
mov ebx, [edi+input]
|
|
stdcall CreateBuffer,[ebx],[ebx+4]
|
|
mov edi, [ioctl]
|
|
mov ecx, [edi+output]
|
|
mov ecx, [ecx]
|
|
mov [ecx], ebx
|
|
ret
|
|
|
|
align 4
|
|
.snd_destroy_buff:
|
|
mov eax, edx
|
|
call DestroyBuffer
|
|
ret
|
|
|
|
align 4
|
|
.snd_setformat:
|
|
stdcall SetFormat, edx,[ebx+4]
|
|
ret
|
|
|
|
align 4
|
|
.snd_getformat:
|
|
movzx eax, word [edx+STREAM.format]
|
|
mov ecx, [edi+output]
|
|
mov ecx, [ecx]
|
|
mov [ecx], eax
|
|
xor eax, eax
|
|
ret
|
|
|
|
align 4
|
|
.snd_reset:
|
|
stdcall ResetBuffer,edx,[ebx+4]
|
|
ret
|
|
|
|
align 4
|
|
.snd_setpos:
|
|
stdcall SetBufferPos,edx,[ebx+4]
|
|
ret
|
|
|
|
align 4
|
|
.snd_getpos:
|
|
stdcall GetBufferPos, edx
|
|
mov edi, [ioctl]
|
|
mov ecx, [edi+output]
|
|
mov ecx, [ecx]
|
|
mov [ecx], ebx
|
|
ret
|
|
|
|
align 4
|
|
.snd_setbuff:
|
|
mov eax, [ebx+4]
|
|
stdcall set_buffer, edx,eax,[ebx+8],[ebx+12]
|
|
ret
|
|
|
|
align 4
|
|
.snd_out:
|
|
mov eax, [ebx+4]
|
|
stdcall wave_out, edx,eax,[ebx+8]
|
|
ret
|
|
|
|
align 4
|
|
.snd_play:
|
|
stdcall play_buffer, edx,[ebx+4]
|
|
ret
|
|
|
|
align 4
|
|
.snd_stop:
|
|
stdcall stop_buffer, edx
|
|
ret
|
|
|
|
align 4
|
|
.snd_setvolume:
|
|
stdcall SetBufferVol,edx,[ebx+4],[ebx+8]
|
|
ret
|
|
|
|
align 4
|
|
.snd_getvolume:
|
|
mov eax, [edi+output]
|
|
mov ecx, [eax]
|
|
mov eax, [eax+4]
|
|
stdcall GetBufferVol,edx,ecx,eax
|
|
ret
|
|
align 4
|
|
.snd_setpan:
|
|
stdcall SetBufferPan,edx,[ebx+4]
|
|
ret
|
|
|
|
align 4
|
|
.snd_getpan:
|
|
mov eax, [edx+STREAM.pan]
|
|
mov ebx, [edi+output]
|
|
mov ebx, [ebx]
|
|
mov [ebx], eax
|
|
xor eax, eax
|
|
ret
|
|
|
|
align 4
|
|
.snd_getbuffsize:
|
|
mov eax, [edx+STREAM.in_size]
|
|
mov ecx, [edi+output]
|
|
mov ecx, [ecx]
|
|
mov [ecx], eax
|
|
xor eax, eax
|
|
ret
|
|
|
|
align 4
|
|
.snd_getfreespace:
|
|
test [edx+STREAM.format], PCM_OUT
|
|
jz .fail
|
|
|
|
mov ebx, [edx+STREAM.in_free]
|
|
mov ecx, [edi+output]
|
|
mov [ecx], ebx
|
|
xor eax, eax
|
|
ret
|
|
align 4
|
|
.snd_settimebase:
|
|
cmp [edi+inp_size], 12
|
|
jne .fail
|
|
|
|
mov eax, [ebx]
|
|
mov ebx, [ebx+4]
|
|
mov dword [edx+STREAM.time_base], eax
|
|
mov dword [edx+STREAM.time_base+4], ebx
|
|
xor eax, eax
|
|
ret
|
|
|
|
.snd_gettimestamp:
|
|
cmp [edi+out_size], 8
|
|
jne .fail
|
|
|
|
pushfd
|
|
cli
|
|
|
|
xor ebx, ebx
|
|
push 48
|
|
push ebx ; local storage
|
|
|
|
cmp [edx+STREAM.flags], SND_STOP
|
|
je @F
|
|
|
|
mov eax, esp
|
|
|
|
push edx
|
|
push edi
|
|
|
|
push 4 ;.out_size
|
|
push eax ;.output
|
|
push ebx ;.inp_size
|
|
push ebx ;.input
|
|
push DEV_GET_POS ;.code
|
|
push dword [hSound] ;.handle
|
|
mov eax, esp
|
|
|
|
stdcall ServiceHandler, eax
|
|
add esp, 6*4
|
|
|
|
pop edi
|
|
pop edx
|
|
|
|
test eax, eax
|
|
jz @F
|
|
|
|
mov dword [esp], 0 ; clear offset
|
|
@@:
|
|
mov edi, [edi+output]
|
|
|
|
emms
|
|
fild qword [edx+STREAM.time_stamp]
|
|
fiadd dword [esp] ; primary buffer offset
|
|
fidiv dword [esp+4] ; total_samples / frequency
|
|
fadd qword [edx+STREAM.time_base]
|
|
fstp qword [edi]
|
|
add esp, 8
|
|
|
|
popfd
|
|
|
|
xor eax, eax
|
|
ret
|
|
endp
|
|
|
|
|
|
restore handle
|
|
restore io_code
|
|
restore input
|
|
restore inp_size
|
|
restore output
|
|
restore out_size
|
|
|
|
align 4
|
|
proc CreateBuffer stdcall, format:dword, size:dword
|
|
locals
|
|
str dd ?
|
|
ring_size dd ?
|
|
ring_pages dd ?
|
|
endl
|
|
|
|
mov eax, [format]
|
|
cmp ax, PCM_1_8_8
|
|
ja .fail
|
|
|
|
test eax, PCM_OUT
|
|
jnz .test_out
|
|
test eax, PCM_RING
|
|
jnz .test_ring
|
|
;staic
|
|
test eax, PCM_STATIC
|
|
jz .test_out ;use PCM_OUT as default format
|
|
jmp .test_ok
|
|
.test_out:
|
|
test eax, PCM_RING+PCM_STATIC
|
|
jnz .fail
|
|
or [format], PCM_OUT ;force set
|
|
jmp .test_ok
|
|
.test_ring:
|
|
test eax, PCM_OUT+PCM_STATIC
|
|
jnz .fail
|
|
.test_ok:
|
|
|
|
call GetPid
|
|
mov ebx, eax
|
|
mov eax, STREAM.sizeof
|
|
|
|
call CreateObject
|
|
test eax, eax
|
|
jz .fail
|
|
mov [str], eax
|
|
|
|
mov ebx, [format]
|
|
mov [eax+STREAM.format], ebx
|
|
|
|
xor ecx, ecx
|
|
movzx ebx, bx
|
|
cmp ebx, 19
|
|
jb @f
|
|
mov ecx, 0x80808080
|
|
@@:
|
|
mov [eax+STREAM.r_silence], ecx
|
|
|
|
shl ebx, 2
|
|
lea ebx, [ebx+ebx*2] ;ebx*=12
|
|
|
|
mov ecx, [resampler_params+ebx]
|
|
mov edx, [resampler_params+ebx+4]
|
|
mov esi, [resampler_params+ebx+8]
|
|
|
|
mov [eax+STREAM.r_size],ecx
|
|
mov [eax+STREAM.r_dt], edx
|
|
mov [eax+STREAM.resample], esi
|
|
xor ecx, ecx
|
|
mov [eax+STREAM.l_vol], ecx
|
|
mov [eax+STREAM.r_vol], ecx
|
|
mov dword [eax+STREAM.l_amp], 0x7FFF7FFF
|
|
mov [eax+STREAM.pan], ecx
|
|
|
|
test [format], PCM_STATIC
|
|
jnz .static
|
|
|
|
; ring and waveout
|
|
|
|
mov ebx, 0x10000
|
|
test [format], PCM_RING
|
|
jz .waveout
|
|
|
|
mov ebx, [eax+STREAM.r_size]
|
|
add ebx, 4095
|
|
and ebx, -4096
|
|
add ebx, ebx
|
|
.waveout:
|
|
mov [ring_size], ebx
|
|
mov eax, ebx
|
|
shr ebx, 12
|
|
mov [ring_pages], ebx
|
|
|
|
stdcall CreateRingBuffer, eax, PG_SW
|
|
|
|
mov edi, [str]
|
|
mov ecx, [ring_size]
|
|
mov [edi+STREAM.in_base], eax
|
|
mov [edi+STREAM.in_size], ecx
|
|
add eax, 128
|
|
mov [edi+STREAM.in_wp], eax
|
|
mov [edi+STREAM.in_rp], eax
|
|
mov [edi+STREAM.in_count], 0
|
|
|
|
mov [edi+STREAM.in_free], ecx
|
|
add eax, ecx
|
|
mov [edi+STREAM.in_top], eax
|
|
|
|
jmp .out_buff
|
|
.static:
|
|
mov ecx, [size]
|
|
add ecx, 128 ;resampler required
|
|
mov [eax+STREAM.in_size], ecx
|
|
stdcall KernelAlloc, ecx
|
|
|
|
mov edi, [str]
|
|
mov [edi+STREAM.in_base], eax
|
|
add eax, 128
|
|
mov [edi+STREAM.in_wp], eax
|
|
mov [edi+STREAM.in_rp], eax
|
|
mov ebx, [size]
|
|
mov [edi+STREAM.in_count], ebx
|
|
mov [edi+STREAM.in_free], ebx
|
|
add eax, ebx
|
|
mov [edi+STREAM.in_top], eax
|
|
|
|
.out_buff:
|
|
stdcall AllocKernelSpace, dword 128*1024
|
|
|
|
mov edi, [str]
|
|
xor ebx, ebx
|
|
|
|
mov [edi+STREAM.out_base], eax
|
|
mov [edi+STREAM.out_wp], eax
|
|
mov [edi+STREAM.out_rp], eax
|
|
mov [edi+STREAM.out_count], ebx
|
|
add eax, 64*1024
|
|
mov [edi+STREAM.out_top], eax
|
|
|
|
mov dword [edi+STREAM.time_base], ebx
|
|
mov dword [edi+STREAM.time_base+4], ebx
|
|
|
|
mov dword [edi+STREAM.time_stamp], ebx
|
|
mov dword [edi+STREAM.time_stamp+4], ebx
|
|
mov dword [edi+STREAM.last_ts], ebx
|
|
|
|
stdcall AllocPages, dword 64/4
|
|
mov edi, [str]
|
|
mov ebx, [edi+STREAM.out_base]
|
|
mov ecx, 16
|
|
or eax, PG_SW
|
|
push eax
|
|
push ebx
|
|
call CommitPages ;eax, ebx, ecx
|
|
mov ecx, 16
|
|
pop ebx
|
|
pop eax
|
|
add ebx, 64*1024
|
|
call CommitPages ;double mapped
|
|
|
|
mov edi, [str]
|
|
mov ecx, [edi+STREAM.in_top]
|
|
mov edi, [edi+STREAM.in_base]
|
|
sub ecx, edi
|
|
xor eax, eax
|
|
shr ecx, 2
|
|
cld
|
|
rep stosd
|
|
|
|
mov edi, [str]
|
|
mov edi, [edi+STREAM.out_base]
|
|
mov ecx, (64*1024)/4
|
|
rep stosd
|
|
|
|
xor esi, esi
|
|
mov ecx, MANUAL_DESTROY
|
|
call CreateEvent
|
|
|
|
mov ebx, [str]
|
|
mov [ebx+STREAM.notify_event], eax
|
|
mov [ebx+STREAM.notify_id], edx
|
|
|
|
mov [ebx+STREAM.magic], 'WAVE'
|
|
mov [ebx+STREAM.destroy], DestroyBuffer.destroy
|
|
mov [ebx+STREAM.size], STREAM.sizeof
|
|
mov [ebx+STREAM.flags], SND_STOP
|
|
|
|
pushf
|
|
cli
|
|
mov eax, str.fd-FD_OFFSET
|
|
mov edx, [eax+STREAM.str_fd]
|
|
mov [ebx+STREAM.str_fd], edx
|
|
mov [ebx+STREAM.str_bk], eax
|
|
mov [eax+STREAM.str_fd], ebx
|
|
mov [edx+STREAM.str_bk], ebx
|
|
popf
|
|
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
xor ebx, ebx
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
;param
|
|
; eax= buffer handle
|
|
|
|
align 4
|
|
DestroyBuffer:
|
|
.handle equ esp ;local
|
|
|
|
mov [eax+STREAM.flags], SND_STOP
|
|
.destroy:
|
|
push eax
|
|
|
|
pushfd
|
|
cli
|
|
mov ebx, [eax+STREAM.str_fd]
|
|
mov ecx, [eax+STREAM.str_bk]
|
|
mov [ebx+STREAM.str_bk], ecx
|
|
mov [ecx+STREAM.str_fd], ebx
|
|
popf
|
|
|
|
stdcall KernelFree, [eax+STREAM.in_base]
|
|
mov eax, [.handle]
|
|
stdcall KernelFree, [eax+STREAM.out_base]
|
|
|
|
pop eax ;restore stack
|
|
call DestroyObject ;eax= stream
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
restore .handle
|
|
|
|
align 4
|
|
proc SetFormat stdcall, str:dword, format:dword
|
|
|
|
cmp word [format], PCM_1_8_8
|
|
ja .fail
|
|
|
|
mov edx, [str]
|
|
mov [edx+STREAM.flags], SND_STOP
|
|
|
|
test [edx+STREAM.format], PCM_RING
|
|
jnz .fail
|
|
|
|
; mov eax,[edx+STREAM.out_base]
|
|
; mov [edx+STREAM.out_wp], eax
|
|
; mov [edx+STREAM.out_rp], eax
|
|
; mov [edx+STREAM.out_count], 0
|
|
|
|
movzx eax, word [format]
|
|
mov word [edx+STREAM.format], ax
|
|
|
|
xor ebx, ebx
|
|
cmp eax, 19
|
|
jb @f
|
|
mov ebx, 0x80808080
|
|
@@:
|
|
mov [edx+STREAM.r_silence], ebx
|
|
|
|
shl eax, 2
|
|
lea eax, [eax+eax*2] ;eax*=12
|
|
|
|
mov edi, [resampler_params+eax]
|
|
mov ecx, [resampler_params+eax+4]
|
|
mov ebx, [resampler_params+eax+8]
|
|
|
|
mov [edx+STREAM.r_size],edi
|
|
mov [edx+STREAM.r_dt], ecx
|
|
mov [edx+STREAM.resample], ebx
|
|
|
|
mov edi, [edx+STREAM.in_base]
|
|
mov ecx, 128/4
|
|
mov eax, [edx+STREAM.r_silence]
|
|
cld
|
|
rep stosd
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
; for static buffers only
|
|
; use waveout for streams
|
|
|
|
align 4
|
|
proc set_buffer stdcall, str:dword,src:dword,offs:dword,size:dword
|
|
|
|
mov edx, [str]
|
|
test [edx+STREAM.format], PCM_OUT
|
|
jnz .fail
|
|
|
|
mov esi, [src]
|
|
mov edi, [offs]
|
|
add edi, [edx+STREAM.in_base]
|
|
add edi, 128
|
|
|
|
cmp edi, [edx+STREAM.in_top]
|
|
jae .fail
|
|
|
|
mov ecx, [size]
|
|
lea ebx, [ecx+edi]
|
|
sub ebx, [edx+STREAM.in_top]
|
|
jb @F
|
|
sub ecx, ebx
|
|
@@:
|
|
shr ecx, 2
|
|
cld
|
|
rep movsd
|
|
xor eax,eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
; for stream buffers only
|
|
|
|
align 4
|
|
proc wave_out stdcall, str:dword,src:dword,size:dword
|
|
locals
|
|
state_saved dd ?
|
|
fpu_state rb 528
|
|
endl
|
|
|
|
mov edx, [str]
|
|
mov eax, [edx+STREAM.format]
|
|
test eax, PCM_OUT
|
|
jz .fail
|
|
|
|
cmp ax, PCM_ALL
|
|
je .fail
|
|
|
|
mov esi,[src]
|
|
test esi, esi
|
|
jz .fail
|
|
|
|
cmp esi, OS_BASE
|
|
jae .fail
|
|
|
|
mov [state_saved], 0
|
|
|
|
.main_loop:
|
|
mov edx, [str]
|
|
|
|
mov ebx, [size]
|
|
test ebx, ebx
|
|
jz .done
|
|
|
|
cmp [edx+STREAM.flags], SND_STOP
|
|
jne .fill
|
|
|
|
mov edi, [edx+STREAM.in_base]
|
|
mov ecx, 128/4
|
|
mov eax, [edx+STREAM.r_silence]
|
|
cld
|
|
rep stosd
|
|
|
|
mov ecx, [edx+STREAM.in_size]
|
|
sub ecx, 128
|
|
mov [edx+STREAM.in_wp], edi
|
|
mov [edx+STREAM.in_rp], edi
|
|
mov [edx+STREAM.in_count], 0
|
|
mov [edx+STREAM.in_free], ecx
|
|
|
|
mov eax,[edx+STREAM.out_base]
|
|
mov [edx+STREAM.out_wp], eax
|
|
mov [edx+STREAM.out_rp], eax
|
|
mov [edx+STREAM.out_count], 0
|
|
.fill:
|
|
cli
|
|
|
|
mov ecx, [edx+STREAM.in_free]
|
|
test ecx, ecx
|
|
jz .wait
|
|
|
|
cmp ecx, ebx
|
|
jbe @F
|
|
|
|
mov ecx, ebx
|
|
@@:
|
|
sub [size], ecx
|
|
add [edx+STREAM.in_count], ecx
|
|
sub [edx+STREAM.in_free], ecx
|
|
|
|
shr ecx, 2
|
|
mov edi, [edx+STREAM.in_wp]
|
|
mov esi, [src]
|
|
cld
|
|
rep movsd
|
|
|
|
mov [src], esi
|
|
cmp edi, [edx+STREAM.in_top]
|
|
jb @F
|
|
sub edi, [edx+STREAM.in_size]
|
|
@@:
|
|
mov [edx+STREAM.in_wp], edi
|
|
|
|
cmp [edx+STREAM.out_count], 32768
|
|
jae .skip
|
|
|
|
cmp [state_saved], 0
|
|
jne @F
|
|
lea eax, [fpu_state+15]
|
|
and eax, -16
|
|
call FpuSave
|
|
mov [state_saved], 1
|
|
@@:
|
|
stdcall refill, edx
|
|
|
|
.skip:
|
|
sti
|
|
mov edx, [str]
|
|
mov [edx+STREAM.flags], SND_PLAY
|
|
cmp [eng_state], SND_PLAY
|
|
je .main_loop
|
|
|
|
stdcall dev_play, [hSound]
|
|
mov [eng_state], SND_PLAY
|
|
jmp .main_loop
|
|
.wait:
|
|
sti
|
|
mov edx, [str]
|
|
mov eax, [edx+STREAM.notify_event]
|
|
mov ebx, [edx+STREAM.notify_id]
|
|
call WaitEvent ;eax ebx
|
|
jmp .main_loop
|
|
.done:
|
|
cmp [state_saved], 1
|
|
jne @F
|
|
|
|
lea eax, [fpu_state+15]
|
|
and eax, -16
|
|
call FpuRestore
|
|
@@:
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
; both static and stream
|
|
; reset all but not clear buffers
|
|
|
|
|
|
; flags reserved
|
|
; RESET_INPUT equ 1 ;reserved reset and clear input buffer
|
|
; RESET_OUTPUT equ 2 ;reserved reset and clear output buffer
|
|
; RESET_ALL equ 3
|
|
|
|
|
|
align 4
|
|
proc ResetBuffer stdcall, str:dword, flags:dword
|
|
|
|
mov edx, [str]
|
|
mov [edx+STREAM.flags], SND_STOP
|
|
|
|
mov edi, [edx+STREAM.in_base]
|
|
mov ecx, 128/4
|
|
mov eax, [edx+STREAM.r_silence]
|
|
cld
|
|
rep stosd
|
|
|
|
mov [edx+STREAM.in_wp], edi
|
|
mov [edx+STREAM.in_rp], edi
|
|
|
|
test [edx+STREAM.flags], PCM_STATIC
|
|
jnz .static
|
|
mov [edx+STREAM.in_count], 0
|
|
jmp @F
|
|
.static:
|
|
mov eax, [edx+STREAM.in_size]
|
|
mov [edx+STREAM.in_count], eax
|
|
@@:
|
|
|
|
mov eax, [edx+STREAM.in_size]
|
|
sub eax, 128
|
|
mov [edx+STREAM.in_free], eax
|
|
|
|
xor eax, eax
|
|
mov ebx,[edx+STREAM.out_base]
|
|
mov [edx+STREAM.out_wp], ebx
|
|
mov [edx+STREAM.out_rp], ebx
|
|
mov [edx+STREAM.out_count], eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
; for static buffers only
|
|
|
|
align 4
|
|
proc SetBufferPos stdcall, str:dword, pos:dword
|
|
|
|
mov edx, [str]
|
|
test [edx+STREAM.format], PCM_STATIC
|
|
jz .fail
|
|
|
|
mov [edx+STREAM.flags], SND_STOP
|
|
|
|
mov eax, [pos]
|
|
add eax, [edx+STREAM.in_base]
|
|
mov ebx, [edx+STREAM.in_top]
|
|
add eax, 128
|
|
|
|
cmp eax, ebx
|
|
jae .fail
|
|
|
|
mov [edx+STREAM.in_rp], eax
|
|
sub ebx, eax
|
|
mov [edx+STREAM.in_count], ebx
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
align 4
|
|
proc GetBufferPos stdcall, str:dword
|
|
|
|
mov edx, [str]
|
|
test [edx+STREAM.format], PCM_STATIC
|
|
jz .fail
|
|
|
|
mov ebx, [edx+STREAM.in_rp]
|
|
sub ebx, [edx+STREAM.in_base]
|
|
sub ebx, 128
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
xor ebx,ebx
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
; both
|
|
|
|
align 4
|
|
proc SetBufferVol stdcall, str:dword,l_vol:dword,r_vol:dword
|
|
|
|
mov edx, [str]
|
|
stdcall set_vol_param,[l_vol],[r_vol],[edx+STREAM.pan]
|
|
ret
|
|
endp
|
|
|
|
|
|
proc minw stdcall, arg1:dword, arg2:dword
|
|
mov ax, word [arg1]
|
|
cmp ax, word [arg2]
|
|
jle @f
|
|
mov eax, [arg2]
|
|
@@:
|
|
ret
|
|
endp
|
|
|
|
proc maxw stdcall, arg1:dword, arg2:dword
|
|
mov ax, word [arg1]
|
|
cmp ax, word [arg2]
|
|
jge @f
|
|
mov eax, [arg2]
|
|
@@:
|
|
ret
|
|
endp
|
|
|
|
|
|
proc set_vol_param stdcall, l_vol:dword,r_vol:dword,pan:dword
|
|
locals
|
|
_600 dd ?
|
|
_32767 dd ?
|
|
state rb 108
|
|
endl
|
|
|
|
mov [_600], 0x44160000 ;600.0
|
|
mov [_32767], 32767
|
|
|
|
lea ebx, [state]
|
|
fnsave [ebx]
|
|
|
|
stdcall minw, [l_vol], [vol_max]
|
|
stdcall maxw, eax, [vol_min]
|
|
mov [l_vol], eax
|
|
mov [edx+STREAM.l_vol], eax
|
|
stdcall minw, [r_vol], [vol_max+4]
|
|
stdcall maxw, eax, [vol_min+4]
|
|
mov [r_vol], eax
|
|
mov [edx+STREAM.r_vol], eax
|
|
|
|
stdcall minw, [pan], [pan_max]
|
|
stdcall maxw, eax, [vol_min]
|
|
mov [edx+STREAM.pan], eax
|
|
|
|
cmp word [edx+STREAM.pan], 0
|
|
jl @f
|
|
|
|
mov ebx, [l_vol]
|
|
sub ebx, eax
|
|
stdcall minw, ebx, [vol_max]
|
|
stdcall maxw, eax, [vol_min]
|
|
mov [l_vol], eax
|
|
jmp .calc_amp
|
|
@@:
|
|
mov ebx, [r_vol]
|
|
add ebx, [pan]
|
|
stdcall minw, ebx, [vol_max+4]
|
|
stdcall maxw, eax, [vol_min+4]
|
|
mov [r_vol], eax
|
|
.calc_amp:
|
|
emms
|
|
fild word [l_vol]
|
|
|
|
call .calc
|
|
|
|
fistp word [edx+STREAM.l_amp]
|
|
fstp dword [edx+STREAM.l_amp_f]
|
|
fstp st0
|
|
|
|
fild word [r_vol]
|
|
|
|
call .calc
|
|
|
|
fistp word [edx+STREAM.r_amp]
|
|
fstp dword [edx+STREAM.r_amp_f]
|
|
fstp st0
|
|
|
|
fnclex
|
|
lea ebx, [state]
|
|
frstor [ebx]
|
|
|
|
xor eax, eax
|
|
inc eax
|
|
ret
|
|
.calc:
|
|
fdiv dword [_600]
|
|
fld st0
|
|
frndint
|
|
fxch st1
|
|
fsub st, st1
|
|
f2xm1
|
|
fld1
|
|
faddp st1, st0
|
|
fscale
|
|
fld st0
|
|
fimul dword [_32767]
|
|
ret 0
|
|
endp
|
|
|
|
|
|
align 4
|
|
proc GetBufferVol stdcall, str:dword,p_lvol:dword,p_rvol:dword
|
|
|
|
mov edx, [str]
|
|
mov eax, [p_lvol]
|
|
movsx ecx, word [edx+STREAM.l_vol]
|
|
mov [eax], ecx
|
|
|
|
mov eax, [p_rvol]
|
|
movsx ecx, word [edx+STREAM.r_vol]
|
|
mov [eax], ecx
|
|
xor eax, eax
|
|
ret
|
|
endp
|
|
|
|
align 4
|
|
proc SetBufferPan stdcall, str:dword,pan:dword
|
|
|
|
mov edx, [str]
|
|
stdcall set_vol_param,[edx+STREAM.l_vol],\
|
|
[edx+STREAM.r_vol],[pan]
|
|
ret
|
|
endp
|
|
|
|
; for static and ring buffers only
|
|
|
|
align 4
|
|
proc play_buffer stdcall, str:dword, flags:dword
|
|
|
|
mov ebx, [str]
|
|
mov eax, [ebx+STREAM.format]
|
|
test eax, PCM_OUT
|
|
jnz .fail
|
|
|
|
cmp ax, PCM_ALL
|
|
je .fail
|
|
|
|
mov [ebx+STREAM.flags], SND_PLAY
|
|
cmp [eng_state], SND_PLAY
|
|
je .done
|
|
|
|
stdcall dev_play, [hSound]
|
|
mov [eng_state], SND_PLAY
|
|
.done:
|
|
test [flags], PLAY_SYNC
|
|
jz @F
|
|
|
|
mov edx, [str]
|
|
.wait:
|
|
mov eax, [edx+STREAM.notify_event]
|
|
mov ebx, [edx+STREAM.notify_id]
|
|
call WaitEvent ;eax ebx
|
|
|
|
mov edx, [str]
|
|
cmp [edx+STREAM.flags], SND_STOP
|
|
jne .wait
|
|
@@:
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
; for static and ring buffers only
|
|
|
|
align 4
|
|
proc stop_buffer stdcall, str:dword
|
|
|
|
mov edx, [str]
|
|
test [edx+STREAM.format], PCM_STATIC+PCM_RING
|
|
jz .fail
|
|
|
|
mov [edx+STREAM.flags], SND_STOP
|
|
|
|
; stdcall [ServiceHandler], [hSound], dword DEV_STOP, 0
|
|
|
|
mov eax, [edx+STREAM.notify_event]
|
|
mov ebx, [edx+STREAM.notify_id]
|
|
call ClearEvent ;eax ebx
|
|
|
|
xor eax, eax
|
|
ret
|
|
.fail:
|
|
or eax, -1
|
|
ret
|
|
endp
|
|
|
|
; param
|
|
; eax= mix_list
|
|
|
|
align 4
|
|
do_mix_list:
|
|
|
|
xor edx, edx
|
|
mov esi, str.fd-FD_OFFSET
|
|
mov ebx, [esi+STREAM.str_fd]
|
|
@@:
|
|
cmp ebx, esi
|
|
je .done
|
|
|
|
cmp [ebx+STREAM.magic], 'WAVE'
|
|
jne .next
|
|
|
|
cmp [ebx+STREAM.size], STREAM.sizeof
|
|
jne .next
|
|
|
|
cmp [ebx+STREAM.flags], SND_PLAY;
|
|
jne .next
|
|
|
|
mov ecx, [ebx+STREAM.out_count]
|
|
test ecx, ecx
|
|
jnz .l1
|
|
|
|
test [ebx+STREAM.format], PCM_RING
|
|
jnz .next
|
|
mov [ebx+STREAM.flags], SND_STOP
|
|
jmp .next
|
|
.l1:
|
|
cmp ecx, 512
|
|
jae .add_buff
|
|
|
|
mov edi, [ebx+STREAM.out_rp]
|
|
add edi, ecx
|
|
sub ecx, 512
|
|
neg ecx
|
|
push eax
|
|
xor eax, eax
|
|
cld
|
|
rep stosb
|
|
pop eax
|
|
|
|
mov [ebx+STREAM.out_count], 512
|
|
|
|
.add_buff:
|
|
mov ecx, [ebx+STREAM.out_rp]
|
|
mov [eax],ecx
|
|
|
|
if USE_SSE2_MIXER
|
|
mov edi, dword [ebx+STREAM.l_amp_f]
|
|
mov [eax+4], edi
|
|
mov edi, dword [ebx+STREAM.r_amp_f]
|
|
mov [eax+8], edi
|
|
else
|
|
mov edi, dword [ebx+STREAM.l_amp]
|
|
mov [eax+4], edi
|
|
end if
|
|
add [ebx+STREAM.out_rp], 512
|
|
sub [ebx+STREAM.out_count], 512
|
|
|
|
add eax, 12
|
|
inc edx
|
|
.next:
|
|
mov ebx, [ebx+STREAM.str_fd]
|
|
jmp @B
|
|
.done:
|
|
mov eax, edx
|
|
ret
|
|
|
|
align 4
|
|
prepare_playlist:
|
|
|
|
xor edx, edx
|
|
mov [play_count], edx
|
|
mov esi, str.fd-FD_OFFSET
|
|
mov edi, [esi+STREAM.str_fd]
|
|
@@:
|
|
cmp edi, esi
|
|
je .done
|
|
|
|
cmp [edi+STREAM.magic], 'WAVE'
|
|
jne .next
|
|
|
|
cmp [edi+STREAM.size], STREAM.sizeof
|
|
jne .next
|
|
|
|
cmp [edi+STREAM.flags], SND_PLAY;
|
|
jne .next
|
|
|
|
mov [play_list+edx], edi
|
|
inc [play_count]
|
|
add edx, 4
|
|
.next:
|
|
mov edi, [edi+STREAM.str_fd]
|
|
jmp @B
|
|
.done:
|
|
ret
|
|
|
|
align 4
|
|
proc set_handler stdcall, hsrv:dword, handler_proc:dword
|
|
locals
|
|
handler dd ?
|
|
io_code dd ?
|
|
input dd ?
|
|
inp_size dd ?
|
|
output dd ?
|
|
out_size dd ?
|
|
val dd ?
|
|
endl
|
|
|
|
mov eax, [hsrv]
|
|
lea ecx, [handler_proc]
|
|
xor ebx, ebx
|
|
|
|
mov [handler], eax
|
|
mov [io_code], DEV_CALLBACK
|
|
mov [input], ecx
|
|
mov [inp_size], 4
|
|
mov [output], ebx
|
|
mov [out_size], 0
|
|
|
|
lea eax, [handler]
|
|
stdcall ServiceHandler, eax
|
|
ret
|
|
endp
|
|
|
|
align 4
|
|
proc dev_play stdcall, hsrv:dword
|
|
locals
|
|
handle dd ?
|
|
io_code dd ?
|
|
input dd ?
|
|
inp_size dd ?
|
|
output dd ?
|
|
out_size dd ?
|
|
val dd ?
|
|
endl
|
|
|
|
mov eax, [hsrv]
|
|
xor ebx, ebx
|
|
|
|
mov [handle], eax
|
|
mov [io_code], DEV_PLAY
|
|
mov [input], ebx
|
|
mov [inp_size], ebx
|
|
mov [output], ebx
|
|
mov [out_size], ebx
|
|
|
|
lea eax, [handle]
|
|
stdcall ServiceHandler, eax
|
|
ret
|
|
endp
|
|
|
|
if 0
|
|
align 4
|
|
dword2str:
|
|
mov esi, hex_buff
|
|
mov ecx, -8
|
|
@@:
|
|
rol eax, 4
|
|
mov ebx, eax
|
|
and ebx, 0x0F
|
|
mov bl, [ebx+hexletters]
|
|
mov [8+esi+ecx], bl
|
|
inc ecx
|
|
jnz @B
|
|
ret
|
|
|
|
hexletters db '0123456789ABCDEF'
|
|
hex_buff db 8 dup(0),13,10,0
|
|
|
|
end if
|
|
|
|
include 'mixer.asm'
|
|
include 'mix_mmx.inc'
|
|
include 'mix_sse2.inc'
|
|
|
|
;if USE_SSE
|
|
; include 'mix_sse.inc'
|
|
;end if
|
|
|
|
align 16
|
|
resampler_params:
|
|
;r_size r_dt resampler_func
|
|
dd 0,0,0 ; 0 PCM_ALL
|
|
dd 16384, 0, copy_stream ; 1 PCM_2_16_48
|
|
dd 8192, 0, m16_stereo ; 2 PCM_1_16_48
|
|
|
|
dd 16384, 30109, resample_2 ; 3 PCM_2_16_44
|
|
dd 8192, 30109, resample_1 ; 4 PCM_1_16_44
|
|
|
|
dd 16384, 21846, resample_2 ; 5 PCM_2_16_32
|
|
dd 8192, 21846, resample_1 ; 6 PCM_1_16_32
|
|
|
|
dd 16384, 16384, resample_2 ; 7 PCM_2_16_24
|
|
dd 8192, 16384, resample_1 ; 8 PCM_1_16_24
|
|
|
|
dd 8192, 15052, resample_2 ; 9 PCM_2_16_22
|
|
dd 4096, 15052, resample_1 ;10 PCM_1_16_22
|
|
|
|
dd 8192, 10923, resample_2 ;11 PCM_2_16_16
|
|
dd 4096, 10923, resample_1 ;12 PCM_1_16_16
|
|
|
|
dd 8192, 8192, resample_2 ;13 PCM_2_16_12
|
|
dd 4096, 8192, resample_1 ;14 PCM_1_16_12
|
|
|
|
dd 4096, 7527, resample_2 ;15 PCM_2_16_11
|
|
dd 2048, 7527, resample_1 ;16 PCM_1_16_11
|
|
|
|
dd 4096, 5462, resample_2 ;17 PCM_2_16_8
|
|
dd 2048, 5462, resample_1 ;18 PCM_1_16_8
|
|
|
|
dd 16384, 0, s8_stereo ;19 PCM_2_8_48
|
|
dd 8192, 0, m8_stereo ;20 PCM_1_8_48
|
|
|
|
dd 8192, 30109, resample_28 ;21 PCM_2_8_44
|
|
dd 4096, 30109, resample_18 ;22 PCM_1_8_44
|
|
|
|
dd 8192, 21846, resample_28 ;23 PCM_2_8_32
|
|
dd 4096, 21846, resample_18 ;24 PCM_1_8_32
|
|
|
|
dd 8192, 16384, resample_28 ;25 PCM_2_8_24
|
|
dd 4096, 16384, resample_18 ;26 PCM_1_8_24
|
|
|
|
dd 4096, 15052, resample_28 ;27 PCM_2_8_22
|
|
dd 2048, 15052, resample_18 ;28 PCM_1_8_22
|
|
|
|
dd 4096, 10923, resample_28 ;29 PCM_2_8_16
|
|
dd 2048, 10923, resample_18 ;30 PCM_1_8_16
|
|
|
|
dd 4096, 8192, resample_28 ;31 PCM_2_8_12
|
|
dd 2048, 8192, resample_18 ;32 PCM_1_8_12
|
|
|
|
dd 2048, 7527, resample_28 ;33 PCM_2_8_11
|
|
dd 1024, 7527, resample_18 ;34 PCM_1_8_11
|
|
|
|
dd 2048, 5462, resample_28 ;35 PCM_2_8_8
|
|
dd 1024, 5462, resample_18 ;36 PCM_1_8_8
|
|
|
|
m7 dw 0x8000,0x8000,0x8000,0x8000
|
|
mm80 dq 0x8080808080808080
|
|
mm_mask dq 0xFF00FF00FF00FF00
|
|
|
|
vol_max dd 0x00000000,0x00000000
|
|
vol_min dd 0x0000D8F0,0x0000D8F0
|
|
pan_max dd 0x00002710,0x00002710
|
|
|
|
;stream_map dd 0xFFFF ; 16
|
|
version dd (5 shl 16) or SOUND_VERSION
|
|
|
|
szInfinity db 'INFINITY',0
|
|
szSound db 'SOUND',0
|
|
|
|
if DEBUG
|
|
msgFail db 'Sound service not loaded',13,10,0
|
|
msgPlay db 'Play buffer',13,10,0
|
|
msgStop db 'Stop',13,10,0
|
|
msgUser db 'User callback',13,10,0
|
|
msgMem db 'Not enough memory',13,10,0
|
|
msgDestroy db 'Destroy sound buffer', 13,10,0
|
|
msgWaveout db 'Play waveout', 13,10,0
|
|
msgSetVolume db 'Set volume',13,10,0
|
|
end if
|
|
|
|
section '.data' data readable writable align 16
|
|
|
|
play_list rd 16
|
|
mix_input rd 16
|
|
play_count rd 1
|
|
hSound rd 1
|
|
eng_state rd 1
|
|
mix_buff rd 1
|
|
mix_buff_map rd 1
|
|
str.fd rd 1
|
|
str.bk rd 1
|
|
|
|
mix_2_core rd 1
|
|
mix_3_core rd 1
|
|
mix_4_core rd 1
|