Files
4kintro/debug_audio.asm
2024-06-04 17:07:01 +03:00

430 lines
10 KiB
NASM

; yasm -f win32 -o dlltest.obj dlltest.asm
; ld --dll -entry=DllMain@12 -L C:\utils -o dlltest.dll dlltest.obj -l user32
; Compofiller Studio by Yzi
;
; Debug DLL for music stuff
;
%include "errormsg.inc"
section .text
; .start:
global DllMain@12
DllMain@12: ; This code is required in .dll files
mov eax,1
ret 12
; extern _midiOutOpen@20
; extern __imp__midiOutOpen@20
; extern _midiOutShortMsg@8
; extern __imp__midiOutShortMsg@8
; extern _timeGetTime@0
; extern __imp__timeGetTime@0
loppu:
push 0
call [__imp__ExitProcess@4]
ret
extern _MessageBeep@4
extern __imp__MessageBeep@4
beepquit:
push 0xFFFFFFFF
call [__imp__MessageBeep@4]
jmp loppu
; ------------------------------ STUFF FOR PCM/4KLANG MUSIC -------------------------
;section .bss
; .bss declares an uninitialized data section
section .data
; !!! TODO sampling rate is coded in two places now, here and 4klang.ini
audio_sampling_rate equ 44100
;audio_length_seconds equ (2*60)
;audio_length_samples equ (audio_length_seconds*audio_sampling_rate*2)
audio_thread_handle: dd 0
; "rendered audio buffer" means the rendered audio length,
; as opposed to "playback buffer" which might be
; - shorter, if we start playback from the middle of rendered audio
; - longer, if we play all the way from start to end of demo, and there's a positive audio offset/delay
rendered_audio_buffer_ptr: dd 0
; loop parameters
audio_loop_enabled: dd 0
; resw audio_length_samples
global hWaveOut
hWaveOut: dd 0
; Flags for WaveHDR.dwFlags
WHDR_BEGINLOOP equ 4
WHDR_ENDLOOP equ 8
section .data
global WaveHDR
WaveHDR:
audio_playback_buffer_ptr:
WaveHDR_lpData: dd 0
audio_playback_length_bytes:
WaveHDR_dwBufferLength: dd 0 ; audio_length_samples*2 ; audio buffer length in bytes
WaveHDR_dwBytesRecorded: dd 0
WaveHDR_dwUser: dd 0
WaveHDR_dwFlags: dd 0
WaveHDR_dwLoops: dd 0
WaveHDR_lpNext: dd 0
WaveHDR_reserved: dd 0
; long GetPosition() {
; static MMTIME MMTime = { TIME_SAMPLES, 0};
; waveOutGetPosition(hWaveOut, &MMTime, sizeof(MMTIME));
; return (MMTime.u.sample);
; }
global pcmFormat
pcmFormat:
pcmFormat_wFormatTag: dw 1 ; WAVE_FORMAT_PCM
pcmFormat_nChannels: dw 2 ; stereo
pcmFormat_nSamplesPerSec: dd audio_sampling_rate
pcmFormat_nAvgBytesPerSec: dd audio_sampling_rate*4 ; for buffer estimation
pcmFormat_nBlockAlign: dw 4 ; block size of data
pcmFormat_wBitsPerSample: dw 16
pcmFormat_cbSize: dw 0
; void Play() {
; static WAVEHDR WaveHDR = { (LPSTR)(myMuzik), MZK_NUMSAMPLESC * 2};
; // Define output format
; static WAVEFORMATEX pcmFormat = {
; WAVE_FORMAT_PCM, // WORD wFormatTag; /* format type */
; 2, // WORD nChannels; /* number of channels (i.e. mono, stereo...) */
; 44100, // DWORD nSamplesPerSec; /* sample rate */
; 4 * 44100, // DWORD nAvgBytesPerSec; /* for buffer estimation */
; 4, // WORD nBlockAlign; /* block size of data */
; 16, // WORD wBitsPerSample; /* number of bits per sample of mono data */
; 0, // WORD cbSize; /* the count in bytes of the size of */
; };
global MMTime
; MMTIME is a "union" struct that can be used for many different contents based on the first
MMTime: dd 2 ; wType: TIME_SAMPLES = 2
MMTime_sample: dd 0 ; actual position value
db 0, 0, 0, 0 ; some room for other cases
; -----------------
section .text
; the __imp__ versions refer to the corresponding import address table entries
; 4klang
extern _su_render_song@4
; General Windows stuff
extern _ExitProcess@4
extern __imp__ExitProcess@4
extern _CreateThread@24
extern __imp__CreateThread@24
extern _TerminateThread@8
extern __imp__TerminateThread@8
extern _Sleep@4
extern __imp__Sleep@4
extern _WaitForSingleObject@8
extern __imp_WaitForSingleObject@8
; Windows Multimedia
extern _waveOutOpen@24
extern __imp__waveOutOpen@24
extern _waveOutPrepareHeader@12
extern __imp__waveOutPrepareHeader@12
extern _waveOutWrite@12
extern __imp__waveOutWrite@12
extern _waveOutGetPosition@12
extern __imp__waveOutGetPosition@12
extern _waveOutReset@4
extern __imp__waveOutReset@4
extern _waveOutClose@4
extern __imp__waveOutClose@4
export GetRenderedAudioBufferPtr
global _GetRenderedAudioBufferPtr
_GetRenderedAudioBufferPtr:
GetRenderedAudioBufferPtr:
mov eax, dword [rendered_audio_buffer_ptr]
ret
export SetRenderedAudioBufferPtr
global _SetRenderedAudioBufferPtr
_SetRenderedAudioBufferPtr:
SetRenderedAudioBufferPtr:
mov eax, [esp+4]
mov [rendered_audio_buffer_ptr], eax
ret 4
export StartAudioRendererThread
global _StartAudioRendererThread
_StartAudioRendererThread
StartAudioRendererThread:
push 0
push 0
push dword [rendered_audio_buffer_ptr]
extern _su_load_gmdls@0
call _su_load_gmdls@0
push _su_render_song@4
push 0
push 0
;call _CreateThread@24
call [__imp__CreateThread@24]
mov [audio_thread_handle], eax
FAIL_ON_WINDOWS_ERROR CreateThread_string
ret
export KillAudioRendererThread
global _KillAudioRendererThread
_KillAudioRendererThread
KillAudioRendererThread:
; already killed by this function, or never even started?
cmp dword [audio_thread_handle], 0
je noeijuu
push 0
push dword [audio_thread_handle]
call _WaitForSingleObject@8
cmp eax, 0 ; WAIT_OBJECT_0 = 0
je already_died
; now we hope that the thread doesn't finish after windows told us it's "still alive"
; but before we get to call TerminateThread
push 0
push dword [audio_thread_handle]
call [__imp__TerminateThread@8]
FAIL_ON_WINDOWS_ERROR TerminateThread_string
; short sleep and let's hope for the best
push 50
call [__imp__Sleep@4]
already_died:
mov dword [audio_thread_handle], 0
noeijuu:
ret
export GetWaveOutHandle
global _GetWaveOutHandle
_GetWaveOutHandle
GetWaveOutHandle:
mov eax, [hWaveOut]
ret
export GetAudioRendererThreadHandle
global _GetAudioRendererThreadHandle
_GetAudioRendererThreadHandle
GetAudioRendererThreadHandle:
mov eax, [audio_thread_handle]
ret
export GetAudioPlaybackBufferPtr
global _GetAudioPlaybackBufferPtr
_GetAudioPlaybackBufferPtr:
GetAudioPlaybackBufferPtr:
mov eax, dword [audio_playback_buffer_ptr]
ret
export SetAudioPlaybackBufferPtr
global _SetAudioPlaybackBufferPtr
_SetAudioPlaybackBufferPtr:
SetAudioPlaybackBufferPtr:
mov eax, [esp+4]
mov [audio_playback_buffer_ptr], eax
ret 4
export GetAudioPlaybackBufferLengthBytes
global _GetAudioPlaybackBufferLengthBytes
_GetAudioPlaybackBufferLengthBytes:
GetAudioPlaybackBufferLengthBytes:
mov eax, [audio_playback_length_bytes]
ret
export SetAudioPlaybackBufferLengthBytes
global _SetAudioPlaybackBufferLengthBytes
_SetAudioPlaybackBufferLengthBytes:
SetAudioPlaybackBufferLengthBytes:
mov eax, [esp+4]
mov [audio_playback_length_bytes], eax
ret 4
; For GNU ld to be able to create a DLL from our object code, it has to
; have both _Play and Play symbols and _Play as global.
;export Play
;global _Play
; _Play:
;Play:
;call StartAudioRendererThread
; Wait a bit so that the 4klang's renderer thread gets well ahead of playback position
; push 200
; call [__imp__Sleep@4]
;call StartAudio
; mov eax, 1
; ret
section .data
global CreateThread_string
CreateThread_string db 'CreateThread', 0
global TerminateThread_string
TerminateThread_string db 'TerminateThread', 0
global waveOutOpen_string
waveOutOpen_string db 'waveOutOpen', 0
global waveOutPrepareHeader_string
waveOutPrepareHeader_string db 'waveOutPrepareHeader', 0
global waveOutWrite_string
waveOutWrite_string db 'waveOutWrite', 0
global waveOutReset_string
waveOutReset_string db 'waveOutReset', 0
global waveOutClose_string
waveOutClose_string db 'waveOutClose', 0
global waveOutGetPosition_string
waveOutGetPosition_string db 'waveOutGetPosition', 0
section .text
export StartAudio
global _StartAudio
_StartAudio:
StartAudio:
mov dword [WaveHDR_dwFlags], 0
mov dword [WaveHDR_dwLoops], 0
cmp dword [audio_loop_enabled], 0
je no_looping
mov dword [WaveHDR_dwFlags], WHDR_BEGINLOOP + WHDR_ENDLOOP
mov dword [WaveHDR_dwLoops], -1
no_looping:
push 0
push 0
push 0
push pcmFormat
push -1
push hWaveOut
call [__imp__waveOutOpen@24]
FAIL_ON_WINMM_ERROR waveOutOpen_string
push 32 ; sizeof(WaveHDR)
push WaveHDR
push DWORD [hWaveOut]
call [__imp__waveOutPrepareHeader@12]
FAIL_ON_WINMM_ERROR waveOutPrepareHeader_string
push 32 ; sizeof(WaveHDR)
push WaveHDR
push DWORD [hWaveOut]
call [__imp__waveOutWrite@12]
FAIL_ON_WINMM_ERROR waveOutWrite_string
mov eax, 1
ret
export StopAudio
global _StopAudio
_StopAudio:
StopAudio:
push DWORD [hWaveOut]
call [__imp__waveOutReset@4]
FAIL_ON_WINMM_ERROR waveOutReset_string
push DWORD [hWaveOut]
call [__imp__waveOutClose@4]
FAIL_ON_WINMM_ERROR waveOutClose_string
mov DWORD [hWaveOut], 0
mov eax, 1
ret
; // _su_render_song(myMuzik);
; CreateThread(0, 0, (LPTHREAD_START_ROUTINE)_su_render_song, myMuzik, 0, 0);
; Sleep(200);
; waveOutOpen( &hWaveOut, WAVE_MAPPER, &pcmFormat, NULL, 0, CALLBACK_NULL );
; waveOutPrepareHeader( hWaveOut, &WaveHDR, sizeof(WaveHDR) );
; waveOutWrite ( hWaveOut, &WaveHDR, sizeof(WaveHDR) );
;}
; ---- GetPosition returns the current audio playback position ----
export GetCurrentAudioPosition
global _GetCurrentAudioPosition
_GetCurrentAudioPosition:
GetCurrentAudioPosition:
push 12 ; sizeof MMTIME struct
push MMTime
push DWORD [hWaveOut]
call [__imp__waveOutGetPosition@12]
FAIL_ON_WINMM_ERROR waveOutGetPosition_string
mov eax, [MMTime_sample]
ret
;export SetPosition
;global _SetPosition
;_SetPosition:
;SetPosition:
; TODO
; ret 4
; This isn't actually used, using Winmm audio for seamless looping is too much trouble
export SetAudioLoopEnabled
global _SetAudioLoopEnabled
_SetAudioLoopEnabled:
SetAudioLoopEnabled:
mov eax, [esp+4]
mov [audio_loop_enabled], eax
ret 4
; -------------------- ^^^^^ END OF MUSIC / AUDIO DATA STUFF ^^^^^ --------------------