mirror of
https://github.com/vsariola/sointu.git
synced 2025-07-18 04:54:27 -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
@ -1,34 +1,68 @@
|
||||
# this fixes a bug in creating a static library from asm, similar to
|
||||
# https://discourse.cmake.org/t/building-lib-file-from-asm-cmake-bug/1959
|
||||
# but for NASM
|
||||
if(MSVC)
|
||||
set(CMAKE_ASM_NASM_CREATE_STATIC_LIBRARY "<CMAKE_AR> /OUT:<TARGET> <LINK_FLAGS> <OBJECTS>")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
COMMAND
|
||||
${compilecmd} -arch=${arch} -o physics_girl_st.asm "${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml"
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS
|
||||
"${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml"
|
||||
OUTPUT
|
||||
physics_girl_st.asm
|
||||
physics_girl_st.h
|
||||
physics_girl_st.inc
|
||||
COMMENT
|
||||
"Compiling ${PROJECT_SOURCE_DIR}/examples/patches/physics-girl-st.yml..."
|
||||
COMMAND
|
||||
${compilecmd} -arch=${arch} -o physics_girl_st.asm "${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml"
|
||||
WORKING_DIRECTORY
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS
|
||||
"${PROJECT_SOURCE_DIR}/examples/patches/physics_girl_st.yml"
|
||||
OUTPUT
|
||||
physics_girl_st.asm
|
||||
physics_girl_st.h
|
||||
physics_girl_st.inc
|
||||
COMMENT
|
||||
"Compiling ${PROJECT_SOURCE_DIR}/examples/patches/physics-girl-st.yml..."
|
||||
)
|
||||
|
||||
add_library(physics_girl_st physics_girl_st.asm)
|
||||
add_dependencies(physics_girl_st sointu-compiler)
|
||||
|
||||
if(WIN32)
|
||||
add_executable(cplay
|
||||
cplay.windows.c
|
||||
physics_girl_st.h
|
||||
)
|
||||
target_link_libraries(cplay PRIVATE winmm)
|
||||
add_executable(cplay-winmm
|
||||
cplay.windows.winmm.c
|
||||
physics_girl_st.h
|
||||
)
|
||||
target_link_libraries(cplay-winmm PRIVATE winmm)
|
||||
target_link_libraries(cplay-winmm PRIVATE physics_girl_st)
|
||||
target_include_directories(cplay-winmm PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_dependencies(examples cplay-winmm)
|
||||
|
||||
add_executable(cplay-directsound
|
||||
cplay.windows.directsound.c
|
||||
physics_girl_st.h
|
||||
)
|
||||
target_link_libraries(cplay-directsound PRIVATE dsound ws2_32 ucrt)
|
||||
target_link_libraries(cplay-directsound PRIVATE physics_girl_st)
|
||||
target_include_directories(cplay-directsound PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_dependencies(examples cplay-directsound)
|
||||
elseif(UNIX)
|
||||
add_executable(cplay
|
||||
cplay.unix.c
|
||||
physics_girl_st.h
|
||||
)
|
||||
target_link_libraries(cplay PRIVATE asound pthread)
|
||||
target_link_options(cplay PRIVATE -z noexecstack -no-pie)
|
||||
add_executable(cplay
|
||||
cplay.unix.c
|
||||
physics_girl_st.h
|
||||
)
|
||||
target_link_libraries(cplay PRIVATE asound pthread)
|
||||
target_link_options(cplay PRIVATE -z noexecstack -no-pie)
|
||||
target_link_libraries(cplay PRIVATE physics_girl_st)
|
||||
target_include_directories(cplay PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
add_dependencies(examples cplay)
|
||||
endif()
|
||||
target_link_libraries(cplay PRIVATE physics_girl_st)
|
||||
target_include_directories(cplay PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_executable(cwav
|
||||
cwav.c
|
||||
physics_girl_st.h
|
||||
)
|
||||
if(WIN32)
|
||||
target_compile_definitions(cwav PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
elseif(UNIX)
|
||||
target_link_options(cwav PRIVATE -z noexecstack -no-pie)
|
||||
endif()
|
||||
target_link_libraries(cwav PRIVATE physics_girl_st)
|
||||
target_include_directories(cwav PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_dependencies(examples cwav)
|
||||
|
@ -20,7 +20,19 @@ int main(int argc, char **args) {
|
||||
|
||||
// Play the track.
|
||||
snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
|
||||
snd_pcm_set_params(pcm_handle, SND_PCM_FORMAT_FLOAT, SND_PCM_ACCESS_RW_INTERLEAVED, SU_CHANNEL_COUNT, SU_SAMPLE_RATE, 0, SU_LENGTH_IN_SAMPLES);
|
||||
snd_pcm_set_params(
|
||||
pcm_handle,
|
||||
#ifdef SU_SAMPLE_FLOAT
|
||||
SND_PCM_FORMAT_FLOAT,
|
||||
#else // SU_SAMPLE_FLOAT
|
||||
SND_PCM_FORMAT_S16_LE,
|
||||
#endif // SU_SAMPLE_FLOAT
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
SU_CHANNEL_COUNT,
|
||||
SU_SAMPLE_RATE,
|
||||
0,
|
||||
SU_LENGTH_IN_SAMPLES
|
||||
);
|
||||
snd_pcm_writei(pcm_handle, sound_buffer, SU_LENGTH_IN_SAMPLES);
|
||||
|
||||
return 0;
|
||||
|
75
examples/code/C/cplay.windows.directsound.c
Normal file
75
examples/code/C/cplay.windows.directsound.c
Normal file
@ -0,0 +1,75 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "physics_girl_st.h"
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_EXTRA_LEAN
|
||||
#include <Windows.h>
|
||||
#include "mmsystem.h"
|
||||
#include "mmreg.h"
|
||||
#define CINTERFACE
|
||||
#include <dsound.h>
|
||||
|
||||
#ifndef DSBCAPS_TRUEPLAYPOSITION // Not defined in MinGW dsound headers, so let's add it
|
||||
#define DSBCAPS_TRUEPLAYPOSITION 0x00080000
|
||||
#endif
|
||||
|
||||
SUsample sound_buffer[SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT];
|
||||
WAVEFORMATEX wave_format = {
|
||||
#ifdef SU_SAMPLE_FLOAT
|
||||
WAVE_FORMAT_IEEE_FLOAT,
|
||||
#else
|
||||
WAVE_FORMAT_PCM,
|
||||
#endif
|
||||
SU_CHANNEL_COUNT,
|
||||
SU_SAMPLE_RATE,
|
||||
SU_SAMPLE_RATE * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT,
|
||||
SU_SAMPLE_SIZE * SU_CHANNEL_COUNT,
|
||||
SU_SAMPLE_SIZE*8,
|
||||
0
|
||||
};
|
||||
DSBUFFERDESC buffer_description = {
|
||||
sizeof(DSBUFFERDESC),
|
||||
DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_TRUEPLAYPOSITION,
|
||||
SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT,
|
||||
0,
|
||||
&wave_format,
|
||||
0
|
||||
};
|
||||
|
||||
int main(int argc, char **args) {
|
||||
// Load gm.dls if necessary.
|
||||
#ifdef SU_LOAD_GMDLS
|
||||
su_load_gmdls();
|
||||
#endif // SU_LOAD_GMDLS
|
||||
|
||||
HWND hWnd = GetForegroundWindow();
|
||||
if(hWnd == NULL) {
|
||||
hWnd = GetDesktopWindow();
|
||||
}
|
||||
|
||||
LPDIRECTSOUND direct_sound;
|
||||
LPDIRECTSOUNDBUFFER direct_sound_buffer;
|
||||
DirectSoundCreate(0, &direct_sound, 0);
|
||||
IDirectSound_SetCooperativeLevel(direct_sound, hWnd, DSSCL_PRIORITY);
|
||||
IDirectSound_CreateSoundBuffer(direct_sound, &buffer_description, &direct_sound_buffer, NULL);
|
||||
|
||||
LPVOID p1;
|
||||
DWORD l1;
|
||||
IDirectSoundBuffer_Lock(direct_sound_buffer, 0, SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT * SU_SAMPLE_SIZE, &p1, &l1, NULL, NULL, 0);
|
||||
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)su_render_song, p1, 0, 0);
|
||||
IDirectSoundBuffer_Play(direct_sound_buffer, 0, 0, 0);
|
||||
|
||||
// We need to handle windows messages properly while playing, as waveOutWrite is async.
|
||||
MSG msg = {0};
|
||||
DWORD last_play_cursor = 0;
|
||||
for(DWORD play_cursor = 0; play_cursor >= last_play_cursor; IDirectSoundBuffer_GetCurrentPosition(direct_sound_buffer, (DWORD*)&play_cursor, NULL)) {
|
||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
||||
}
|
||||
|
||||
last_play_cursor = play_cursor;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
|
||||
SUsample sound_buffer[SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT];
|
||||
HWAVEOUT wave_out_handle;
|
||||
WAVEFORMATEX WaveFMT = {
|
||||
WAVEFORMATEX wave_format = {
|
||||
#ifdef SU_SAMPLE_FLOAT
|
||||
WAVE_FORMAT_IEEE_FLOAT,
|
||||
#else
|
||||
@ -22,7 +22,7 @@ WAVEFORMATEX WaveFMT = {
|
||||
SU_SAMPLE_SIZE*8,
|
||||
0
|
||||
};
|
||||
WAVEHDR WaveHDR = {
|
||||
WAVEHDR wave_header = {
|
||||
(LPSTR)sound_buffer,
|
||||
SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT,
|
||||
0,
|
||||
@ -32,7 +32,7 @@ WAVEHDR WaveHDR = {
|
||||
0,
|
||||
0
|
||||
};
|
||||
MMTIME MMTime = {
|
||||
MMTIME mmtime = {
|
||||
TIME_SAMPLES,
|
||||
0
|
||||
};
|
||||
@ -48,11 +48,11 @@ int main(int argc, char **args) {
|
||||
// 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.
|
||||
waveOutOpen(&wave_out_handle, WAVE_MAPPER, &WaveFMT, 0, 0, CALLBACK_NULL);
|
||||
waveOutWrite(wave_out_handle, &WaveHDR, sizeof(WaveHDR));
|
||||
waveOutOpen(&wave_out_handle, WAVE_MAPPER, &wave_format, 0, 0, CALLBACK_NULL);
|
||||
waveOutWrite(wave_out_handle, &wave_header, sizeof(wave_header));
|
||||
|
||||
// We need to handle windows messages properly while playing, as waveOutWrite is async.
|
||||
for(MSG msg = {0}; MMTime.u.sample != SU_LENGTH_IN_SAMPLES; waveOutGetPosition(wave_out_handle, &MMTime, sizeof(MMTIME))) {
|
||||
for(MSG msg = {0}; mmtime.u.sample != SU_LENGTH_IN_SAMPLES; waveOutGetPosition(wave_out_handle, &mmtime, sizeof(MMTIME))) {
|
||||
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageA(&msg);
|
72
examples/code/C/cwav.c
Normal file
72
examples/code/C/cwav.c
Normal file
@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "physics_girl_st.h"
|
||||
|
||||
#define WAVE_FORMAT_PCM 0x1
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x3
|
||||
|
||||
static SUsample sound_buffer[SU_LENGTH_IN_SAMPLES * SU_CHANNEL_COUNT];
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
char riff[4];
|
||||
uint32_t file_size;
|
||||
char wavefmt[8];
|
||||
} riff_header_t;
|
||||
|
||||
typedef struct {
|
||||
char data[4];
|
||||
uint32_t data_size;
|
||||
} data_header_t;
|
||||
|
||||
typedef struct {
|
||||
riff_header_t riff_header;
|
||||
uint32_t riff_header_size;
|
||||
uint16_t sample_type;
|
||||
uint16_t channel_count;
|
||||
uint32_t sample_rate;
|
||||
uint32_t bytes_per_second;
|
||||
uint16_t bytes_per_channel;
|
||||
uint16_t bits_per_sample;
|
||||
data_header_t data_header;
|
||||
} wave_header_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
int main(int argc, char **args) {
|
||||
wave_header_t wave_header = {
|
||||
.riff_header = (riff_header_t) {
|
||||
.riff = "RIFF",
|
||||
.file_size = sizeof(wave_header_t) + SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT,
|
||||
.wavefmt = "WAVEfmt ",
|
||||
},
|
||||
.riff_header_size = sizeof(riff_header_t),
|
||||
#ifdef SU_SAMPLE_FLOAT
|
||||
.sample_type = WAVE_FORMAT_IEEE_FLOAT,
|
||||
#else // SU_SAMPLE_FLOAT
|
||||
.sample_type = WAVE_FORMAT_PCM,
|
||||
#endif // SU_SAMPLE_FLOAT
|
||||
.channel_count = SU_CHANNEL_COUNT,
|
||||
.sample_rate = SU_SAMPLE_RATE,
|
||||
.bytes_per_second = SU_SAMPLE_SIZE * SU_SAMPLE_RATE * SU_CHANNEL_COUNT,
|
||||
.bytes_per_channel = SU_SAMPLE_SIZE * SU_CHANNEL_COUNT,
|
||||
.bits_per_sample = SU_SAMPLE_SIZE * 8,
|
||||
.data_header = (data_header_t) {
|
||||
.data = "data",
|
||||
.data_size = sizeof(data_header_t) + SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT
|
||||
}
|
||||
};
|
||||
|
||||
// Load gm.dls if necessary.
|
||||
#ifdef SU_LOAD_GMDLS
|
||||
su_load_gmdls();
|
||||
#endif // SU_LOAD_GMDLS
|
||||
|
||||
su_render_song(sound_buffer);
|
||||
|
||||
FILE *file = fopen("physics_girl_st.wav", "wb");
|
||||
fwrite(&wave_header, sizeof(wave_header_t), 1, file);
|
||||
fwrite((uint8_t *)sound_buffer, 1, SU_LENGTH_IN_SAMPLES * SU_SAMPLE_SIZE * SU_CHANNEL_COUNT, file);
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user