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:
parent
3f61e9b479
commit
7d475fc117
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
54
src/S3/3d.c
54
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
|
||||
int gS3_cda_enabled;
|
||||
|
||||
void S3EnableCDA(void) {
|
||||
gS3_cda_enabled = 1;
|
||||
}
|
||||
|
||||
void S3DisableCDA(void) {
|
||||
S3StopCDAOutlets();
|
||||
gS3_cda_enabled = 0;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "s3_defs.h"
|
||||
|
||||
void S3EnableCDA(void);
|
||||
void S3DisableCDA(void);
|
||||
void S3StopCDAOutlets(void);
|
||||
|
||||
|
|
|
|||
130
src/S3/s3sound.c
130
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 <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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue