Audio in cutscenes (#390)

* audio in cutscenes
This commit is contained in:
Dethrace Engineering Department 2024-07-10 06:27:31 +12:00 committed by GitHub
parent ca1098ad91
commit af3019469a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 400 additions and 251 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,6 @@
#include "s3/s3.h"
#include <miniaudio/miniaudio.h>
#include <stdint.h>
// extern int PDGetTotalTime();

View File

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

View File

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

View File

@ -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, &current_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;
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +0,0 @@
#include "sound.h"
void Sound_Service(void) {
}

View File

@ -1,8 +0,0 @@
#ifndef HARNESS_SOUND_H
#define HARNESS_SOUND_H
void Sound_Init(void);
void Sound_Service(void);
#endif

View File

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

View File

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

View File

@ -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, &microsecs_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);
}