parent
ca1098ad91
commit
af3019469a
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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 <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;
|
||||
|
||||
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;
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include "s3/s3.h"
|
||||
|
||||
#include <miniaudio/miniaudio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// extern int PDGetTotalTime();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// 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;
|
||||
}
|
|
@ -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 <errno.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
|
|
@ -5,11 +5,6 @@
|
|||
#include "harness/win95_polyfill_defs.h"
|
||||
#include <stdio.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#include "sound.h"
|
||||
|
||||
void Sound_Service(void) {
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
|
||||
#ifndef HARNESS_SOUND_H
|
||||
#define HARNESS_SOUND_H
|
||||
|
||||
void Sound_Init(void);
|
||||
void Sound_Service(void);
|
||||
|
||||
#endif
|
|
@ -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)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "harness/audio.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "include/smackw32/smackw32.h"
|
||||
#include "smackw32/smackw32.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
@ -7,18 +7,24 @@
|
|||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue