6#include <SDL3_mixer/SDL_mixer.h>
52 if (!MIX_SetTrackFrequencyRatio(sample->
track, ratio)) {
53 DTTR_LOG_ERROR(
"MIX_SetTrackFrequencyRatio failed: %s", SDL_GetError());
74 return sample && sample >=
samples
80 return sample ? (int)(sample -
samples) : -1;
112 MIX_DestroyAudio(sample->
audio);
124 memset(&sample->
wave, 0,
sizeof(sample->
wave));
130 MIX_DestroyTrack(sample->
track);
138 memset(sample, 0,
sizeof(*sample));
149 const void *file_image,
154 float *frames =
NULL;
166 sample->
wave = decoded;
172 const void *file_image,
175 SDL_IOStream *io = SDL_IOFromConstMem(file_image,
size);
182 if (!sample->
audio) {
183 DTTR_LOG_ERROR(
"MIX_LoadAudio_IO sample failed: %s", SDL_GetError());
196 MIX_SetTrackAudio(sample->
track, sample->
audio);
204 MIX_StopTrack(sample->
track, 0);
222 if (in_frames_size > INT_MAX) {
226 const int in_frames = (int)in_frames_size;
228 int64_t out_frames64 = ((int64_t)in_frames * out_rate + sample->
current_rate - 1)
230 if (out_frames64 <= 0 || out_frames64 > INT_MAX) {
234 const int out_frames = (int)out_frames64;
235 float previous_values[8] = {0};
237 if (channels > (
int)SDL_arraysize(previous_values)) {
241 if ((
size_t)out_frames > SIZE_MAX / (
size_t)channels) {
245 const size_t out_values = (size_t)out_frames * (
size_t)channels;
246 if (out_values > SIZE_MAX /
sizeof(
float)) {
250 float *converted = calloc(out_values,
sizeof(
float));
257 uint64_t source_pos = 0;
258 const uint64_t source_step = ((uint64_t)sample->
current_rate << 32) / out_rate;
260 for (
int frame = 0; frame < out_frames; frame++) {
261 size_t source_frame = (size_t)(source_pos >> 32);
263 if (source_frame >= in_frames_size) {
264 source_frame = in_frames_size - 1;
267 for (
int channel = 0; channel < channels; channel++) {
268 const size_t source_index = source_frame * (size_t)channels + (
size_t)channel;
269 const float value = sample->
pcm_frames[source_index];
272 [(size_t)frame * (
size_t)channels
273 + (size_t)channel] = value
274 + preemphasis * (value - previous_values[channel]);
275 previous_values[channel] = value;
278 source_pos += source_step;
281 const SDL_AudioSpec spec = {
282 .format = SDL_AUDIO_F32,
283 .channels = channels,
287 MIX_Audio *audio = MIX_LoadRawAudio(
290 out_values *
sizeof(
float),
295 DTTR_LOG_ERROR(
"MSS sample render load failed: %s", SDL_GetError());
301 sample->
audio = audio;
304 if (!sample->
track) {
308 MIX_SetTrackAudio(sample->
track, sample->
audio);
340 DTTR_LOG_TRACE(
"MSS AIL_allocate_sample_handle(driver=%p)", driver);
343 DTTR_LOG_TRACE(
"MSS AIL_allocate_sample_handle -> NULL (mixer unavailable)");
354 DTTR_LOG_TRACE(
"MSS AIL_allocate_sample_handle -> sample[%d]=%p", i, sample);
358 DTTR_LOG_TRACE(
"MSS AIL_allocate_sample_handle -> NULL (pool exhausted)");
370 "MSS AIL_release_sample_handle(sample[%d]=%p)",
376 memset(sample, 0,
sizeof(*sample));
393 const void *file_image,
398 "MSS AIL_set_sample_file(sample=%p, file=%p, block=%d) -> 0 (invalid)",
409 "MSS AIL_set_sample_file(sample[%d]=%p, file=%p, block=%d)",
419 if (block > 0 &&
size > (
size_t)block) {
420 DTTR_LOG_ERROR(
"AIL_set_sample_file received truncated WAVE data");
431 "MSS AIL_set_sample_file sample[%d] RIFF size=%zu format=%u channels=%u "
444 if (!sample->
track) {
445 DTTR_LOG_ERROR(
"MIX_CreateTrack sample failed: %s", SDL_GetError());
471 "MSS AIL_set_sample_file sample[%d] -> 1 track=%p audio=%p pcm_frames=%zu "
472 "base_rate=%d current_rate=%d",
490 "MSS AIL_start_sample(sample[%d]=%p status=%d loops=%d volume=%d pan=%d "
492 "track=%p audio=%p)",
512 "MSS AIL_start_sample sample[%d] skipped missing track/audio",
524 "MSS AIL_start_sample sample[%d] played sdl_loops=%d",
537 "MSS AIL_stop_sample(sample[%d]=%p status=%d track=%p)",
566 sample->
loops = loops;
601 if (pause_for_rate) {
603 MIX_PauseTrack(sample->
track);
609 "MSS AIL_set_sample_playback_rate(sample[%d]=%p, rate=%d previous=%d) "
628 MIX_ResumeTrack(sample->
track);
633 "MSS AIL_set_sample_playback_rate(sample[%d]=%p, rate=%d previous=%d "
635 "base=%d resumed=%d)",
642 sample->
track ? !MIX_TrackPaused(sample->
track) : 0
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
#define DTTR_LOG_TRACE(...)
#define DTTR_LOG_ERROR(...)
float dttr_mss_core_sample_headroom_gain()
void dttr_mss_core_ensure_preferences()
float dttr_mss_core_master_gain()
float dttr_mss_core_sample_preemphasis()
SDL_AudioSpec dttr_mss_core_mixer_spec()
bool dttr_mss_core_ensure_mixer()
static SDL_AudioSpec mixer_spec
int dttr_mss_core_get_preference(unsigned int preference)
MIX_Mixer * dttr_mss_core_mixer()
#define DTTR_MSS_DEFAULT_RATE
#define DTTR_MSS_PREF_DIG_DEFAULT_VOLUME
float dttr_mss_track_frequency_ratio(int rate, int reference_rate)
static int dttr_mss_loops_to_sdl(int mss_loop_count)
void dttr_mss_wave_free(void *ptr)
#define DTTR_MSS_STATUS_PLAYING
void dttr_mss_track_apply_pan(MIX_Track *track, int pan)
#define DTTR_MSS_STATUS_STOPPED
#define DTTR_MSS_DEFAULT_VOLUME
#define DTTR_MSS_MIXER_RATE
void dttr_mss_track_play(MIX_Track *track, int sdl_loops)
bool dttr_mss_wave_parse(const void *file_image, mss_wave_info *info)
#define DTTR_MSS_STATUS_DONE
float dttr_mss_track_gain(int volume, float master_gain, float headroom)
static bool dttr_mss_sample_rate_pauses_playback(int rate)
size_t dttr_mss_wave_riff_size(const void *file_image)
bool dttr_mss_wave_decode_f32(const void *file_image, size_t size, mss_wave_info *info, float **frames_out)
#define DTTR_MSS_DEFAULT_MIXER_CHANNELS
#define DTTR_MSS_DEFAULT_PAN
int dttr_mss_wave_rate(const mss_wave_info *info)
int dttr_mss_track_status(MIX_Track *track, int previous_status)
#define DTTR_MSS_DEFAULT_LOOP_COUNT
static void destroy_sample_audio_object(mss_sample *sample)
static bool load_sample_audio_from_memory(mss_sample *sample, const void *file_image, size_t size)
void dttr_mss_sample_stop_all()
void dttr_mss_ail_set_sample_loop_count(void *sample_ptr, int loops)
static void apply_sample_track(mss_sample *sample)
void dttr_mss_ail_end_sample(void *sample_ptr)
void dttr_mss_sample_shutdown_all()
static bool is_sample(const void *ptr)
void dttr_mss_ail_start_sample(void *sample_ptr)
static void clear_sample_wave(mss_sample *sample)
void dttr_mss_ail_init_sample(void *sample_ptr)
static void reset_sample_slot(mss_sample *sample)
void dttr_mss_ail_stop_sample(void *sample_ptr)
void dttr_mss_ail_set_sample_pan(void *sample_ptr, int pan)
int dttr_mss_ail_sample_playback_rate(void *sample_ptr)
int dttr_mss_ail_set_sample_file(void *sample_ptr, const void *file_image, int block)
static void free_sample_audio(mss_sample *sample)
static int sample_slot(const mss_sample *sample)
static void stop_sample(mss_sample *sample)
static bool render_sample_audio(mss_sample *sample)
static void apply_rate(mss_sample *sample)
int dttr_mss_ail_sample_status(void *sample_ptr)
static void reset_sample_defaults(mss_sample *sample)
void dttr_mss_ail_set_sample_volume(void *sample_ptr, int volume)
static void apply_sample_gain(mss_sample *sample)
static mss_sample * require_sample(void *sample_ptr)
static mss_sample samples[DTTR_MSS_DEFAULT_MIXER_CHANNELS]
void dttr_mss_ail_set_sample_playback_rate(void *sample_ptr, int rate)
void dttr_mss_sample_apply_master_gain()
void * dttr_mss_ail_allocate_sample_handle(void *driver)
void dttr_mss_ail_release_sample_handle(void *sample_ptr)
static const uint32_t SAMPLE_MAGIC
static bool load_sample_frames(mss_sample *sample, const void *file_image, size_t size, const mss_wave_info *wave)