From 7d475fc117d25b44f8d5f39bf2cb19c2adc78212 Mon Sep 17 00:00:00 2001 From: Dethrace Engineering Department <78985374+dethrace-labs@users.noreply.github.com> Date: Tue, 4 Jul 2023 07:40:44 +1200 Subject: [PATCH] Fixes player engine stumbling sound (#332) * audio backend * fixes stumbing sound at speed * implements missing S3ChangePitchSpeed, tidies error codes --------- Co-authored-by: Jeff Harris --- CMakeLists.txt | 3 +- src/DETHRACE/common/sound.c | 48 +++++---- src/DETHRACE/constants.h | 5 +- src/S3/3d.c | 54 +++++----- src/S3/CMakeLists.txt | 4 +- src/S3/audio.c | 79 +++++++++------ src/S3/backends/backend.h | 26 +++++ src/S3/backends/miniaudio_backend.c | 148 ++++++++++++++++++++++++++++ src/S3/include/s3/s3.h | 1 + src/S3/s3_defs.h | 6 -- src/S3/s3cda.c | 4 + src/S3/s3cda.h | 1 + src/S3/s3sound.c | 130 +++++++++--------------- src/S3/s3sound.h | 2 +- src/harness/harness.c | 2 +- 15 files changed, 347 insertions(+), 166 deletions(-) create mode 100644 src/S3/backends/backend.h create mode 100644 src/S3/backends/miniaudio_backend.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c21e639..98e04180 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ set(DETHRACE_IDE_ROOT_DIR "" CACHE PATH "DethRace rootdir (only used by MSVC whe option(BUILD_TESTS "Build unit tests." OFF) option(DETHRACE_INSTALL "Add install target" OFF) option(DETHRACE_WERROR "Treat warnings as errors") +option(DETHRACE_FIX_BUGS "Fix Dethrace bugs" ON) function(add_compile_flag_if_supported TARGET FLAG) string(MAKE_C_IDENTIFIER "${FLAG}" FLAG_TO_IDENTIFIER) @@ -63,7 +64,7 @@ if(DETHRACE_WERROR) endif() endif() -option(DETHRACE_FIX_BUGS "Fix Dethrace bugs" ON) + add_subdirectory(src/harness) add_subdirectory(src/S3) diff --git a/src/DETHRACE/common/sound.c b/src/DETHRACE/common/sound.c index a74d215b..f445d2ab 100644 --- a/src/DETHRACE/common/sound.c +++ b/src/DETHRACE/common/sound.c @@ -265,8 +265,11 @@ int DRS3ChangeSpeed(tS3_sound_tag pTag, tS3_pitch pNew_speed) { // IDA: int __usercall DRS3ChangePitchSpeed@(tS3_sound_tag pTag@, tS3_pitch pNew_pitch@) int DRS3ChangePitchSpeed(tS3_sound_tag pTag, tS3_pitch pNew_pitch) { LOG_TRACE("(%d, %d)", pTag, pNew_pitch); - STUB_ONCE(); - return 0; + + if (!gSound_enabled) { + return 0; + } + return S3ChangePitchSpeed(pTag, pNew_pitch); } // IDA: int __usercall DRS3StopSound@(tS3_sound_tag pSound_tag@) @@ -550,27 +553,38 @@ void MungeEngineNoise(void) { int type_of_engine_noise; tS3_sound_id engine_noise; + // added by dethrace + tU32 frame_period; + frame_period = gFrame_period; + +#ifdef DETHRACE_FIX_BUGS + // At framerates higher than 30, `gCamera_velocity` is not stable enough and causes the player car audio to stumble + // as the pitch shifts up and down while applying doppler effect in `S3Calculate3D`. + // We avoid the issue by only updating the engine sounds every MUNGE_ENGINE_INTERVAL ms + static tU32 dethrace_last_executed = 0; + + tU32 now = GetTotalTime(); + if (now - dethrace_last_executed < MUNGE_ENGINE_INTERVAL) { + return; + } + frame_period = now - dethrace_last_executed; + dethrace_last_executed = now; +#endif + type_of_engine_noise = 0; if (gSound_available == 0 || gProgram_state.racing == 0) { return; } - gCamera_position = *(br_vector3*)&gCamera_to_world.m[3][0]; - gCamera_left.v[0] = gCamera_to_world.m[0][0] * -1.0; - gCamera_left.v[1] = gCamera_to_world.m[0][1] * -1.0; - gCamera_left.v[2] = gCamera_to_world.m[0][2] * -1.0; - gCamera_velocity.v[0] = gCamera_to_world.m[3][0] - gOld_camera_position.v[0]; - gCamera_velocity.v[1] = gCamera_to_world.m[3][1] - gOld_camera_position.v[1]; - gCamera_velocity.v[2] = gCamera_to_world.m[3][2] - gOld_camera_position.v[2]; - if (gFrame_period) { - gCamera_velocity.v[0] = gCamera_velocity.v[0] / (gFrame_period / 1000.0f); - gCamera_velocity.v[1] = gCamera_velocity.v[1] / (gFrame_period / 1000.0f); - gCamera_velocity.v[2] = gCamera_velocity.v[2] / (gFrame_period / 1000.0f); + + BrVector3Copy(&gCamera_position, (br_vector3*)&gCamera_to_world.m[3][0]); + BrVector3Negate(&gCamera_left, (br_vector3*)&gCamera_to_world.m[0][0]); + BrVector3Sub(&gCamera_velocity, &gCamera_position, &gOld_camera_position); + if (frame_period) { + BrVector3InvScale(&gCamera_velocity, &gCamera_velocity, ((float)frame_period / 1000.0f)); } else { - gCamera_velocity.v[0] = 0.0f; - gCamera_velocity.v[1] = 0.0f; - gCamera_velocity.v[2] = 0.0f; + BrVector3Set(&gCamera_velocity, 0.0f, 0.0f, 0.0f); } - gOld_camera_position = gCamera_position; + BrVector3Copy(&gOld_camera_position, &gCamera_position); stop_all = (gAction_replay_mode && (fabsf(GetReplayRate()) > 1.0f || GetReplayRate() == 0.0f)) || gFaded_palette || gPalette_fade_time; for (cat = eVehicle_self; cat <= eVehicle_rozzer; cat++) { if (cat) { diff --git a/src/DETHRACE/constants.h b/src/DETHRACE/constants.h index 2abdbb09..fbe0cf39 100644 --- a/src/DETHRACE/constants.h +++ b/src/DETHRACE/constants.h @@ -235,7 +235,7 @@ typedef enum keycodes { } keycodes; typedef enum keymapcodes { - KEYMAP_ESCAPE = 0, // default: ESC + KEYMAP_ESCAPE = 0, // default: ESC KEYMAP_CONTROL_ANY = 7, // default: LCTRL or RCTRL (any) KEYMAP_SHIFT_ANY = 8, // default: LSHIFT or RSHIFT (any) @@ -499,4 +499,7 @@ enum { #define DOUBLESIDED_USER_FLAG (void*)12345 +// average frame time in carm95 +#define MUNGE_ENGINE_INTERVAL 50 + #endif diff --git a/src/S3/3d.c b/src/S3/3d.c index 6cb9ed49..f51d6203 100644 --- a/src/S3/3d.c +++ b/src/S3/3d.c @@ -122,35 +122,37 @@ void S3ServiceAmbientSoundSources(void) { s->tag = 0; } - if (s->channel == NULL) { - if (s->time_since_last_played <= s->period || !s->period || s->tag) { - if ((s->ambient_repeats == 0 || s->period == 0) && s->tag == 0) { - if (s->volume > 0 && S3ServiceSoundSource(s) == 0) { - s->channel = NULL; - s->tag = 0; - } - s->time_since_last_played = 0; - } - } else { + if (s->channel != NULL) { + continue; + } + if (s->time_since_last_played <= s->period || !s->period || s->tag) { + if ((s->ambient_repeats == 0 || s->period == 0) && s->tag == 0) { if (s->volume > 0 && S3ServiceSoundSource(s) == 0) { s->channel = NULL; s->tag = 0; } s->time_since_last_played = 0; } + } else { + if (s->volume > 0 && S3ServiceSoundSource(s) == 0) { + s->channel = NULL; + s->tag = 0; + } + s->time_since_last_played = 0; } } } int S3UpdateSpatialSound(tS3_channel* chan) { int close_enough_to_play; // [esp+10h] [ebp-4h] + if (chan->sound_source_ptr && chan->sound_source_ptr->ambient) { close_enough_to_play = S3Calculate3D(chan, 1); } else { close_enough_to_play = S3Calculate3D(chan, 0); } if (close_enough_to_play) { - S3SyncSampleVolume(chan); + S3SyncSampleVolumeAndPan(chan); S3SyncSampleRate(chan); } return close_enough_to_play; @@ -481,8 +483,8 @@ tS3_sound_tag S3StartSound3D(tS3_outlet* pOutlet, tS3_sound_id pSound, tS3_vecto } int S3Calculate3D(tS3_channel* chan, int pIs_ambient) { - float v10; // [esp+2Ch] [ebp-1Ch] - float v11; // [esp+30h] [ebp-18h] + float attenuation; // [esp+2Ch] [ebp-1Ch] + float doppler_shift; // [esp+30h] [ebp-18h] float vol_multiplier; // [esp+38h] [ebp-10h] tS3_sound_source* sound_source_ptr; // [esp+3Ch] [ebp-Ch] float dist_squared; // [esp+40h] [ebp-8h] @@ -518,13 +520,13 @@ int S3Calculate3D(tS3_channel* chan, int pIs_ambient) { dist = sqrtf(dist_squared); } if (pIs_ambient) { - v11 = 1.0f - ((chan->position.z - gS3_listener_position_now.z) * (chan->velocity.z - gS3_listener_vel_now.z) + (chan->velocity.y - gS3_listener_vel_now.y) * (chan->position.y - gS3_listener_position_now.y) + (chan->position.x - gS3_listener_position_now.x) * (chan->velocity.x - gS3_listener_vel_now.x)) / dist / flt_531D98; - if (v11 > 2.0f) { - v11 = 2.0f; - } else if (v11 < 0.5f) { - v11 = 0.5; + doppler_shift = 1.0f - ((chan->position.z - gS3_listener_position_now.z) * (chan->velocity.z - gS3_listener_vel_now.z) + (chan->velocity.y - gS3_listener_vel_now.y) * (chan->position.y - gS3_listener_position_now.y) + (chan->position.x - gS3_listener_position_now.x) * (chan->velocity.x - gS3_listener_vel_now.x)) / dist / flt_531D98; + if (doppler_shift > 2.0f) { + doppler_shift = 2.0f; + } else if (doppler_shift < 0.5f) { + doppler_shift = 0.5; } - chan->rate = chan->initial_pitch * v11; + chan->rate = chan->initial_pitch * doppler_shift; } else { chan->rate = chan->initial_pitch; } @@ -533,20 +535,20 @@ int S3Calculate3D(tS3_channel* chan, int pIs_ambient) { if (!gS3_inside_cockpit) { vol_multiplier = vol_multiplier * 1.3f; } - v10 = (chan->position.z - gS3_listener_position_now.z) * gS3_listener_left_now.z + attenuation = (chan->position.z - gS3_listener_position_now.z) * gS3_listener_left_now.z + (chan->position.y - gS3_listener_position_now.y) * gS3_listener_left_now.y + (chan->position.x - gS3_listener_position_now.x) * gS3_listener_left_now.x; - if (v10 < -1.0) { - v10 = v10 - ceil(v10); + if (attenuation < -1.0f) { + attenuation -= ceil(attenuation); } - if (v10 > 1.0) { - v10 = v10 - floor(v10); + if (attenuation > 1.0f) { + attenuation -= floor(attenuation); } - chan->left_volume = (v10 + 1.0f) / 2.0f * ((double)chan->initial_volume * vol_multiplier) * chan->volume_multiplier; + chan->left_volume = (attenuation + 1.0f) / 2.0f * ((double)chan->initial_volume * vol_multiplier) * chan->volume_multiplier; if (chan->left_volume < 0) { chan->left_volume = 0; } - chan->right_volume = (1.0f - v10) / 2.0f * ((double)chan->initial_volume * vol_multiplier) * chan->volume_multiplier; + chan->right_volume = (1.0f - attenuation) / 2.0f * ((double)chan->initial_volume * vol_multiplier) * chan->volume_multiplier; if (chan->right_volume < 0) { chan->right_volume = 0; } diff --git a/src/S3/CMakeLists.txt b/src/S3/CMakeLists.txt index 2771378c..ef86e287 100644 --- a/src/S3/CMakeLists.txt +++ b/src/S3/CMakeLists.txt @@ -4,7 +4,7 @@ target_include_directories(s3 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" PRIVATE - ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} ) target_link_libraries(s3 PRIVATE brender SDL2::SDL2 harness miniaudio compile_with_werror) @@ -48,4 +48,6 @@ 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 0ec934a6..685301c7 100644 --- a/src/S3/audio.c +++ b/src/S3/audio.c @@ -2,10 +2,10 @@ #include "resource.h" #include "3d.h" +#include "backends/backend.h" #include "harness/config.h" #include "harness/os.h" #include "harness/trace.h" -#include "miniaudio/miniaudio.h" #include "s3/s3.h" #include "s3cda.h" #include "s3music.h" @@ -47,9 +47,6 @@ char gS3_directory_name[8]; int gS3_have_current_dir; char gS3_current_dir[260]; -// dethrace -ma_engine miniaudio_engine; - int dword_5216C0; int S3Init(char* pPath, int pLow_memory_mode) { @@ -143,24 +140,22 @@ int S3OpenOutputDevices(void) { } int S3OpenSampleDevice(void) { - ma_result result; - ma_engine_config engineConfig; - engineConfig = ma_engine_config_init(); - engineConfig.sampleRate = 22050; + // if (DirectSoundCreate(0, &gS3_direct_sound_ptr, 0)) { + // return 0; + // } + // if (gS3_direct_sound_ptr->lpVtbl->SetCooperativeLevel(gS3_direct_sound_ptr, gWin32_hwnd, 3)) { + // return 0; + // } - result = ma_engine_init(&engineConfig, &miniaudio_engine); - if (result != MA_SUCCESS) { - printf("Failed to initialize audio engine."); + if (AudioBackend_Init() != eAB_success) { return 0; } - - ma_engine_set_volume(&miniaudio_engine, harness_game_config.volume_multiplier); - S3Enable(); return 1; } +// returns 0 on failure, 1 on success int S3OpenCDADevice(void) { // gS3_cda_device.lpstrDeviceType = (LPCSTR)516; // if (mciSendCommandA(0, 0x803u, 0x3000u, (DWORD_PTR)&gS3_cda_device) @@ -169,22 +164,27 @@ int S3OpenCDADevice(void) { // } // stru_550560.dwTimeFormat = 10; // MCI_FORMAT_TMSF // mciSendCommandA(gS3_cda_device.wDeviceID, 0x80Du, 0x400u, (DWORD_PTR)&stru_550560); - // S3CDAEnable(); - // return 1; - return 0; + if (AudioBackend_InitCDA() != eAB_success) { + return 0; + } + + S3EnableCDA(); + return 1; } void S3CloseDevices(void) { - // if (gS3_hardware_info.device_installed) { - // gS3_direct_sound_ptr->lpVtbl->Release(gS3_direct_sound_ptr); - // gS3_direct_sound_ptr = NULL; - // } + if (gS3_hardware_info.device_installed) { + // gS3_direct_sound_ptr->lpVtbl->Release(gS3_direct_sound_ptr); + // gS3_direct_sound_ptr = NULL; + + AudioBackend_UnInit(); + } // if (gS3_cda_device.wDeviceID) { // mciSendCommandA(gS3_cda_device.wDeviceID, 0x804u, 0, 0); // MCI_CLOSE // } - ma_engine_uninit(&miniaudio_engine); + AudioBackend_UnInitCDA(); } int S3ReleaseSound(tS3_sound_id id) { @@ -833,14 +833,9 @@ void S3ServiceOutlets(void) { } int S3ServiceChannel(tS3_channel* chan) { - tS3_sample_struct_miniaudio* miniaudio; - if (chan->type == eS3_ST_sample) { - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - if (chan->descriptor && chan->descriptor->type == chan->type) { - if (ma_sound_is_playing(&miniaudio->sound)) { - return 1; - } + if (AudioBackend_SoundIsPlaying(chan)) { + return 1; } S3StopSample(chan); return 0; @@ -1110,6 +1105,30 @@ int S3SoundStillPlaying(tS3_sound_tag pTag) { return S3ServiceChannel(chan) != 0; } +int S3ChangePitchSpeed(tS3_sound_tag pTag, tS3_pitch pNew_pitch) { + tS3_channel* chan; + + if (!gS3_enabled) { + return 0; + } + if (pNew_pitch == -1) { + pNew_pitch = 0x10000; + } + chan = S3GetChannelForTag(pTag); + if (chan == NULL) { + return eS3_error_bad_stag; + } + if (chan->type != eS3_ST_sample) { + return 0; + } + chan->rate = ldexp(pNew_pitch, -16) * ((tS3_sample*)chan->descriptor->sound_data)->rate; + if (S3SyncSampleRate(chan)) { + return 0; + } else { + return eS3_error_function_failed; + } +} + int S3StopSound(tS3_sound_tag pTag) { tS3_channel* chan; // [esp+Ch] [ebp-4h] @@ -1263,7 +1282,7 @@ int S3ChangeVolume(tS3_sound_tag pTag, tS3_volume pVolume) { if (chan->type == eS3_ST_sample) { chan->left_volume = pVolume * chan->volume_multiplier; chan->right_volume = pVolume * chan->volume_multiplier; - if (!S3SyncSampleVolume(chan)) { + if (!S3SyncSampleVolumeAndPan(chan)) { return eS3_error_function_failed; } } else if (chan->type == eS3_ST_midi) { diff --git a/src/S3/backends/backend.h b/src/S3/backends/backend.h new file mode 100644 index 00000000..2348716c --- /dev/null +++ b/src/S3/backends/backend.h @@ -0,0 +1,26 @@ + +#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 new file mode 100644 index 00000000..d7b58b68 --- /dev/null +++ b/src/S3/backends/miniaudio_backend.c @@ -0,0 +1,148 @@ + +#include "backend.h" +#include "harness/config.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; + +// dethrace +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; + } + + 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/include/s3/s3.h b/src/S3/include/s3/s3.h index fb88185b..8319e81c 100644 --- a/src/S3/include/s3/s3.h +++ b/src/S3/include/s3/s3.h @@ -51,6 +51,7 @@ tS3_sound_tag S3StartSound(tS3_outlet_ptr pOutlet, tS3_sound_id pSound); tS3_sound_tag S3StartSound2(tS3_outlet_ptr pOutlet, tS3_sound_id pSound, tS3_repeats pRepeats, tS3_volume pLVolume, tS3_volume pRVolume, tS3_pitch pPitch, tS3_speed pSpeed); void S3StopAllOutletSounds(void); int S3SoundStillPlaying(tS3_sound_tag pSound); +int S3ChangePitchSpeed(tS3_sound_tag pTag, tS3_pitch pNew_pitch); int S3StopSound(tS3_sound_tag pSound_tag); int S3StopOutletSound(tS3_outlet_ptr pOutlet); int S3SetOutletVolume(tS3_outlet_ptr pOutlet, tS3_volume pVolume); diff --git a/src/S3/s3_defs.h b/src/S3/s3_defs.h index e565c824..6d730f4c 100644 --- a/src/S3/s3_defs.h +++ b/src/S3/s3_defs.h @@ -219,10 +219,4 @@ typedef struct wav_header { } wav_header; #pragma pack(pop) -typedef struct tS3_sample_struct_miniaudio { - ma_audio_buffer_ref buffer_ref; - ma_sound sound; - int initialized; -} tS3_sample_struct_miniaudio; - #endif diff --git a/src/S3/s3cda.c b/src/S3/s3cda.c index 09e6df88..bae52e4b 100644 --- a/src/S3/s3cda.c +++ b/src/S3/s3cda.c @@ -3,6 +3,10 @@ int gS3_cda_enabled; +void S3EnableCDA(void) { + gS3_cda_enabled = 1; +} + void S3DisableCDA(void) { S3StopCDAOutlets(); gS3_cda_enabled = 0; diff --git a/src/S3/s3cda.h b/src/S3/s3cda.h index d780e4fa..5658ba8e 100644 --- a/src/S3/s3cda.h +++ b/src/S3/s3cda.h @@ -3,6 +3,7 @@ #include "s3_defs.h" +void S3EnableCDA(void); void S3DisableCDA(void); void S3StopCDAOutlets(void); diff --git a/src/S3/s3sound.c b/src/S3/s3sound.c index c63f4e39..6591d344 100644 --- a/src/S3/s3sound.c +++ b/src/S3/s3sound.c @@ -1,7 +1,7 @@ #include "s3sound.h" #include "audio.h" +#include "backends/backend.h" #include "harness/trace.h" -#include "miniaudio/miniaudio.h" #include "resource.h" #include #include @@ -15,9 +15,6 @@ long gS3_last_file_length; tS3_sample_filter* gS3_sample_filter_func; tS3_sample_filter* gS3_sample_filter_disable_func; -// dethrace -extern ma_engine miniaudio_engine; - int S3LoadSample(tS3_sound_id id) { // changed by dethrace for compatibility // char filename[80]; // [esp+10h] [ebp-5Ch] BYREF @@ -80,7 +77,7 @@ int S3LoadSample(tS3_sound_id id) { return eS3_error_none; } -int S3ReadWavHeader(char* buf, tWAVEFORMATEX_** pWav_format, char** data_ptr, int* pData_size) { +int S3ReadWavHeader_Win95(char* buf, tWAVEFORMATEX_** pWav_format, char** data_ptr, int* pData_size) { int riff_len; char* file_eof; // [esp+10h] [ebp-14h] unsigned int chunk_len; // [esp+18h] [ebp-Ch] @@ -209,7 +206,7 @@ void* S3LoadWavFile_Win95(char* pFile_name, tS3_sample* pSample) { data_size = 0; wav_format = 0; data_ptr = 0; - if (S3ReadWavHeader(buf, &wav_format, &data_ptr, &data_size) == 0) { + if (S3ReadWavHeader_Win95(buf, &wav_format, &data_ptr, &data_size) == 0) { gS3_last_error = eS3_error_readfile; dr_dprintf("ERROR: .WAV file '%s' is crap", pFile_name); return 0; @@ -253,25 +250,18 @@ void* S3LoadWavFile_Win95(char* pFile_name, tS3_sample* pSample) { } int S3StopSample(tS3_channel* chan) { - tS3_sample_struct_miniaudio* miniaudio; - if (chan->tag == 0) { return 1; } - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - if (miniaudio == NULL) { + if (chan->type_struct_sample == NULL) { return 0; } - if (miniaudio->initialized) { - ma_sound_stop(&miniaudio->sound); - ma_sound_uninit(&miniaudio->sound); - ma_audio_buffer_ref_uninit(&miniaudio->buffer_ref); - miniaudio->initialized = 0; - if (chan->active) { - chan->needs_service = 1; - } + AudioBackend_StopSample(chan); + + if (chan->active) { + chan->needs_service = 1; } return 1; @@ -290,60 +280,47 @@ int S3ExecuteSampleFilterFuncs(tS3_channel* chan) { int S3PlaySample(tS3_channel* chan) { - tS3_sample_struct_miniaudio* miniaudio; - tS3_sample* sample_data; - ma_result result; - - S3SyncSampleVolume(chan); - S3SyncSampleRate(chan); - if (chan->descriptor && chan->descriptor->type == chan->type) { - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - sample_data = (tS3_sample*)chan->descriptor->sound_data; - - 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 0; - } - result = ma_sound_init_from_data_source(&miniaudio_engine, &miniaudio->buffer_ref, MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, &miniaudio->sound); - if (result != MA_SUCCESS) { - return 0; - } - miniaudio->initialized = 1; - - ma_sound_set_looping(&miniaudio->sound, chan->repetitions == 0); - ma_sound_start(&miniaudio->sound); - - // dsound_buffer = chan->descriptor->dsound_buffer; - // if (dsound_buffer) { - // dsound_buffer->lpVtbl->SetCurrentPosition(dsound_buffer, 0); - // play_flags = chan->repetitions == 0; // 1 = DSBPLAY_LOOPING - // dsound_buffer->lpVtbl->Play(dsound_buffer, 0, 0, play_flags); - // if (!dsound_buffer->lpVtbl->GetStatus(dsound_buffer, (LPDWORD)&status)) { - // if ((status & 1) != 0) // DSBSTATUS_PLAYING - // { - // dsound_buffer->lpVtbl->SetCurrentPosition(dsound_buffer, 0); - // } else { - // dsound_buffer->lpVtbl->Play(dsound_buffer, 0, 0, play_flags); - // } - // } - // } + if (chan->type_struct_sample == NULL) { + return 0; } + S3SyncSampleVolumeAndPan(chan); + S3SyncSampleRate(chan); + + if (AudioBackend_PlaySample(chan) != eAB_success) { + return 0; + } + // if (chan->descriptor && chan->descriptor->type == chan->type) { + // dsound_buffer = chan->descriptor->dsound_buffer; + // if (dsound_buffer) { + // dsound_buffer->lpVtbl->SetCurrentPosition(dsound_buffer, 0); + // play_flags = chan->repetitions == 0; // 1 = DSBPLAY_LOOPING + // dsound_buffer->lpVtbl->Play(dsound_buffer, 0, 0, play_flags); + // if (!dsound_buffer->lpVtbl->GetStatus(dsound_buffer, (LPDWORD)&status)) { + // if ((status & 1) != 0) // DSBSTATUS_PLAYING + // { + // dsound_buffer->lpVtbl->SetCurrentPosition(dsound_buffer, 0); + // } else { + // dsound_buffer->lpVtbl->Play(dsound_buffer, 0, 0, play_flags); + // } + // } + // } + // } + return 1; } // this function was only called in DOS build int S3CreateTypeStructs(tS3_channel* chan) { - tS3_sample_struct_miniaudio* sample_struct; - sample_struct = S3MemAllocate(sizeof(tS3_sample_struct_miniaudio), kMem_S3_DOS_SOS_channel); - if (sample_struct == NULL) { + void* result; + + result = AudioBackend_AllocateSampleTypeStruct(); + if (result == NULL) { return 0; } - memset(sample_struct, 0, sizeof(tS3_sample_struct_miniaudio)); chan->type_struct_midi = NULL; chan->type_struct_cda = NULL; - chan->type_struct_sample = (char*)sample_struct; + chan->type_struct_sample = (char*)result; return 1; } @@ -359,7 +336,7 @@ int S3ReleaseTypeStructs(tS3_channel* chan) { return 1; } -int S3SyncSampleVolume(tS3_channel* chan) { +int S3SyncSampleVolumeAndPan(tS3_channel* chan) { float pan_ratio; // [esp+38h] [ebp-8h] float total_vol; // [esp+3Ch] [ebp-4h] @@ -367,7 +344,6 @@ int S3SyncSampleVolume(tS3_channel* chan) { int volume_db; int pan; float linear_volume; - tS3_sample_struct_miniaudio* miniaudio; if (chan->type != eS3_ST_sample) { return 1; @@ -382,12 +358,8 @@ int S3SyncSampleVolume(tS3_channel* chan) { volume_db = 0; } - // convert from directsound -10000-0 volume scale - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - linear_volume = ma_volume_db_to_linear(volume_db / 100.0f); - ma_sound_set_volume(&miniaudio->sound, linear_volume); + if (AudioBackend_SetVolume(chan, volume_db) == eAB_success && chan->spatial_sound) { - if (chan->spatial_sound) { if (chan->left_volume != 0 && chan->right_volume > chan->left_volume) { pan_ratio = chan->right_volume / (float)chan->left_volume; } else if (chan->right_volume != 0) { @@ -402,31 +374,25 @@ int S3SyncSampleVolume(tS3_channel* chan) { } else { pan = 10000; } - ma_sound_set_pan(&miniaudio->sound, pan / 10000.0f); + AudioBackend_SetPan(chan, pan); } } return 1; } int S3SyncSampleRate(tS3_channel* chan) { - tS3_sample_struct_miniaudio* miniaudio; - if (chan->type != eS3_ST_sample) { return 1; } - if (chan->descriptor && chan->descriptor->type == chan->type) { - miniaudio = (tS3_sample_struct_miniaudio*)chan->type_struct_sample; - if (miniaudio != NULL) { - int rate = chan->rate; - if (rate >= 100000) { - rate = 100000; - } - // sound_buffer->lpVtbl->SetFrequency(sound_buffer, rate); - // miniaudio uses a linear pitch scale instead of sample rate, so scale it down - ma_sound_set_pitch(&miniaudio->sound, (rate / (float)((tS3_sample*)chan->descriptor->sound_data)->rate)); - } + int rate = chan->rate; + if (rate >= 100000) { + rate = 100000; } + + // sound_buffer->lpVtbl->SetFrequency(sound_buffer, rate); + AudioBackend_SetFrequency(chan, rate); + return 1; } diff --git a/src/S3/s3sound.h b/src/S3/s3sound.h index 224e85cc..02c63fd8 100644 --- a/src/S3/s3sound.h +++ b/src/S3/s3sound.h @@ -15,7 +15,7 @@ int S3CreateTypeStructs(tS3_channel* chan); int S3ReleaseTypeStructs(tS3_channel* chan); int S3StopSample(tS3_channel* chan); int S3ExecuteSampleFilterFuncs(tS3_channel* chan); -int S3SyncSampleVolume(tS3_channel* chan); +int S3SyncSampleVolumeAndPan(tS3_channel* chan); int S3SyncSampleRate(tS3_channel* chan); #endif diff --git a/src/harness/harness.c b/src/harness/harness.c index 4b21abb0..6762be25 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -1,11 +1,11 @@ #include "harness.h" +#include "ascii_tables.h" #include "brender_emu/renderer_impl.h" #include "include/harness/config.h" #include "include/harness/hooks.h" #include "include/harness/os.h" #include "platforms/null.h" #include "sound/sound.h" -#include "ascii_tables.h" #include "version.h" #include