mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 21:14:31 -04:00
Added x86 asm and C wav writer and player examples.
Specifically: * Added win32, elf32 and elf64 asm player and wav writers using winmm. * Added dsound player in C. * Separated the ALL target and the examples; introduced a new examples target.
This commit is contained in:
committed by
Veikko Sariola
parent
a439a4fa48
commit
607e5b5da0
10
examples/code/asm/386/CMakeLists.txt
Normal file
10
examples/code/asm/386/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
if(WIN32)
|
||||
set(CMAKE_ASM_NASM_OBJECT_FORMAT win32)
|
||||
elseif(UNIX)
|
||||
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf32)
|
||||
endif()
|
||||
set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <DEFINES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
|
||||
|
||||
add_asm_example(asmplay "${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml" 386 32 "winmm" "asound;pthread")
|
||||
add_asm_example(asmwav "${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml" 386 32 "" "")
|
||||
target_compile_definitions(asmwav-386 PRIVATE FILENAME="physics_girl_st.wav")
|
81
examples/code/asm/386/asmplay.elf32.asm
Normal file
81
examples/code/asm/386/asmplay.elf32.asm
Normal file
@ -0,0 +1,81 @@
|
||||
%include TRACK_INCLUDE
|
||||
|
||||
%define SND_PCM_FORMAT_S16_LE 0x2
|
||||
%define SND_PCM_FORMAT_FLOAT 0xE
|
||||
%define SND_PCM_ACCESS_RW_INTERLEAVED 0x3
|
||||
%define SND_PCM_STREAM_PLAYBACK 0x0
|
||||
|
||||
section .bss
|
||||
sound_buffer:
|
||||
resb SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
|
||||
render_thread:
|
||||
resd 1
|
||||
|
||||
pcm_handle:
|
||||
resd 1
|
||||
|
||||
section .data
|
||||
default_device:
|
||||
db "default", 0
|
||||
|
||||
section .text
|
||||
symbols:
|
||||
extern pthread_create
|
||||
extern sleep
|
||||
extern snd_pcm_open
|
||||
extern snd_pcm_set_params
|
||||
extern snd_pcm_writei
|
||||
|
||||
global main
|
||||
main:
|
||||
; elf32 uses the cdecl calling convention. This is more readable imo ;)
|
||||
|
||||
; Prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
sub esp, 0x10
|
||||
|
||||
; Unix does not have gm.dls, no need to ifdef and setup here.
|
||||
|
||||
; We render in the background while playing already.
|
||||
push sound_buffer
|
||||
lea eax, su_render_song
|
||||
push eax
|
||||
push 0
|
||||
push render_thread
|
||||
call pthread_create
|
||||
|
||||
; We can't start playing too early or the missing samples will be audible.
|
||||
push 0x2
|
||||
call sleep
|
||||
|
||||
; Play the track.
|
||||
push 0x0
|
||||
push SND_PCM_STREAM_PLAYBACK
|
||||
push default_device
|
||||
push pcm_handle
|
||||
call snd_pcm_open
|
||||
|
||||
push SU_LENGTH_IN_SAMPLES
|
||||
push 0
|
||||
push SU_SAMPLE_RATE
|
||||
push SU_CHANNEL_COUNT
|
||||
push SND_PCM_ACCESS_RW_INTERLEAVED
|
||||
%ifdef SU_SAMPLE_FLOAT
|
||||
push SND_PCM_FORMAT_FLOAT
|
||||
%else ; SU_SAMPLE_FLOAT
|
||||
push SND_PCM_FORMAT_S16_LE
|
||||
%endif ; SU_SAMPLE_FLOAT
|
||||
push dword [pcm_handle]
|
||||
call snd_pcm_set_params
|
||||
|
||||
push SU_LENGTH_IN_SAMPLES
|
||||
push sound_buffer
|
||||
push dword [pcm_handle]
|
||||
call snd_pcm_writei
|
||||
|
||||
exit:
|
||||
; At least we can skip the epilogue :)
|
||||
leave
|
||||
ret
|
120
examples/code/asm/386/asmplay.win32.asm
Normal file
120
examples/code/asm/386/asmplay.win32.asm
Normal file
@ -0,0 +1,120 @@
|
||||
%define MANGLED
|
||||
%include TRACK_INCLUDE
|
||||
|
||||
%define WAVE_FORMAT_PCM 0x1
|
||||
%define WAVE_FORMAT_IEEE_FLOAT 0x3
|
||||
%define WHDR_PREPARED 0x2
|
||||
%define WAVE_MAPPER 0xFFFFFFFF
|
||||
%define TIME_SAMPLES 0x2
|
||||
%define PM_REMOVE 0x1
|
||||
|
||||
section .bss
|
||||
sound_buffer:
|
||||
resb SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
|
||||
wave_out_handle:
|
||||
resd 1
|
||||
|
||||
msg:
|
||||
resd 1
|
||||
message:
|
||||
resd 7
|
||||
|
||||
section .data
|
||||
wave_format:
|
||||
%ifdef SU_SAMPLE_FLOAT
|
||||
dw WAVE_FORMAT_IEEE_FLOAT
|
||||
%else ; SU_SAMPLE_FLOAT
|
||||
dw WAVE_FORMAT_PCM
|
||||
%endif ; SU_SAMPLE_FLOAT
|
||||
dw SU_CHANNEL_COUNT
|
||||
dd SU_SAMPLE_RATE
|
||||
dd SU_SAMPLE_SIZE * SU_SAMPLE_RATE * SU_CHANNEL_COUNT
|
||||
dw SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
dw SU_SAMPLE_SIZE * 8
|
||||
dw 0
|
||||
|
||||
wave_header:
|
||||
dd sound_buffer
|
||||
dd SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
times 2 dd 0
|
||||
dd WHDR_PREPARED
|
||||
times 4 dd 0
|
||||
wave_header_end:
|
||||
|
||||
mmtime:
|
||||
dd TIME_SAMPLES
|
||||
sample:
|
||||
times 2 dd 0
|
||||
mmtime_end:
|
||||
|
||||
section .text
|
||||
symbols:
|
||||
extern _CreateThread@24
|
||||
extern _waveOutOpen@24
|
||||
extern _waveOutWrite@12
|
||||
extern _waveOutGetPosition@12
|
||||
extern _PeekMessageA@20
|
||||
extern _TranslateMessage@4
|
||||
extern _DispatchMessageA@4
|
||||
|
||||
global _mainCRTStartup
|
||||
_mainCRTStartup:
|
||||
; win32 uses the cdecl calling convention. This is more readable imo ;)
|
||||
; We can also skip the prologue; Windows doesn't mind.
|
||||
|
||||
%ifdef SU_LOAD_GMDLS
|
||||
call _su_load_gmdls
|
||||
%endif ; SU_LOAD_GMDLS
|
||||
|
||||
times 2 push 0
|
||||
push sound_buffer
|
||||
lea eax, _su_render_song@4
|
||||
push eax
|
||||
times 2 push 0
|
||||
call _CreateThread@24
|
||||
|
||||
; We render in the background while playing already. Fortunately,
|
||||
; Windows is slow with the calls below, so we're not worried that
|
||||
; we don't have enough samples ready before the track starts.
|
||||
times 3 push 0
|
||||
push wave_format
|
||||
push WAVE_MAPPER
|
||||
push wave_out_handle
|
||||
call _waveOutOpen@24
|
||||
|
||||
push wave_header_end - wave_header
|
||||
push wave_header
|
||||
push dword [wave_out_handle]
|
||||
call _waveOutWrite@12
|
||||
|
||||
; We need to handle windows messages properly while playing, as waveOutWrite is async.
|
||||
mainloop:
|
||||
dispatchloop:
|
||||
push PM_REMOVE
|
||||
times 3 push 0
|
||||
push msg
|
||||
call _PeekMessageA@20
|
||||
jz dispatchloop_end
|
||||
|
||||
push msg
|
||||
call _TranslateMessage@4
|
||||
|
||||
push msg
|
||||
call _DispatchMessageA@4
|
||||
|
||||
jmp dispatchloop
|
||||
dispatchloop_end:
|
||||
|
||||
push mmtime_end - mmtime
|
||||
push mmtime
|
||||
push dword [wave_out_handle]
|
||||
call _waveOutGetPosition@12
|
||||
|
||||
cmp dword [sample], SU_LENGTH_IN_SAMPLES
|
||||
jne mainloop
|
||||
|
||||
exit:
|
||||
; At least we can skip the epilogue :)
|
||||
leave
|
||||
ret
|
91
examples/code/asm/386/asmwav.elf32.asm
Normal file
91
examples/code/asm/386/asmwav.elf32.asm
Normal file
@ -0,0 +1,91 @@
|
||||
%include TRACK_INCLUDE
|
||||
|
||||
%define WAVE_FORMAT_PCM 0x1
|
||||
%define WAVE_FORMAT_IEEE_FLOAT 0x3
|
||||
|
||||
section .bss
|
||||
sound_buffer:
|
||||
resb SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
|
||||
file:
|
||||
resd 1
|
||||
|
||||
section .data
|
||||
; Change the filename over -DFILENAME="yourfilename.wav"
|
||||
filename:
|
||||
db FILENAME, 0
|
||||
|
||||
format:
|
||||
db "wb", 0
|
||||
|
||||
; This is the wave file header.
|
||||
wave_file:
|
||||
db "RIFF"
|
||||
dd wave_file_end + SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT - wave_file
|
||||
db "WAVE"
|
||||
db "fmt "
|
||||
wave_format_end:
|
||||
dd wave_format_end - wave_file
|
||||
%ifdef SU_SAMPLE_FLOAT
|
||||
dw WAVE_FORMAT_IEEE_FLOAT
|
||||
%else ; SU_SAMPLE_FLOAT
|
||||
dw WAVE_FORMAT_PCM
|
||||
%endif ; SU_SAMPLE_FLOAT
|
||||
dw SU_CHANNEL_COUNT
|
||||
dd SU_SAMPLE_RATE
|
||||
dd SU_SAMPLE_SIZE * SU_SAMPLE_RATE * SU_CHANNEL_COUNT
|
||||
dw SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
dw SU_SAMPLE_SIZE * 8
|
||||
wave_header_end:
|
||||
db "data"
|
||||
dd wave_file_end + SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT - wave_header_end
|
||||
wave_file_end:
|
||||
|
||||
section .text
|
||||
symbols:
|
||||
extern fopen
|
||||
extern fwrite
|
||||
extern fclose
|
||||
|
||||
global main
|
||||
main:
|
||||
; elf32 uses the cdecl calling convention. This is more readable imo ;)
|
||||
|
||||
; Prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
sub esp, 0x10
|
||||
|
||||
; Unix does not have gm.dls, no need to ifdef and setup here.
|
||||
|
||||
; We render the complete track here.
|
||||
push sound_buffer
|
||||
call su_render_song
|
||||
|
||||
; Now we open the file and save the track.
|
||||
push format
|
||||
push filename
|
||||
call fopen
|
||||
mov dword [file], eax
|
||||
|
||||
; Write header
|
||||
push dword [file]
|
||||
push 0x1
|
||||
push wave_file_end - wave_file
|
||||
push wave_file
|
||||
call fwrite
|
||||
|
||||
; write data
|
||||
push dword [file]
|
||||
push 0x1
|
||||
push SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
push sound_buffer
|
||||
call fwrite
|
||||
|
||||
push dword [file]
|
||||
call fclose
|
||||
|
||||
exit:
|
||||
; At least we can skip the epilogue :)
|
||||
leave
|
||||
ret
|
102
examples/code/asm/386/asmwav.win32.asm
Normal file
102
examples/code/asm/386/asmwav.win32.asm
Normal file
@ -0,0 +1,102 @@
|
||||
%define MANGLED
|
||||
%include TRACK_INCLUDE
|
||||
|
||||
%define WAVE_FORMAT_PCM 0x1
|
||||
%define WAVE_FORMAT_IEEE_FLOAT 0x3
|
||||
%define FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||
%define CREATE_ALWAYS 2
|
||||
%define GENERIC_WRITE 0x40000000
|
||||
|
||||
section .bss
|
||||
sound_buffer:
|
||||
resb SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
|
||||
file:
|
||||
resd 1
|
||||
|
||||
bytes_written:
|
||||
resd 1
|
||||
|
||||
section .data
|
||||
; Change the filename over -DFILENAME="yourfilename.wav"
|
||||
filename:
|
||||
db FILENAME, 0
|
||||
|
||||
; This is the wave file header.
|
||||
wave_file:
|
||||
db "RIFF"
|
||||
dd wave_file_end + SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT - wave_file
|
||||
db "WAVE"
|
||||
db "fmt "
|
||||
wave_format_end:
|
||||
dd wave_format_end - wave_file
|
||||
%ifdef SU_SAMPLE_FLOAT
|
||||
dw WAVE_FORMAT_IEEE_FLOAT
|
||||
%else ; SU_SAMPLE_FLOAT
|
||||
dw WAVE_FORMAT_PCM
|
||||
%endif ; SU_SAMPLE_FLOAT
|
||||
dw SU_CHANNEL_COUNT
|
||||
dd SU_SAMPLE_RATE
|
||||
dd SU_SAMPLE_SIZE * SU_SAMPLE_RATE * SU_CHANNEL_COUNT
|
||||
dw SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
dw SU_SAMPLE_SIZE * 8
|
||||
wave_header_end:
|
||||
db "data"
|
||||
dd wave_file_end + SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT - wave_header_end
|
||||
wave_file_end:
|
||||
|
||||
section .text
|
||||
symbols:
|
||||
extern _CreateFileA@28
|
||||
extern _WriteFile@20
|
||||
extern _CloseHandle@4
|
||||
|
||||
global _mainCRTStartup
|
||||
_mainCRTStartup:
|
||||
; Prologue
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
sub esp, 0x10
|
||||
|
||||
%ifdef SU_LOAD_GMDLS
|
||||
call _su_load_gmdls
|
||||
%endif ; SU_LOAD_GMDLS
|
||||
|
||||
; We render the complete track here.
|
||||
push sound_buffer
|
||||
call _su_render_song@4
|
||||
|
||||
; Now we open the file and save the track.
|
||||
push 0x0
|
||||
push FILE_ATTRIBUTE_NORMAL
|
||||
push CREATE_ALWAYS
|
||||
push 0x0
|
||||
push 0x0
|
||||
push GENERIC_WRITE
|
||||
push filename
|
||||
call _CreateFileA@28
|
||||
mov dword [file], eax
|
||||
|
||||
; This is the WAV header
|
||||
push 0x0
|
||||
push bytes_written
|
||||
push wave_file_end - wave_file
|
||||
push wave_file
|
||||
push dword [file]
|
||||
call _WriteFile@20
|
||||
|
||||
; There we write the actual samples
|
||||
push 0x0
|
||||
push bytes_written
|
||||
push SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT * SU_SAMPLE_SIZE
|
||||
push sound_buffer
|
||||
push dword [file]
|
||||
call _WriteFile@20
|
||||
|
||||
push dword [file]
|
||||
call _CloseHandle@4
|
||||
|
||||
exit:
|
||||
; At least we can skip the epilogue :)
|
||||
leave
|
||||
ret
|
Reference in New Issue
Block a user