Fixes player engine stumbling sound (#332)

* audio backend

* fixes stumbing sound at speed

* implements missing S3ChangePitchSpeed, tidies error codes

---------

Co-authored-by: Jeff Harris <jeff@1amstudios.com>
This commit is contained in:
Dethrace Engineering Department 2023-07-04 07:40:44 +12:00 committed by GitHub
parent 3f61e9b479
commit 7d475fc117
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 347 additions and 166 deletions

View File

@ -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)

View File

@ -265,8 +265,11 @@ int DRS3ChangeSpeed(tS3_sound_tag pTag, tS3_pitch pNew_speed) {
// IDA: int __usercall DRS3ChangePitchSpeed@<EAX>(tS3_sound_tag pTag@<EAX>, tS3_pitch pNew_pitch@<EDX>)
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@<EAX>(tS3_sound_tag pSound_tag@<EAX>)
@ -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) {

View File

@ -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

View File

@ -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;
}

View File

@ -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
)

View File

@ -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) {

26
src/S3/backends/backend.h Normal file
View File

@ -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

View File

@ -0,0 +1,148 @@
#include "backend.h"
#include "harness/config.h"
#include "miniaudio/miniaudio.h"
#include "resource.h"
#include "s3_defs.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
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;
}

View File

@ -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);

View File

@ -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

View File

@ -3,6 +3,10 @@
int gS3_cda_enabled;
void S3EnableCDA(void) {
gS3_cda_enabled = 1;
}
void S3DisableCDA(void) {
S3StopCDAOutlets();
gS3_cda_enabled = 0;

View File

@ -3,6 +3,7 @@
#include "s3_defs.h"
void S3EnableCDA(void);
void S3DisableCDA(void);
void S3StopCDAOutlets(void);

View File

@ -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 <stdio.h>
#include <stdlib.h>
@ -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;
}

View File

@ -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

View File

@ -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 <errno.h>