mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 13:04:25 -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
|
58
examples/code/asm/CMakeLists.txt
Normal file
58
examples/code/asm/CMakeLists.txt
Normal file
@ -0,0 +1,58 @@
|
||||
# identifier: Name of the example
|
||||
# songfile: File path of the song YAML file.
|
||||
# architecture: 386 or amd64
|
||||
# abi: 32 or 64
|
||||
# windows_libraries: All libraries that you need to link on Windows
|
||||
# unix_libraries: All libraries that you need to link on unix
|
||||
function(add_asm_example identifier songfile architecture sizeof_void_ptr windows_libraries unix_libraries)
|
||||
get_filename_component(songprefix ${songfile} NAME_WE)
|
||||
|
||||
# Generate the song assembly file
|
||||
add_custom_command(
|
||||
COMMAND
|
||||
${compilecmd} -arch=${architecture} -o ${songprefix}_${architecture}.asm ${songfile}
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS
|
||||
${songfile}
|
||||
OUTPUT
|
||||
${songprefix}_${architecture}.asm
|
||||
${songprefix}_${architecture}.h
|
||||
${songprefix}_${architecture}.inc
|
||||
COMMENT
|
||||
"Compiling ${PROJECT_SOURCE_DIR}/examples/patches/physics-girl-st.yml..."
|
||||
)
|
||||
|
||||
# Platform dependent options
|
||||
if(WIN32)
|
||||
set(abi win)
|
||||
set(libraries ${windows_libraries})
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(link_options -nostartfiles)
|
||||
endif()
|
||||
elseif(UNIX)
|
||||
set(abi elf)
|
||||
set(link_options -z noexecstack -no-pie)
|
||||
set(libraries ${unix_libraries})
|
||||
endif()
|
||||
|
||||
# Add target
|
||||
add_executable(${identifier}-${architecture}
|
||||
${identifier}.${abi}${sizeof_void_ptr}.asm
|
||||
${songprefix}_${architecture}.asm
|
||||
${songprefix}_${architecture}.inc
|
||||
)
|
||||
set_target_properties(${identifier}-${architecture} PROPERTIES ASM_NASM_COMPILE_OPTIONS -f${abi}${sizeof_void_ptr})
|
||||
target_include_directories(${identifier}-${architecture} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_target_properties(${identifier}-${architecture} PROPERTIES LINKER_LANGUAGE C)
|
||||
target_link_options(${identifier}-${architecture} PRIVATE -m${sizeof_void_ptr} ${link_options})
|
||||
target_link_libraries(${identifier}-${architecture} PRIVATE ${libraries})
|
||||
target_compile_definitions(${identifier}-${architecture} PRIVATE TRACK_INCLUDE="${songprefix}_${architecture}.inc")
|
||||
|
||||
# Set up dependencies
|
||||
add_dependencies(${identifier}-${architecture} sointu-compiler)
|
||||
add_dependencies(examples ${identifier}-${architecture})
|
||||
endfunction()
|
||||
|
||||
add_subdirectory(386)
|
||||
add_subdirectory(amd64)
|
12
examples/code/asm/amd64/CMakeLists.txt
Normal file
12
examples/code/asm/amd64/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
||||
if(WIN32)
|
||||
set(CMAKE_ASM_NASM_OBJECT_FORMAT win64)
|
||||
elseif(UNIX)
|
||||
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
|
||||
endif()
|
||||
set(CMAKE_ASM_NASM_COMPILE_OBJECT "<CMAKE_ASM_NASM_COMPILER> <INCLUDES> <DEFINES> <FLAGS> -f ${CMAKE_ASM_NASM_OBJECT_FORMAT} -o <OBJECT> <SOURCE>")
|
||||
|
||||
if(UNIX)
|
||||
add_asm_example(asmplay "${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml" amd64 64 "winmm" "asound;pthread")
|
||||
add_asm_example(asmwav "${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml" amd64 64 "" "")
|
||||
target_compile_definitions(asmwav-amd64 PRIVATE FILENAME="physics_girl_st.wav")
|
||||
endif()
|
81
examples/code/asm/amd64/asmplay.elf64.asm
Normal file
81
examples/code/asm/amd64/asmplay.elf64.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:
|
||||
resq 1
|
||||
|
||||
pcm_handle:
|
||||
resq 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:
|
||||
; Prologue
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 0x10
|
||||
|
||||
; Unix does not have gm.dls, no need to ifdef and setup here.
|
||||
|
||||
; We render in the background while playing already.
|
||||
mov rcx, sound_buffer
|
||||
lea rdx, su_render_song
|
||||
mov rsi, 0x0
|
||||
mov rdi, render_thread
|
||||
call pthread_create
|
||||
|
||||
; We can't start playing too early or the missing samples will be audible.
|
||||
mov edi, 0x2
|
||||
call sleep
|
||||
|
||||
; Play the track.
|
||||
mov rdi, pcm_handle
|
||||
mov rsi, default_device
|
||||
mov rdx, SND_PCM_STREAM_PLAYBACK
|
||||
mov rcx, 0x0
|
||||
call snd_pcm_open
|
||||
|
||||
; This is unfortunate. amd64 ABI calling convention kicks in.
|
||||
; now we have to maintain the stack pointer :/
|
||||
mov rdi, qword [pcm_handle]
|
||||
sub rsp, 0x8
|
||||
push SU_LENGTH_IN_SAMPLES
|
||||
%ifdef SU_SAMPLE_FLOAT
|
||||
mov rsi, SND_PCM_FORMAT_FLOAT
|
||||
%else ; SU_SAMPLE_FLOAT
|
||||
mov rsi, SND_PCM_FORMAT_S16_LE
|
||||
%endif ; SU_SAMPLE_FLOAT
|
||||
mov rdx, SND_PCM_ACCESS_RW_INTERLEAVED
|
||||
mov rcx, SU_CHANNEL_COUNT
|
||||
mov r8d, SU_SAMPLE_RATE
|
||||
mov r9d, 0x0
|
||||
call snd_pcm_set_params
|
||||
|
||||
mov rdi, qword [pcm_handle]
|
||||
mov rsi, sound_buffer
|
||||
mov rdx, SU_LENGTH_IN_SAMPLES
|
||||
call snd_pcm_writei
|
||||
|
||||
exit:
|
||||
; At least we can skip the epilogue :)
|
||||
leave
|
||||
ret
|
91
examples/code/asm/amd64/asmwav.elf64.asm
Normal file
91
examples/code/asm/amd64/asmwav.elf64.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:
|
||||
resq 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 rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 0x10
|
||||
|
||||
; Unix does not have gm.dls, no need to ifdef and setup here.
|
||||
|
||||
; We render the complete track here.
|
||||
mov rdi, sound_buffer
|
||||
call su_render_song
|
||||
|
||||
; Now we open the file and save the track.
|
||||
mov rsi, format
|
||||
mov rdi, filename
|
||||
call fopen
|
||||
mov qword [file], rax
|
||||
|
||||
; Write header
|
||||
mov rcx, qword [file]
|
||||
mov rdx, 0x1
|
||||
mov rsi, wave_file_end - wave_file
|
||||
mov rdi, wave_file
|
||||
call fwrite
|
||||
|
||||
; write data
|
||||
mov rcx, qword [file]
|
||||
mov rdx, 0x1
|
||||
mov rsi, SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
mov rdi, sound_buffer
|
||||
call fwrite
|
||||
|
||||
mov rdi, qword [file]
|
||||
call fclose
|
||||
|
||||
exit:
|
||||
; At least we can skip the epilogue :)
|
||||
leave
|
||||
ret
|
Reference in New Issue
Block a user