diff --git a/src/DETHRACE/pc-win95/win95sys.c b/src/DETHRACE/pc-win95/win95sys.c index a55bc58eb..5189e96e6 100644 --- a/src/DETHRACE/pc-win95/win95sys.c +++ b/src/DETHRACE/pc-win95/win95sys.c @@ -415,8 +415,8 @@ void Win32CreateWindow(void) { int width = gGraf_specs[gGraf_spec_index].total_width; int height = gGraf_specs[gGraf_spec_index].total_height; - // WS_VISIBLE | WS_POPUP - gWin32_hwnd = CreateWindowExA_(0, "CarmageddonClass", "Carmageddon", 0x90000000, 0, 0, width, height, 0, NULL, NULL, NULL); + int dwStyle = 0x90000000; // WS_VISIBLE | WS_POPUP + gWin32_hwnd = CreateWindowExA_(0, "CarmageddonClass", "Carmageddon", dwStyle, 0, 0, width, height, 0, NULL, NULL, NULL); SSDXGetWindowRect(gWin32_hwnd); // hdc = GetDC(gWin32_hwnd); // GetSystemPaletteEntries(hdc, 0, 256u, &gWin32_palette); diff --git a/src/S3/CMakeLists.txt b/src/S3/CMakeLists.txt index ef86e2877..4b64f7d51 100644 --- a/src/S3/CMakeLists.txt +++ b/src/S3/CMakeLists.txt @@ -1,13 +1,13 @@ add_library(s3 STATIC) -target_include_directories(s3 +target_include_directories(s3 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} ) -target_link_libraries(s3 PRIVATE brender SDL2::SDL2 harness miniaudio compile_with_werror) +target_link_libraries(s3 PRIVATE brender SDL2::SDL2 harness compile_with_werror) if(NOT MSVC) target_link_libraries(s3 PUBLIC pthread m) @@ -48,6 +48,4 @@ target_sources(s3 PRIVATE s3music.h s3sound.c s3sound.h - backends/miniaudio_backend.c - backends/backend.h ) diff --git a/src/S3/audio.c b/src/S3/audio.c index 216e7e27f..a709f931a 100644 --- a/src/S3/audio.c +++ b/src/S3/audio.c @@ -2,7 +2,7 @@ #include "resource.h" #include "3d.h" -#include "backends/backend.h" +#include "harness/audio.h" #include "harness/config.h" #include "harness/os.h" #include "harness/trace.h" @@ -835,7 +835,7 @@ void S3ServiceOutlets(void) { int S3ServiceChannel(tS3_channel* chan) { if (chan->type == eS3_ST_sample) { - if (AudioBackend_SoundIsPlaying(chan)) { + if (AudioBackend_SoundIsPlaying(chan->type_struct_sample)) { return 1; } S3StopSample(chan); diff --git a/src/S3/backends/backend.h b/src/S3/backends/backend.h deleted file mode 100644 index 2348716ca..000000000 --- a/src/S3/backends/backend.h +++ /dev/null @@ -1,26 +0,0 @@ - -#ifndef BACKEND_H -#define BACKEND_H - -#include "s3_defs.h" - -typedef enum tAudioBackend_error_code { - eAB_success = 0, - eAB_error = 1 -} tAudioBackend_error_code; - -tAudioBackend_error_code AudioBackend_Init(void); -tAudioBackend_error_code AudioBackend_InitCDA(void); -void AudioBackend_UnInit(void); -void AudioBackend_UnInitCDA(void); -void* AudioBackend_AllocateSampleTypeStruct(void); - -// returns 1 if playing, otherwise 0 -int AudioBackend_SoundIsPlaying(tS3_channel* chan); -tAudioBackend_error_code AudioBackend_StopSample(tS3_channel* chan); -tAudioBackend_error_code AudioBackend_PlaySample(tS3_channel* chan); -tAudioBackend_error_code AudioBackend_SetVolume(tS3_channel* chan, int volume); -tAudioBackend_error_code AudioBackend_SetPan(tS3_channel* chan, int pan); -tAudioBackend_error_code AudioBackend_SetFrequency(tS3_channel* chan, int rate); - -#endif diff --git a/src/S3/backends/miniaudio_backend.c b/src/S3/backends/miniaudio_backend.c deleted file mode 100644 index dbfc276be..000000000 --- a/src/S3/backends/miniaudio_backend.c +++ /dev/null @@ -1,150 +0,0 @@ -// Disable miniaudio's 'null' device fallback. A proper device must be found to enable playback -#define MA_NO_NULL - -#include "backend.h" -#include "harness/config.h" -#include "harness/trace.h" -#include "miniaudio/miniaudio.h" -#include "resource.h" -#include "s3_defs.h" -#include -#include -#include - -typedef struct tS3_sample_struct_miniaudio { - ma_audio_buffer_ref buffer_ref; - ma_sound sound; - int initialized; -} tS3_sample_struct_miniaudio; - -ma_engine miniaudio_engine; - -tAudioBackend_error_code AudioBackend_Init(void) { - ma_result result; - - ma_engine_config engineConfig; - engineConfig = ma_engine_config_init(); - result = ma_engine_init(&engineConfig, &miniaudio_engine); - if (result != MA_SUCCESS) { - printf("Failed to initialize audio engine."); - return eAB_error; - } - LOG_INFO("Playback device: '%s'", miniaudio_engine.pDevice->playback.name); - ma_engine_set_volume(&miniaudio_engine, harness_game_config.volume_multiplier); - return eAB_success; -} - -tAudioBackend_error_code AudioBackend_InitCDA(void) { - return eAB_error; -} - -void AudioBackend_UnInit(void) { - ma_engine_uninit(&miniaudio_engine); -} - -void AudioBackend_UnInitCDA(void) { -} - -void* AudioBackend_AllocateSampleTypeStruct(void) { - tS3_sample_struct_miniaudio* sample_struct; - sample_struct = S3MemAllocate(sizeof(tS3_sample_struct_miniaudio), kMem_S3_DOS_SOS_channel); - if (sample_struct == NULL) { - return 0; - } - memset(sample_struct, 0, sizeof(tS3_sample_struct_miniaudio)); - return sample_struct; -} - -tAudioBackend_error_code AudioBackend_PlaySample(tS3_channel* chan) { - tS3_sample_struct_miniaudio* miniaudio; - tS3_sample* sample_data; - ma_result result; - ma_int32 flags; - - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - assert(miniaudio != NULL); - sample_data = (tS3_sample*)chan->descriptor->sound_data; - assert(sample_data != NULL); - - result = ma_audio_buffer_ref_init(ma_format_u8, sample_data->channels, sample_data->dataptr, sample_data->size / sample_data->channels, &miniaudio->buffer_ref); - miniaudio->buffer_ref.sampleRate = sample_data->rate; - if (result != MA_SUCCESS) { - return eAB_error; - } - - flags = MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_NO_SPATIALIZATION; - result = ma_sound_init_from_data_source(&miniaudio_engine, &miniaudio->buffer_ref, flags, NULL, &miniaudio->sound); - if (result != MA_SUCCESS) { - return eAB_error; - } - miniaudio->initialized = 1; - - ma_sound_set_looping(&miniaudio->sound, chan->repetitions == 0); - ma_sound_start(&miniaudio->sound); - return eAB_success; -} - -int AudioBackend_SoundIsPlaying(tS3_channel* chan) { - tS3_sample_struct_miniaudio* miniaudio; - - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - assert(miniaudio != NULL); - - if (ma_sound_is_playing(&miniaudio->sound)) { - return 1; - } - return 0; -} - -tAudioBackend_error_code AudioBackend_SetVolume(tS3_channel* chan, int volume_db) { - tS3_sample_struct_miniaudio* miniaudio; - float linear_volume; - - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - assert(miniaudio != NULL); - - // convert from directsound -10000 - 0 decibel volume scale - linear_volume = ma_volume_db_to_linear(volume_db / 100.0f); - ma_sound_set_volume(&miniaudio->sound, linear_volume); - return eAB_success; -} - -tAudioBackend_error_code AudioBackend_SetPan(tS3_channel* chan, int pan) { - tS3_sample_struct_miniaudio* miniaudio; - - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - assert(miniaudio != NULL); - - // convert from directsound -10000 - 10000 pan scale - ma_sound_set_pan(&miniaudio->sound, pan / 10000.0f); - return eAB_success; -} - -tAudioBackend_error_code AudioBackend_SetFrequency(tS3_channel* chan, int rate) { - tS3_sample_struct_miniaudio* miniaudio; - tS3_sample* sample_data; - - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - assert(miniaudio != NULL); - - sample_data = (tS3_sample*)chan->descriptor->sound_data; - - // convert from directsound frequency to linear pitch scale - ma_sound_set_pitch(&miniaudio->sound, (rate / (float)sample_data->rate)); - return eAB_success; -} - -tAudioBackend_error_code AudioBackend_StopSample(tS3_channel* chan) { - tS3_sample_struct_miniaudio* miniaudio; - - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - assert(miniaudio != NULL); - - if (miniaudio->initialized) { - ma_sound_stop(&miniaudio->sound); - ma_sound_uninit(&miniaudio->sound); - ma_audio_buffer_ref_uninit(&miniaudio->buffer_ref); - miniaudio->initialized = 0; - } - return eAB_success; -} diff --git a/src/S3/s3_defs.h b/src/S3/s3_defs.h index 6d730f4c9..08cdb7d74 100644 --- a/src/S3/s3_defs.h +++ b/src/S3/s3_defs.h @@ -3,7 +3,6 @@ #include "s3/s3.h" -#include #include // extern int PDGetTotalTime(); diff --git a/src/S3/s3sound.c b/src/S3/s3sound.c index 73d4525e6..19c7bb5bd 100644 --- a/src/S3/s3sound.c +++ b/src/S3/s3sound.c @@ -1,6 +1,6 @@ #include "s3sound.h" #include "audio.h" -#include "backends/backend.h" +#include "harness/audio.h" #include "harness/hooks.h" #include "harness/trace.h" #include "resource.h" @@ -259,7 +259,7 @@ int S3StopSample(tS3_channel* chan) { return 0; } - AudioBackend_StopSample(chan); + AudioBackend_StopSample(chan->type_struct_sample); if (chan->active) { chan->needs_service = 1; @@ -280,6 +280,7 @@ int S3ExecuteSampleFilterFuncs(tS3_channel* chan) { } int S3PlaySample(tS3_channel* chan) { + tS3_sample* sound_data; if (chan->type_struct_sample == NULL) { return 0; @@ -288,7 +289,14 @@ int S3PlaySample(tS3_channel* chan) { S3SyncSampleVolumeAndPan(chan); S3SyncSampleRate(chan); - if (AudioBackend_PlaySample(chan) != eAB_success) { + sound_data = (tS3_sample*)chan->descriptor->sound_data; + if (AudioBackend_PlaySample(chan->type_struct_sample, + sound_data->channels, + sound_data->dataptr, + sound_data->size, + sound_data->rate, + chan->repetitions == 0) + != eAB_success) { return 0; } // if (chan->descriptor && chan->descriptor->type == chan->type) { @@ -359,7 +367,7 @@ int S3SyncSampleVolumeAndPan(tS3_channel* chan) { volume_db = 0; } - if (AudioBackend_SetVolume(chan, volume_db) == eAB_success && chan->spatial_sound) { + if (AudioBackend_SetVolume(chan->type_struct_sample, volume_db) == eAB_success && chan->spatial_sound) { if (chan->left_volume != 0 && chan->right_volume > chan->left_volume) { pan_ratio = chan->right_volume / (float)chan->left_volume; @@ -375,24 +383,29 @@ int S3SyncSampleVolumeAndPan(tS3_channel* chan) { } else { pan = 10000; } - AudioBackend_SetPan(chan, pan); + AudioBackend_SetPan(chan->type_struct_sample, pan); } } return 1; } int S3SyncSampleRate(tS3_channel* chan) { + int new_rate; + tS3_sample* sound_data; + if (chan->type != eS3_ST_sample) { return 1; } - int rate = chan->rate; - if (rate >= 100000) { - rate = 100000; + new_rate = chan->rate; + if (new_rate >= 100000) { + new_rate = 100000; } + sound_data = (tS3_sample*)chan->descriptor->sound_data; + // sound_buffer->lpVtbl->SetFrequency(sound_buffer, rate); - AudioBackend_SetFrequency(chan, rate); + AudioBackend_SetFrequency(chan->type_struct_sample, sound_data->rate, new_rate); return 1; } diff --git a/src/harness/CMakeLists.txt b/src/harness/CMakeLists.txt index 6d009d285..74b903987 100644 --- a/src/harness/CMakeLists.txt +++ b/src/harness/CMakeLists.txt @@ -10,7 +10,6 @@ target_include_directories(harness PRIVATE . ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/src/DETHRACE "${CMAKE_CURRENT_BINARY_DIR}" PUBLIC include @@ -20,11 +19,7 @@ if(DETHRACE_FIX_BUGS) target_compile_definitions(harness PRIVATE DETHRACE_FIX_BUGS) endif() -target_link_libraries(harness PRIVATE brender s3 compile_with_werror) - -if(WIN32) - target_link_libraries(harness PRIVATE dbghelp) -endif() +target_link_libraries(harness PRIVATE brender miniaudio compile_with_werror) if(NOT MSVC) target_compile_options(harness PRIVATE @@ -53,14 +48,14 @@ target_sources(harness PRIVATE include/harness/os.h include/harness/win95_polyfill.h include/harness/win95_polyfill_defs.h + include/harness/audio.h # cameras/debug_camera.c # cameras/debug_camera.h ascii_tables.h harness_trace.c harness.c harness.h - sound/sound.c - sound/sound.h + audio/miniaudio.c win95/polyfill.c win95/winsock.c platforms/null.c @@ -70,13 +65,10 @@ target_sources(harness PRIVATE ) if (IO_PLATFORM STREQUAL "SDL2") - target_sources(harness PRIVATE platforms/sdl2.c platforms/sdl2_scancode_to_dinput.h - ) - target_include_directories(harness PRIVATE "${dethrace_SOURCE_DIR}/src/DETHRACE/common") target_link_libraries(harness PRIVATE SDL2::SDL2) endif() @@ -84,7 +76,7 @@ if(WIN32) target_sources(harness PRIVATE os/windows.c ) - target_link_libraries(harness PRIVATE ws2_32) + target_link_libraries(harness PRIVATE dbghelp ws2_32) elseif(APPLE) target_sources(harness PRIVATE os/macos.c diff --git a/src/harness/audio/miniaudio.c b/src/harness/audio/miniaudio.c new file mode 100644 index 000000000..8a96da3bc --- /dev/null +++ b/src/harness/audio/miniaudio.c @@ -0,0 +1,280 @@ +// Disable miniaudio's 'null' device fallback. A proper device must be found to enable playback +#define MA_NO_NULL + +#include "miniaudio/miniaudio.h" +#include "harness/audio.h" +#include "harness/config.h" +#include "harness/trace.h" +#include +#include +#include + +// duplicates DETHRACE/constants.h but is a necessary evil(?) +static int kMem_S3_DOS_SOS_channel = 234; + +typedef struct tMiniaudio_sample { + ma_audio_buffer_ref buffer_ref; + ma_sound sound; + int initialized; +} tMiniaudio_sample; + +typedef struct tMiniaudio_stream { + int frame_size_in_bytes; + int sample_rate; + int needs_converting; + ma_paged_audio_buffer_data paged_audio_buffer_data; + ma_paged_audio_buffer paged_audio_buffer; + ma_data_converter data_converter; + ma_sound sound; +} tMiniaudio_stream; + +ma_engine engine; + +tAudioBackend_error_code AudioBackend_Init(void) { + ma_result result; + ma_engine_config config; + + config = ma_engine_config_init(); + result = ma_engine_init(&config, &engine); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio engine."); + return eAB_error; + } + LOG_INFO("Playback device: '%s'", engine.pDevice->playback.name); + ma_engine_set_volume(&engine, harness_game_config.volume_multiplier); + return eAB_success; +} + +tAudioBackend_error_code AudioBackend_InitCDA(void) { + return eAB_error; +} + +void AudioBackend_UnInit(void) { + ma_engine_uninit(&engine); +} + +void AudioBackend_UnInitCDA(void) { +} + +void* AudioBackend_AllocateSampleTypeStruct(void) { + tMiniaudio_sample* sample_struct; + sample_struct = BrMemAllocate(sizeof(tMiniaudio_sample), kMem_S3_DOS_SOS_channel); + if (sample_struct == NULL) { + return 0; + } + memset(sample_struct, 0, sizeof(tMiniaudio_sample)); + return sample_struct; +} + +tAudioBackend_error_code AudioBackend_PlaySample(void* type_struct_sample, int channels, void* data, int size, int rate, int loop) { + tMiniaudio_sample* miniaudio; + ma_result result; + ma_int32 flags; + + miniaudio = (tMiniaudio_sample*)type_struct_sample; + assert(miniaudio != NULL); + + result = ma_audio_buffer_ref_init(ma_format_u8, channels, data, size / channels, &miniaudio->buffer_ref); + miniaudio->buffer_ref.sampleRate = rate; + if (result != MA_SUCCESS) { + return eAB_error; + } + + flags = MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_NO_SPATIALIZATION; + result = ma_sound_init_from_data_source(&engine, &miniaudio->buffer_ref, flags, NULL, &miniaudio->sound); + if (result != MA_SUCCESS) { + return eAB_error; + } + miniaudio->initialized = 1; + + ma_sound_set_looping(&miniaudio->sound, loop); + ma_sound_start(&miniaudio->sound); + return eAB_success; +} + +int AudioBackend_SoundIsPlaying(void* type_struct_sample) { + tMiniaudio_sample* miniaudio; + + miniaudio = (tMiniaudio_sample*)type_struct_sample; + assert(miniaudio != NULL); + + if (ma_sound_is_playing(&miniaudio->sound)) { + return 1; + } + return 0; +} + +tAudioBackend_error_code AudioBackend_SetVolume(void* type_struct_sample, int volume_db) { + tMiniaudio_sample* miniaudio; + float linear_volume; + + miniaudio = (tMiniaudio_sample*)type_struct_sample; + assert(miniaudio != NULL); + + // convert from directsound -10000 - 0 decibel volume scale + linear_volume = ma_volume_db_to_linear(volume_db / 100.0f); + ma_sound_set_volume(&miniaudio->sound, linear_volume); + return eAB_success; +} + +tAudioBackend_error_code AudioBackend_SetPan(void* type_struct_sample, int pan) { + tMiniaudio_sample* miniaudio; + + miniaudio = (tMiniaudio_sample*)type_struct_sample; + assert(miniaudio != NULL); + + // convert from directsound -10000 - 10000 pan scale + ma_sound_set_pan(&miniaudio->sound, pan / 10000.0f); + return eAB_success; +} + +tAudioBackend_error_code AudioBackend_SetFrequency(void* type_struct_sample, int original_rate, int new_rate) { + tMiniaudio_sample* miniaudio; + + miniaudio = (tMiniaudio_sample*)type_struct_sample; + assert(miniaudio != NULL); + + // convert from directsound frequency to linear pitch scale + ma_sound_set_pitch(&miniaudio->sound, (new_rate / (float)original_rate)); + return eAB_success; +} + +tAudioBackend_error_code AudioBackend_StopSample(void* type_struct_sample) { + tMiniaudio_sample* miniaudio; + + miniaudio = (tMiniaudio_sample*)type_struct_sample; + assert(miniaudio != NULL); + + if (miniaudio->initialized) { + ma_sound_stop(&miniaudio->sound); + ma_sound_uninit(&miniaudio->sound); + ma_audio_buffer_ref_uninit(&miniaudio->buffer_ref); + miniaudio->initialized = 0; + } + return eAB_success; +} + +tAudioBackend_stream* AudioBackend_StreamOpen(int bit_depth, int channels, unsigned int sample_rate) { + tMiniaudio_stream* new; + ma_data_converter_config data_converter_config; + + new = malloc(sizeof(tMiniaudio_stream)); + new->sample_rate = sample_rate; + ma_format format; + switch (bit_depth) { + case 8: + format = ma_format_u8; + new->frame_size_in_bytes = 1 * channels; + break; + case 16: + format = ma_format_s16; + new->frame_size_in_bytes = 2 * channels; + break; + case 24: + format = ma_format_s24; + new->frame_size_in_bytes = 3 * channels; + break; + case 32: + format = ma_format_s32; + new->frame_size_in_bytes = 4 * channels; + break; + default: + goto failed; + } + + if ((new->frame_size_in_bytes == 0) || (ma_paged_audio_buffer_data_init(format, channels, &new->paged_audio_buffer_data) != MA_SUCCESS)) { + LOG_WARN("Failed to create paged audio buffer data"); + goto failed; + } + + ma_paged_audio_buffer_config paged_audio_buffer_config = ma_paged_audio_buffer_config_init(&new->paged_audio_buffer_data); + if (ma_paged_audio_buffer_init(&paged_audio_buffer_config, &new->paged_audio_buffer) != MA_SUCCESS) { + LOG_WARN("Failed to create paged audio buffer for smacker audio stream"); + goto failed; + } + + if (ma_sound_init_from_data_source(&engine, &new->paged_audio_buffer, MA_SOUND_FLAG_NO_PITCH | MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, &new->sound) != MA_SUCCESS) { + LOG_WARN("Failed to create sound from data source"); + goto failed; + } + + // allocate and initialize data converter if miniaudio engine and Smack file soundtrack sample rates differ + if (ma_engine_get_sample_rate(&engine) != sample_rate) { + new->needs_converting = 1; + data_converter_config = ma_data_converter_config_init(format, format, channels, channels, sample_rate, ma_engine_get_sample_rate(&engine)); + if (ma_data_converter_init(&data_converter_config, NULL, &new->data_converter) != MA_SUCCESS) { + LOG_WARN("Failed to create sound data converter"); + goto failed; + } + } + return new; + +failed: + free(new); + return NULL; +} + +tAudioBackend_error_code AudioBackend_StreamWrite(void* stream_handle, const unsigned char* data, unsigned long size) { + tMiniaudio_stream* stream = stream_handle; + ma_uint64 nb_frames_in; + ma_uint64 nb_frames_out; + ma_uint64 current_pos; + ma_paged_audio_buffer_page* new_page; + + if (ma_paged_audio_buffer_get_length_in_pcm_frames(&stream->paged_audio_buffer, ¤t_pos) != MA_SUCCESS) { + LOG_WARN("ma_paged_audio_buffer_get_length_in_pcm_frames failed"); + return eAB_error; + } + + // do we need to convert the sample frequency? + if (stream->needs_converting) { + nb_frames_in = size / stream->frame_size_in_bytes; + nb_frames_out = nb_frames_in * ma_engine_get_sample_rate(&engine) / stream->sample_rate; + + if (ma_paged_audio_buffer_data_allocate_page(&stream->paged_audio_buffer_data, nb_frames_out, NULL, NULL, &new_page) != MA_SUCCESS) { + LOG_WARN("ma_paged_audio_buffer_data_allocate_page failed"); + return eAB_error; + } + if (ma_data_converter_process_pcm_frames(&stream->data_converter, data, &nb_frames_in, new_page->pAudioData, &nb_frames_out) != MA_SUCCESS) { + LOG_WARN("ma_data_converter_process_pcm_frames failed"); + return eAB_error; + } + if (ma_paged_audio_buffer_data_append_page(&stream->paged_audio_buffer_data, new_page) != MA_SUCCESS) { + LOG_WARN("ma_paged_audio_buffer_data_append_page failed"); + return eAB_error; + } + } else { // no sampling frequency conversion needed + if (ma_paged_audio_buffer_data_allocate_and_append_page(&stream->paged_audio_buffer_data, (ma_uint32)(size / (ma_uint64)stream->frame_size_in_bytes), data, NULL) != MA_SUCCESS) { + LOG_WARN("ma_paged_audio_buffer_data_allocate_and_append_page failed"); + return eAB_error; + } + } + + if (!ma_sound_is_playing(&stream->sound)) { + // seek either at start, or where the accumulated value hasn't played yet + if (ma_sound_seek_to_pcm_frame(&stream->sound, current_pos) != MA_SUCCESS) { + LOG_WARN("ma_sound_seek_to_pcm_frame failed"); + } + if (ma_sound_start(&stream->sound) != MA_SUCCESS) { + LOG_WARN("ma_sound_start failed"); + } + } + if (ma_sound_at_end(&stream->sound)) { + LOG_WARN("video not playing fast enough: sound starved!"); + } + return eAB_success; +} + +tAudioBackend_error_code AudioBackend_StreamClose(tAudioBackend_stream* stream_handle) { + tMiniaudio_stream* stream = stream_handle; + if (stream->needs_converting) { + ma_data_converter_uninit(&stream->data_converter, NULL); + } + ma_sound_stop(&stream->sound); + ma_sound_uninit(&stream->sound); + ma_paged_audio_buffer_uninit(&stream->paged_audio_buffer); + ma_paged_audio_buffer_data_uninit(&stream->paged_audio_buffer_data, NULL); + + free(stream); + return eAB_success; +} diff --git a/src/harness/harness.c b/src/harness/harness.c index a428239a7..7d3a5c06d 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -4,7 +4,6 @@ #include "include/harness/hooks.h" #include "include/harness/os.h" #include "platforms/null.h" -#include "sound/sound.h" #include "version.h" #include diff --git a/src/harness/include/harness/audio.h b/src/harness/include/harness/audio.h new file mode 100644 index 000000000..e4d7e5e74 --- /dev/null +++ b/src/harness/include/harness/audio.h @@ -0,0 +1,30 @@ + +#ifndef HARNESS_AUDIO_H +#define HARNESS_AUDIO_H + +typedef enum tAudioBackend_error_code { + eAB_success = 0, + eAB_error = 1 +} tAudioBackend_error_code; + +typedef void tAudioBackend_stream; + +// Used by S3 +tAudioBackend_error_code AudioBackend_Init(void); +void AudioBackend_UnInit(void); +tAudioBackend_error_code AudioBackend_InitCDA(void); +void AudioBackend_UnInitCDA(void); +void* AudioBackend_AllocateSampleTypeStruct(void); +tAudioBackend_error_code AudioBackend_PlaySample(void* type_struct_sample, int channels, void* data, int size, int rate, int loop); +int AudioBackend_SoundIsPlaying(void* type_struct_sample); +tAudioBackend_error_code AudioBackend_StopSample(void* type_struct_sample); +tAudioBackend_error_code AudioBackend_SetVolume(void* type_struct_sample, int volume); +tAudioBackend_error_code AudioBackend_SetPan(void* type_struct_sample, int pan); +tAudioBackend_error_code AudioBackend_SetFrequency(void* type_struct_sample, int original_rate, int new_rate); + +// Used by smackw32 +tAudioBackend_stream* AudioBackend_StreamOpen(int bitdepth, int channels, unsigned int sample_rate); +tAudioBackend_error_code AudioBackend_StreamWrite(tAudioBackend_stream* stream_handle, const unsigned char* data, unsigned long size); +tAudioBackend_error_code AudioBackend_StreamClose(tAudioBackend_stream* stream_handle); + +#endif diff --git a/src/harness/include/harness/hooks.h b/src/harness/include/harness/hooks.h index 967df49d4..5ac5a703a 100644 --- a/src/harness/include/harness/hooks.h +++ b/src/harness/include/harness/hooks.h @@ -5,11 +5,6 @@ #include "harness/win95_polyfill_defs.h" #include -typedef enum { - eFlush_all, - eFlush_color_buffer -} tRenderer_flush_type; - // Platform implementation functions typedef struct tHarness_platform { // Render a fullscreen quad using the specified pixel data diff --git a/src/harness/platforms/sdl2.c b/src/harness/platforms/sdl2.c index 6d58513ff..6ba8ad8cf 100644 --- a/src/harness/platforms/sdl2.c +++ b/src/harness/platforms/sdl2.c @@ -6,25 +6,18 @@ #include "harness/trace.h" #include "sdl2_scancode_to_dinput.h" -#include "globvars.h" -#include "grafdata.h" -#include "pd/sys.h" - SDL_Window* window; SDL_Renderer* renderer; SDL_Texture* screen_texture; uint32_t converted_palette[256]; br_pixelmap* last_screen_src; int render_width, render_height; -int window_width, window_height; Uint32 last_frame_time; uint8_t directinput_key_state[SDL_NUM_SCANCODES]; static void* create_window_and_renderer(char* title, int x, int y, int width, int height) { - window_width = width; - window_height = height; render_width = width; render_height = height; @@ -142,16 +135,20 @@ static int get_mouse_buttons(int* pButton1, int* pButton2) { } static int get_mouse_position(int* pX, int* pY) { + float lX, lY; SDL_GetMouseState(pX, pY); + SDL_RenderWindowToLogical(renderer, *pX, *pY, &lX, &lY); #if defined(DETHRACE_FIX_BUGS) // In hires mode (640x480), the menus are still rendered at (320x240), // so prescale the cursor coordinates accordingly. - *pX *= gGraf_specs[gGraf_data_index].phys_width; - *pX /= gGraf_specs[gReal_graf_data_index].phys_width; - *pY *= gGraf_specs[gGraf_data_index].phys_height; - *pY /= gGraf_specs[gReal_graf_data_index].phys_height; + lX *= 320; + lX /= render_width; + lY *= 200; + lY /= render_height; #endif + *pX = (int)lX; + *pY = (int)lY; return 0; } diff --git a/src/harness/sound/sound.c b/src/harness/sound/sound.c deleted file mode 100644 index 2d866a4c9..000000000 --- a/src/harness/sound/sound.c +++ /dev/null @@ -1,4 +0,0 @@ -#include "sound.h" - -void Sound_Service(void) { -} diff --git a/src/harness/sound/sound.h b/src/harness/sound/sound.h deleted file mode 100644 index 199190601..000000000 --- a/src/harness/sound/sound.h +++ /dev/null @@ -1,8 +0,0 @@ - -#ifndef HARNESS_SOUND_H -#define HARNESS_SOUND_H - -void Sound_Init(void); -void Sound_Service(void); - -#endif diff --git a/src/smackw32/CMakeLists.txt b/src/smackw32/CMakeLists.txt index 2c31c02e8..482f1d1f2 100644 --- a/src/smackw32/CMakeLists.txt +++ b/src/smackw32/CMakeLists.txt @@ -1,10 +1,10 @@ add_library(smackw32 STATIC) -target_include_directories(smackw32 +target_include_directories(smackw32 PUBLIC include PRIVATE - ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR} ) target_link_libraries(smackw32 PRIVATE harness brender libsmacker compile_with_werror) diff --git a/src/smackw32/include/smackw32/smackw32.h b/src/smackw32/include/smackw32/smackw32.h index 77229fd4f..46713ac7d 100644 --- a/src/smackw32/include/smackw32/smackw32.h +++ b/src/smackw32/include/smackw32/smackw32.h @@ -1,3 +1,4 @@ +#include "harness/audio.h" #include #include @@ -43,7 +44,8 @@ typedef struct SmackTag { unsigned long addr32; // added by dethrace - void* smk_handle; + void* smk_handle; // opaque pointer to the libsmacker instance + tAudioBackend_stream* audio_stream; } Smack; Smack* SmackOpen(const char* name, uint32_t flags, uint32_t extrabuf); diff --git a/src/smackw32/smackw32.c b/src/smackw32/smackw32.c index 5c63c8dec..eb261d454 100644 --- a/src/smackw32/smackw32.c +++ b/src/smackw32/smackw32.c @@ -1,4 +1,4 @@ -#include "include/smackw32/smackw32.h" +#include "smackw32/smackw32.h" #include #include @@ -7,18 +7,24 @@ #include #include "harness/hooks.h" +#include "harness/trace.h" + // lib/libsmacker #include "smacker.h" -uint32_t smack_last_frame_time; +static uint32_t smack_last_frame_time = 0; -void copy_palette(Smack* smack) { +static void copy_palette(Smack* smack) { const unsigned char* pal = smk_get_palette(smack->smk_handle); memcpy(smack->Palette, pal, 256 * 3); } Smack* SmackOpen(const char* name, uint32_t flags, uint32_t extrabuf) { - double usf; + unsigned char track_mask_smk; + unsigned char channels_smk[7]; + unsigned char bitdepth_smk[7]; + unsigned long sample_rate_smk[7]; + double microsecs_per_frame; Smack* smack; double fps; @@ -35,12 +41,24 @@ Smack* SmackOpen(const char* name, uint32_t flags, uint32_t extrabuf) { // smk_handle is added to hold a pointer to the underlying libsmacker instance smack->smk_handle = smk_handle; - smk_info_all(smk_handle, NULL, &smack->Frames, &usf); - fps = 1000000.0 / usf; - smack->MSPerFrame = (1 / fps) * 1000; + smk_info_all(smk_handle, NULL, &smack->Frames, µsecs_per_frame); + fps = 1000000.0 / microsecs_per_frame; + smack->MSPerFrame = (unsigned long)((1 / fps) * 1000); smk_info_video(smk_handle, &smack->Width, &smack->Height, NULL); smk_enable_video(smk_handle, 1); + // get info about the audio tracks in this video + smk_info_audio(smk_handle, &track_mask_smk, channels_smk, bitdepth_smk, sample_rate_smk); + + if ((track_mask_smk & SMK_AUDIO_TRACK_0)) { + smack->audio_stream = AudioBackend_StreamOpen(bitdepth_smk[0], channels_smk[0], sample_rate_smk[0]); + if (smack->audio_stream != NULL) { + // tell libsmacker we can process audio now + smk_enable_audio(smk_handle, 0, 1); + } + } + + // load the first frame and return a handle to the Smack file if (smk_first(smk_handle) == SMK_ERROR) { smk_close(smk_handle); free(smack); @@ -51,13 +69,11 @@ Smack* SmackOpen(const char* name, uint32_t flags, uint32_t extrabuf) { } int SmackSoundUseDirectSound(void* dd) { - // TODO: do some miniaudio init - return 0; } void SmackToBuffer(Smack* smack, uint32_t left, uint32_t top, uint32_t pitch, uint32_t destheight, void* buf, uint32_t flags) { - int i, j; + unsigned long i; // Pierre-Marie Baty -- fixed type // minimal implementation assert(left == 0); @@ -73,9 +89,20 @@ void SmackToBuffer(Smack* smack, uint32_t left, uint32_t top, uint32_t pitch, ui } uint32_t SmackDoFrame(Smack* smack) { - smack_last_frame_time = gHarness_platform.GetTicks(); + const unsigned char* audio_data; + unsigned long audio_data_size; + + // process audio if we have some + if (smack->audio_stream != NULL) { + audio_data = smk_get_audio(smack->smk_handle, 0); + audio_data_size = smk_get_audio_size(smack->smk_handle, 0); + if ((audio_data == NULL) || (audio_data_size == 0)) { + return 0; + } + + AudioBackend_StreamWrite(smack->audio_stream, audio_data, audio_data_size); + } - // TODO: audio processing return 0; } @@ -90,10 +117,15 @@ uint32_t SmackWait(Smack* smack) { gHarness_platform.Sleep(1); return 1; } + smack_last_frame_time = now; return 0; } void SmackClose(Smack* smack) { + if (smack->audio_stream != NULL) { + AudioBackend_StreamClose(smack->audio_stream); + } + smk_close(smack->smk_handle); free(smack); }