; ; This file is part of the Infinity sound library. ; (C) copyright Serge 2006 ; email: infinity_sound@mail.ru ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. format MS COFF include 'proc32.inc' include 'main.inc' include 'imports.inc' 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 DEBUG equ 1 EVENT_NOTIFY equ 0x00000200 OS_BASE equ 0 new_app_base equ 0x60400000 PROC_BASE equ OS_BASE+0x0080000 CAPS_SSE2 equ 26 public START public service_proc public version SND_CREATE_BUFF equ 2 SND_PLAY equ 3 SND_STOP equ 4 SND_SETBUFF equ 5 SND_DESTROY_BUFF equ 6 DEV_PLAY equ 1 DEV_STOP equ 2 DEV_CALLBACK equ 3 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 ~(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: ;new 128-bit 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 stdcall set_handler, [hSound], new_mix 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 proc service_proc stdcall, ioctl:dword mov edi, [ioctl] mov eax, [edi+io_code] cmp eax, SND_CREATE_BUFF jne @F mov ebx, [edi+input] stdcall CreateBuffer,[ebx] ret @@: cmp eax, SND_PLAY jne @F mov ebx, [edi+input] stdcall play_buffer, [ebx] ret @@: cmp eax, SND_STOP jne @F ; if DEBUG ; mov esi, msgStop ; call [SysMsgBoardStr] ; end if mov ebx, [edi+input] stdcall stop_buffer, [ebx] ret @@: cmp eax, SND_SETBUFF jne @F mov ebx, [edi+input] mov eax, [ebx+4] add eax, new_app_base stdcall set_buffer, [ebx],eax,[ebx+8],[ebx+12] ret @@: cmp eax, SND_DESTROY_BUFF jne @F mov eax, [edi+input] mov eax, [eax] call DestroyBuffer ;eax ret @@: xor eax, eax ret endp restore handle restore io_code restore input restore inp_size restore output restore out_size TASK_COUNT equ 0x0003004 CURRENT_TASK equ 0x0003000 align 8 proc CreateBuffer stdcall, format:dword locals str dd ? endl mov ebx, [CURRENT_TASK] ;hack: direct accsess shl ebx, 5 ;to kernel data mov ebx, [0x3000+ebx+4] mov eax, STREAM_SIZE call CreateObject test eax, eax jz .fail mov [str], eax mov [eax+STREAM.magic], 'WAVE' mov [eax+STREAM.destroy], DestroyBuffer.destroy mov [eax+STREAM.size], STREAM_SIZE pushf cli mov ebx, str.fd-FD_OFFSET mov edx, [ebx+STREAM.str_fd] mov [eax+STREAM.str_fd], edx mov [eax+STREAM.str_bk], ebx mov [ebx+STREAM.str_fd], eax mov [edx+STREAM.str_bk], eax popf stdcall KernelAlloc, 168*1024 mov edi, [str] mov [edi+STREAM.base], eax add eax, 0x1000 mov [edi+STREAM.seg_0], eax mov [edi+STREAM.curr_seg], eax mov [edi+STREAM.notify_off1], eax add eax, 0x8000 mov [edi+STREAM.lim_0], eax add eax, 0x1000 mov [edi+STREAM.seg_1], eax mov [edi+STREAM.notify_off2], eax add eax, 0x8000 mov [edi+STREAM.limit], eax mov [edi+STREAM.lim_1], eax mov [edi+STREAM.work_buff], eax mov [edi+STREAM.work_read], eax mov [edi+STREAM.work_write], eax mov [edi+STREAM.work_count], 0 add eax, 0x10000 mov [edi+STREAM.work_top], eax mov eax, [format] mov [edi+STREAM.format], eax mov [edi+STREAM.flags], SND_STOP xor ebx, ebx cmp eax, 19 jb @f mov ebx, 0x80808080 @@: mov [edi+STREAM.r_silence], ebx shl eax, 4 mov ebx, [resampler_params+eax] mov ecx, [resampler_params+eax+4] mov edx, [resampler_params+eax+8] mov [edi+STREAM.r_size],ebx mov [edi+STREAM.r_end], ecx mov [edi+STREAM.r_dt], edx mov ebx, [resampler_params+eax+12] mov [edi+STREAM.resample], ebx mov edx, [edi+STREAM.base] lea eax, [edx+0x9000] call GetPgAddr ;eax call FreePage ;eax mov eax, edx lea ebx, [edx+0x9000] call GetPgAddr ;eax stdcall MapPage, ebx, eax, dword 3 mov edi, [edi+STREAM.base] mov ecx, (168*1024)/4 xor eax, eax rep stosd mov eax, [str] ret .fail: xor eax, eax ret endp align 4 pid_to_slot: push ebx push ecx mov ebx,[TASK_COUNT] shl ebx,5 mov ecx,2*32 .loop: cmp byte [CURRENT_TASK+ecx+0xa],9 jz .endloop ;skip empty slots cmp [CURRENT_TASK+ecx+0x4],eax ;check PID jz .pid_found .endloop: add ecx,32 cmp ecx,ebx jle .loop pop ecx pop ebx xor eax,eax ret .pid_found: shr ecx,5 mov eax,ecx pop ecx pop ebx ret ;param ; eax= buffer handle align 4 DestroyBuffer: cmp [eax+STREAM.magic], 'WAVE' jne .fail cmp [eax+STREAM.size], STREAM_SIZE jne .fail .destroy: pushf 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 push eax stdcall KernelFree, [eax+STREAM.base] pop eax call DestroyObject ;eax ret .fail: ret align 4 proc play_buffer stdcall, str:dword mov ebx, [str] cmp [ebx+STREAM.magic], 'WAVE' jne .fail cmp [ebx+STREAM.size], STREAM_SIZE jne .fail mov edi,[ebx+STREAM.work_buff] mov [ebx+STREAM.work_read], edi mov [ebx+STREAM.work_write], edi mov [ebx+STREAM.work_count], 0 mov edx, [ebx+STREAM.base] add edx, 0x1000 mov [ebx+STREAM.seg_0], edx mov [ebx+STREAM.curr_seg], edx add edx, 0x8000 mov [ebx+STREAM.lim_0], edx add edx, 0x1000 mov [ebx+STREAM.seg_1], edx add edx, 0x8000 mov [ebx+STREAM.lim_1], edx mov edx, [ebx+STREAM.seg_0] mov ecx, -128 mov eax, [ebx+STREAM.r_silence] @@: mov [edx+ecx], eax add ecx, 4 jnz @B stdcall [ebx+STREAM.resample], edi, edx,\ [ebx+STREAM.r_dt],[ebx+STREAM.r_size],[ebx+STREAM.r_end] mov ebx, [str] add [ebx+STREAM.work_count], eax add [ebx+STREAM.work_write], eax mov edx, [ebx+STREAM.r_size] add [ebx+STREAM.curr_seg], edx mov [ebx+STREAM.flags], SND_PLAY mov eax, [ebx+STREAM.r_silence] mov edi, [ebx+STREAM.work_write] mov ecx, [ebx+STREAM.work_top] sub ecx, edi shr ecx, 2 cld rep stosd stdcall dev_play, [hSound] xor eax, eax inc eax ret .fail: xor eax, eax ret endp align 4 proc stop_buffer stdcall, str:dword mov edi, [str] cmp [edi+STREAM.magic], 'WAVE' jne .fail cmp [edi+STREAM.size], STREAM_SIZE jne .fail mov [edi+STREAM.flags], SND_STOP ; stdcall [ServiceHandler], [hSound], dword DEV_STOP, 0 xor eax, eax inc eax ret .fail: xor eax, eax ret endp align 4 proc set_buffer stdcall, str:dword,src:dword,offs:dword,size:dword mov edx, [str] test edx, edx jz .fail cmp [edx+STREAM.magic], 'WAVE' jne .fail cmp [edx+STREAM.size], STREAM_SIZE jne .fail mov esi,[src] test esi, esi jz .fail cmp esi, new_app_base jb .fail mov edi, [offs] mov ecx, 0x8000 sub ecx, edi jbe .seg_1 sub [size], ecx jb .fail add edi, [edx+STREAM.base] add edi, 0x1000 shr ecx, 2 cld rep movsd jmp @F .seg_1: add edi, [edx+STREAM.base] add edi, 0x1000 @@: add edi, 0x1000 mov ecx, [size] test ecx, ecx jz .done cmp ecx, 0x8000 ja .fail shr ecx, 2 rep movsd .done: xor eax, eax inc eax ret .fail: xor eax, eax ret endp 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_SIZE jne .next ; mov eax,[edi+STREAM.pid] ; cmp eax, -1 ; je .next ; call pid_to_slot ; test eax, eax ; jz .next cmp [edi+STREAM.flags], SND_PLAY; jne .next cmp [edi+STREAM.work_count], 16384 jb .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 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_end r_dt resampler_func dd 0,0,0,0 ; 0 PCM_ALL dd 16384, 0, 0, copy_stream ; 1 PCM_2_16_48 dd 16384, 0, 0, m16_stereo ; 2 PCM_1_16_48 dd 16384, 0x08000000, 30109, resample_2 ; 3 PCM_2_16_44 dd 8192, 0x08000000, 30109, resample_1 ; 4 PCM_1_16_44 dd 16384, 0x08000000, 21846, resample_2 ; 5 PCM_2_16_32 dd 8192, 0x08000000, 21846, resample_1 ; 6 PCM_1_16_32 dd 16384, 0x08000000, 16384, resample_2 ; 7 PCM_2_16_24 dd 8192, 0x08000000, 16384, resample_1 ; 8 PCM_1_16_24 dd 8192, 0x04000000, 15052, resample_2 ; 9 PCM_2_16_22 dd 4096, 0x04000000, 15052, resample_1 ;10 PCM_1_16_22 dd 8192, 0x04000000, 10923, resample_2 ;11 PCM_2_16_16 dd 4096, 0x04000000, 10923, resample_1 ;12 PCM_1_16_16 dd 8192, 0x04000000, 8192, resample_2 ;13 PCM_2_16_12 dd 4096, 0x04000000, 8192, resample_1 ;14 PCM_1_16_12 dd 4096, 0x02000000, 7527, resample_2 ;15 PCM_2_16_11 dd 2048, 0x02000000, 7527, resample_1 ;16 PCM_1_16_11 dd 4096, 0x02000000, 5462, resample_2 ;17 PCM_2_16_8 dd 2048, 0x02000000, 5462, resample_1 ;18 PCM_1_16_8 dd 16384, 0, 0, s8_stereo ;19 PCM_2_8_48 dd 8192, 0, 0, m8_stereo ;20 PCM_1_8_48 dd 8192, 0x08000000, 30109, resample_28 ;21 PCM_2_8_44 dd 4096, 0x08000000, 30109, resample_18 ;22 PCM_1_8_44 dd 8192, 0x08000000, 21846, resample_28 ;23 PCM_2_8_32 dd 4096, 0x08000000, 21846, resample_18 ;24 PCM_1_8_32 dd 8192, 0x08000000, 16384, resample_28 ;25 PCM_2_8_24 dd 4096, 0x08000000, 16384, resample_18 ;26 PCM_1_8_24 dd 4096, 0x04000000, 15052, resample_28 ;27 PCM_2_8_22 dd 2048, 0x04000000, 15052, resample_18 ;28 PCM_1_8_22 dd 4096, 0x04000000, 10923, resample_28 ;29 PCM_2_8_16 dd 2048, 0x04000000, 10923, resample_18 ;30 PCM_1_8_16 dd 4096, 0x04000000, 8192, resample_28 ;31 PCM_2_8_12 dd 2048, 0x04000000, 8192, resample_18 ;32 PCM_1_8_12 dd 2048, 0x02000000, 7527, resample_28 ;33 PCM_2_8_11 dd 1024, 0x02000000, 7527, resample_18 ;34 PCM_1_8_11 dd 2048, 0x02000000, 5462, resample_28 ;35 PCM_2_8_8 dd 1024, 0x02000000, 5462, resample_18 ;36 PCM_1_8_8 m7 dw 0x8000,0x8000,0x8000,0x8000 mm80 dq 0x8080808080808080 mm_mask dq 0xFF00FF00FF00FF00 ;stream_map dd 0xFFFF ; 16 version dd 0x00030003 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 end if section '.data' data readable writable align 16 play_list rd 16 mix_input rd 16 play_count rd 1 hSound 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