📄 vmp3d.asm
字号:
@@
mov dword [MpegPtr], 0
cmp dword [BufAddr], byte 0
jz @F
VMMCall _PageFree, dword [BufAddr], byte 0
mov dword [BufAddr], 0
@@
retn
SetIndex:
; EAX = index
push edx
mov edx, [ListBuf]
cmp edx, byte 0
jz @F
cmp eax, [edx]
jae @F
mov [NextFile], eax
pop edx
xor eax, eax
clc
retn
@@
pop edx
or eax, byte -1
stc
retn
SetIndexNext:
push edx
mov edx, [ListBuf]
cmp edx, byte 0
jnz @F
pop edx
or eax, byte -1
stc
retn
@@
inc dword [NextFile]
mov eax, [NextFile]
cmp eax, [edx]
jb @F
and dword [NextFile], byte 0
@@
pop edx
xor eax, eax
clc
retn
SetIndexPrev:
push edx
mov edx, [ListBuf]
cmp edx, byte 0
jnz @F
pop edx
or eax, byte -1
stc
retn
@@
sub dword [NextFile], byte 1
jnc @F
mov eax, [edx]
dec eax
mov [NextFile], eax
@@
pop edx
xor eax, eax
clc
retn
PlayMpegIndex:
pushad
mov esi, [ListBuf]
mov eax, [NextFile]
lea eax, [esi+eax*4+4]
mov esi, [eax] ; pointer to file name
jmp short PlayMpeg.NoRegs
PlayMpeg:
; ESI = filename
pushad
.NoRegs:
; acquire wave device if not done yet
cmp word [hMMWave], 0
jnz .hasdevice
VxDCall _SHELL_CallAtAppyTime, dword AppyWaveOpen, byte 0, byte 0, byte 0
cmp eax, byte 0
jnz @F
%if ADD_DEBUG = 1
Trace_Out "Grab Wave appy event-schedule failed"
%endif
mov eax, -5
jmp .err_noclose
@@
; wait for appy to finish
; mov eax, [hMMSem]
; mov ecx, BLOCK_SVC_INTS | BLOCK_ENABLE_INTS
; VMMCall Wait_Semaphore
VMMCall _BlockOnID, dword hMMLib, dword BLOCK_SVC_INTS | BLOCK_ENABLE_INTS
cmp word [hMMWave], 0
jnz .hasdevice
mov eax, -5
jmp .err_noclose
.hasdevice:
xor eax, eax ; keep the device
call StopMpeg
; open file
mov eax, R0_OPENCREATFILE
mov ebx, 2040h ; read only|share:deny none|no INT24
mov ecx, 0020h ; archive
mov edx, 0001h ; open|fail
VxDCall IFSMgr_Ring0_FileIO
%if ADD_DEBUG = 1
Trace_OutC "Open file failed, code #EAX"
%endif
jc near .err_noclose
; save handle for future
mov ebx, eax
mov eax, R0_GETFILESIZE
VxDCall IFSMgr_Ring0_FileIO
jc near .err_close
mov [FileSize], eax
add eax, 0fffh
shr eax, 12
VMMCall _PageAllocate, eax, byte PG_SYS, byte 0, byte 0, byte 0, byte 0, byte 0, dword PAGEFIXED
cmp eax, byte 0
jnz @F
%if ADD_DEBUG = 1
Trace_Out "File buffer alloc failed"
%endif
mov eax, 8 ; Not enough mem
jmp .err_close
@@
mov [BufAddr], eax
; read entire file in
mov esi, eax ; buffer
mov eax, R0_READFILE
mov ecx, [FileSize] ; bytes to read
xor edx, edx ; file ofs
VxDCall IFSMgr_Ring0_FileIO
%if ADD_DEBUG = 1
Trace_OutC "Read file failed, code #EAX"
%endif
jc near .err_close
mov eax, R0_CLOSEFILE
VxDCall IFSMgr_Ring0_FileIO
; reset vars
mov ecx, [FileSize]
mov [FileLeft], ecx
xor ecx, ecx
mov [CurBlock], ecx
mov [cBlocks], ecx
mov [BufPtr], ecx
call InitMpeg
jc near .err_noclose
call MpegNextBlock
call MpegNextBlock
; init DMA for auto-init xfer
VxDCall VDSPD_Get_DMA
mov ebx, [DmaPhysAddr]
mov ecx, 10000h
call DmaInit
mov byte [IsPlaying], 1
mov eax, [hIrq]
VxDCall VPICD_Physically_Unmask
mov eax, [LastFrame + FrameInfo.SampFreq]
mov ebx, [LastFrame + FrameInfo.Chans]
shr ebx, 1 ; set mono/stereo bit
mov edx, [LastFrame + FrameInfo.BitsPerSample]
shr edx, 4
shl edx, 1
or ebx, edx ; set 16bit-play bit
mov ecx, 8000h
VxDCall VDSPD_Play
xor eax, eax
mov [esp + CRS.EAX], eax
popad
clc
retn
.err_close:
push eax
mov eax, R0_CLOSEFILE
VxDCall IFSMgr_Ring0_FileIO
pop eax
.err_noclose:
mov [esp + CRS.EAX], eax
popad
stc
retn
WAVE_MAPPER EQU -1
struc WaveOpenArgs
woa_fdwOpen resd 1
woa_dwInstance resd 1
woa_dwCB resd 1
woa_lpWaveFmt resd 1
woa_uDeviceID resw 1
woa_lphWaveOut resd 1
endstruc
struc WaveCloseArgs
wca_hWaveOut resw 1
endstruc
AppyWaveOpen:
; PROC C Public, dwRefData:DWORD, dwFlags:DWORD
; setup call stack
mov eax, [hMMmem]
mov [woa + woa_lpWaveFmt], eax
add eax, byte WaveFormatEx_size
mov [woa + woa_lphWaveOut], eax
; init hWaveOut in case call fails
mov edx, [LinMMmem]
mov word [edx + WaveFormatEx_size], 0
push edx
VxDCall _SHELL_CallDll, byte 0, dword [waveOutOpen], byte WaveOpenArgs_size, dword woa
pop edx
mov cx, [edx + WaveFormatEx_size]
%if ADD_DEBUG = 1
cmp eax, byte 0
jnz @F
cmp cx, 0
jnz @F
Trace_Out "waveOutOpen failed"
@@
%endif
mov [hMMWave], cx
%if ADD_DEBUG = 1
Trace_Out "waveOutOpen succeeded at AppyTime"
%endif
; mov eax, [hMMSem]
; VMMCall Signal_Semaphore
VMMCall _SignalID, dword hMMLib
retn
segment _LDATA
align 4
woa:
istruc WaveOpenArgs
at woa_fdwOpen, dd 0
at woa_dwInstance, dd 0
at woa_dwCB, dd 0
at woa_lpWaveFmt, dd 0
at woa_uDeviceID, dw WAVE_MAPPER
at woa_lphWaveOut, dd 0
iend
segment _LTEXT
AppyWaveClose:
; PROC C Public, dwRefData:DWORD, dwFlags:DWORD
mov ax, [hMMWave]
mov [wca + wca_hWaveOut], ax
VxDCall _SHELL_CallDll, byte 0, dword [waveOutClose], byte WaveCloseArgs_size, dword wca
mov word [hMMWave], 0
%if ADD_DEBUG = 1
Trace_Out "waveOutClose succeeded at AppyTime"
%endif
; mov eax, [hMMSem]
; VMMCall Signal_Semaphore
VMMCall _SignalID, dword hMMLib
retn
segment _LDATA
align 4
wca:
istruc WaveCloseArgs
iend
segment _LTEXT
InitMpeg:
VxDCall VDSPD_Is_Stereo
mov edi, eax
xor edi, byte 1 ; not
VxDCall VDSPD_Is_16bit
mov esi, eax
xor esi, byte 1 ; not
xor ebx, ebx
.loop1:
push byte 0
push edi
push esi
push ebx
push dword 1234h ; dummy file handle
call _MpegBegin@20
and eax, 0C0000000h
cmp eax, 0C0000000h
je .err1
call NextFrame
jc .err1
VxDCall VDSPD_Get_Rate
cmp eax, [LastFrame + FrameInfo.SampFreq]
jae .ret1 ; card freq supported, ok
push dword 1234h
call _MpegEnd@4
inc ebx
mov dword [MpegPtr], 0
mov dword [BufPtr], 0
jmp short .loop1
.ret1:
clc
retn
.err1:
stc
retn
NextFrame:
push edi
mov edi, [MpegBuf]
add edi, [MpegPtr]
@@
push dword LastFrame
push dword MpegLastBytes
push edi
call _MpegNextFrame@12
mov edx, eax
and edx, 0C0000000h
cmp edx, 0C0000000h ; check for error
jz @F
cmp eax, MPEG_ENDOFTRACK
je @F
cmp dword [MpegLastBytes], byte 0
jz @B
mov eax, [MpegLastBytes]
add [MpegPtr], eax
clc
pop edi
retn
@@
stc
pop edi
retn
MpegNextBlock:
@@
call NextFrame
jc near .err1
cmp dword [MpegPtr], 0x8000
jb @B
mov edx, [MpegPtr]
mov ecx, 8000h
sub edx, ecx
mov [MpegPtr], edx
; copy wave-form to DMA Buffer
mov edi, [DmaLinAddr]
mov esi, [MpegBuf]
add edi, [CurBlock]
xor [CurBlock], ecx ; update current block
cld
shr ecx, 2
rep movsd
inc dword [cBlocks]
; move wave-form leftovers (above 8000h) to the begining
mov edi, [MpegBuf]
mov ecx, edx
and edx, 3
shr ecx, 2
rep movsd
cmp edx, byte 0
jz @F
mov ecx, edx
rep movsb
@@
retn
.err1:
; end the stream
mov dword [FileLeft], 0
mov ecx, [FileSize]
inc ecx
mov [BufPtr], ecx
retn
align 4
DspHwIntProc:
pushad
call OnDspIrq
jnc @F
popad
jmp dword [OrgHwIntProc]
@@
mov eax, [esp+CRS.EAX]
VxDCall VPICD_Phys_EOI
popad
clc
retn
;
; this mess simulates a HOOK_PROC
;
jmp short HookedMaskIRQ ; *MUST* assemble to EB,06 or EB,0A
jmp [OrgMaskIRQProc]
%if ADD_DEBUG = 1
dd 0
%endif
HookedMaskIRQ:
; LOCKED, HOOK_PROC, OrgMaskIRQProc
; prevents our irq from being masked
;Assume eax:PTR VID_IRQ_Struct
cmp byte [IsPlaying], 1
jne IgnoreIRQ
push ecx
mov ecx, [eax + VID_IRQ_Struct.CtrlBlock]
mov ecx, [ecx + VID_IRQCB.nIRQ]
cmp ecx, [IrqNum]
pop ecx
jne IgnoreIRQ
retn ; do nothing
IgnoreIRQ:
jmp [OrgMaskIRQProc]
HookIrq:
; EAX = irq #
; EBX = hVM
; EBP = CRS
mov [IrqNum], eax
; get PIC addr
mov ecx, eax
shl cl, 5
mov ch, 40h
rcr ch, 1
shr cl, 5
mov [PicReg], ch
; get PIC mask
mov ah, 1
shl ah, cl
mov [PicMask], ah
; hook VPICD_Physically_Mask to prevent masking of our irq
GetDeviceServiceOrdinal eax, VPICD_Physically_Mask
mov esi, HookedMaskIRQ
VMMCall Hook_Device_Service
%if ADD_DEBUG = 1
Trace_OutC "Hooking VPICD_Physically_Mask failed"
%endif
jnc @F
retn
@@
; lookup virtualized irq handle
mov edi, [IrqTab]
mov eax, [IrqNum]
mov edi, [edi+eax*4] ; get VID_IRQCB ptr
mov eax, [edi + VID_IRQCB.hIrqOwner]
cmp dword [eax + VID_IRQ_Struct.DbgStr], 51524953h ; 'SIRQ'
jne .cleanup1
; we got our int, now hook Hw_Int_Proc
mov [hIrq], eax
pushfd
cli
mov ecx, [eax + VID_IRQ_Struct.Hw_Int_Proc]
mov [OrgHwIntProc], ecx
mov ecx, DspHwIntProc
mov [eax + VID_IRQ_Struct.Hw_Int_Proc], ecx
popfd
clc
retn
.cleanup1:
%if ADD_DEBUG = 1
Trace_Out "VPICD hack failed, invalid or unknown struct"
%endif
; unhook VPICD_Physically_Mask
GetDeviceServiceOrdinal eax, VPICD_Physically_Mask
mov esi, HookedMaskIRQ
VMMCall Unhook_Device_Service
stc
retn
UnhookIrq:
; unhook Hw_Int_Proc
pushfd
cli
mov edx, [hIrq]
mov eax, [OrgHwIntProc]
mov [edx + VID_IRQ_Struct.Hw_Int_Proc], eax
popfd
; unhook VPICD_Physically_Mask
GetDeviceServiceOrdinal eax, VPICD_Physically_Mask
mov esi, HookedMaskIRQ
VMMCall Unhook_Device_Service
%if ADD_DEBUG = 1
Trace_OutC "Unhooking VPICD_Physically_Mask failed"
%endif
retn
align 4
OnDspIrq:
cmp byte [IsPlaying], 1
je @F
stc
retn
@@
VxDCall VDSPD_Check_Int
jnc @F
stc
retn
@@
; save fpu state (save TS)
mov eax, cr0
push eax
clts
sub esp, byte FPU_Status_PM32_size + FPU_STx_size
fnsave [esp]
fninit
call MpegNextBlock
; now restore FPU state, first clear possible pending exceptions
xor al, al
xchg al, [esp + FPU_Status_PM32.StatusLo]
frstor [esp]
; now restore status with possible pending exceptions
xchg al, [esp + FPU_Status_PM32.StatusLo]
fldenv [esp]
add esp, byte FPU_Status_PM32_size + FPU_STx_size
pop eax
mov cr0, eax ; restore CR0.TS
dec dword [cBlocks]
jnz .nostop
VxDCall VDSPD_Stop
.nostop:
clc
retn
align 4
ReadStreamData:
; returns number of bytes read or MPEG_ENDOFSTREAM
; PROC Stdcall, hFile:DWORD, Buffer:PTR BYTE, BufferSize:DWORD
%define hFile esp+4+12
%define Buffer esp+8+12
%define BufferSize esp+12+12
push esi
push edi
push ebx
mov ecx, [FileLeft]
cmp ecx, byte 0
jnz @F
mov eax, MPEG_ENDOFTRACK
pop ebx
pop edi
pop esi
retn 12
@@
mov eax, [BufferSize]
cmp ecx, eax
jb .block_ok
mov ecx, eax
.block_ok:
sub [FileLeft], ecx
mov esi, [BufAddr] ; calc next block ptr
add esi, [BufPtr]
add [BufPtr], ecx ; update buffer ptr
mov edi, [Buffer]
mov eax, ecx
cld
shr ecx, 2
rep movsd
mov ecx, eax
and ecx, 3
cmp ecx, byte 0
jz @F
rep movsb
@@
pop ebx
pop edi
pop esi
retn 12
VMP3D_Get_Version:
mov eax, 0100h
clc
retn
VMP3D_Get_IRQ:
VxDCall VDSPD_Get_IRQ
retn
VMP3D_On_SoftIce_IRQ:
pushad
call OnDspIrq
popad
clc
retn
VMP3D_Need_SoftIce_IRQ:
cmp byte [IsPlaying], 0
retn
VMP3D_Play:
bts dword [IsBusy], 0
jc @F
pushad
call SetIndex ; eax: index
jc @F
call PlayMpegIndex
btr dword [IsBusy], 0
@@
popad
retn
VMP3D_Play_Next:
bts dword [IsBusy], 0
jc @F
pushad
call SetIndexNext
jc @F
call PlayMpegIndex
btr dword [IsBusy], 0
@@
popad
retn
VMP3D_Play_Prev:
bts dword [IsBusy], 0
jc @F
pushad
call SetIndexPrev
jc @F
call PlayMpegIndex
btr dword [IsBusy], 0
@@
popad
retn
VMP3D_Stop:
pushad
cmp byte [IsPlaying], 0
jz @F
bts dword [IsBusy], 0
jc @F
mov eax, 1
call StopMpeg
btr dword [IsBusy], 0
@@
popad
clc
retn
VMP3D_Pause:
retn ; NOT READY YET
pushad
cmp byte [IsPlaying], 0
jz @F
VxDCall VDSPD_Pause
@@
popad
retn
VMP3D_Resume:
retn ; NOT READY YET
pushad
cmp byte [IsPlaying], 0
jz @F
VxDCall VDSPD_Resume
@@
popad
retn
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -