diff --git a/audio/audio_driver.c b/audio/audio_driver.c index 10dcbc5b38..e9a024e210 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -106,7 +106,7 @@ static const audio_driver_t *audio_drivers[] = { &audio_rwebaudio, #endif #if defined(PSP) || defined(VITA) - &audio_psp, + &audio_psp, #endif #ifdef _3DS &audio_ctr_csnd, @@ -122,38 +122,43 @@ static size_t audio_driver_chunk_block_size = 0; static size_t audio_driver_rewind_ptr = 0; static size_t audio_driver_rewind_size = 0; -static int16_t *audio_driver_rewind_buf = NULL; -static float *audio_driver_input_data = NULL; +static int16_t *audio_driver_rewind_buf = NULL; +static int16_t *audio_driver_output_samples_conv_buf = NULL; static unsigned audio_driver_free_samples_buf[AUDIO_BUFFER_FREE_SAMPLES_COUNT]; static uint64_t audio_driver_free_samples_count = 0; -static float *audio_driver_output_samples_buf = NULL; -static int16_t *audio_driver_output_samples_conv_buf = NULL; - -static float audio_driver_volume_gain = 0.0f; - static size_t audio_driver_buffer_size = 0; static size_t audio_driver_data_ptr = 0; -static bool audio_driver_control = false; +static bool audio_driver_control = false; +static bool audio_driver_mute_enable = false; +static bool audio_driver_use_float = false; +static bool audio_driver_active = false; +static bool audio_driver_data_own = false; +static bool audio_mixer_active = false; + +static float audio_driver_rate_control_delta = 0.0f; static float audio_driver_input = 0.0f; +static float audio_driver_volume_gain = 0.0f; + +static float *audio_driver_input_data = NULL; +static float *audio_driver_output_samples_buf = NULL; + static double audio_source_ratio_original = 0.0f; static double audio_source_ratio_current = 0.0f; + static struct retro_audio_callback audio_callback = {0}; static retro_dsp_filter_t *audio_driver_dsp = NULL; static struct string_list *audio_driver_devices_list = NULL; static const retro_resampler_t *audio_driver_resampler = NULL; + static void *audio_driver_resampler_data = NULL; static const audio_driver_t *current_audio = NULL; static void *audio_driver_context_audio_data = NULL; -static bool audio_driver_use_float = false; -static bool audio_driver_active = false; -static bool audio_driver_data_own = false; - /** * compute_audio_buffer_statistics: * @@ -464,6 +469,8 @@ static bool audio_driver_init_internal(bool audio_cb_inited) audio_driver_free_samples_count = 0; + audio_mixer_init(settings->uints.audio_out_rate); + /* Threaded driver is initially stopped. */ if ( audio_driver_active @@ -513,7 +520,6 @@ static bool audio_driver_flush(const int16_t *data, size_t samples) bool is_slowmotion = false; const void *output_data = NULL; unsigned output_frames = 0; - settings_t *settings = config_get_ptr(); src_data.data_in = NULL; src_data.data_out = NULL; @@ -527,7 +533,7 @@ static bool audio_driver_flush(const int16_t *data, size_t samples) runloop_get_status(&is_paused, &is_idle, &is_slowmotion, &is_perfcnt_enable); - if (is_paused || settings->bools.audio_mute_enable) + if (is_paused || audio_driver_mute_enable) return true; if (!audio_driver_active || !audio_driver_input_data) return false; @@ -555,8 +561,8 @@ static bool audio_driver_flush(const int16_t *data, size_t samples) if (dsp_data.output) { - src_data.data_in = dsp_data.output; - src_data.input_frames = dsp_data.output_frames; + src_data.data_in = dsp_data.output; + src_data.input_frames = dsp_data.output_frames; } } @@ -572,14 +578,15 @@ static bool audio_driver_flush(const int16_t *data, size_t samples) (int)current_audio->write_avail(audio_driver_context_audio_data); int delta_mid = avail - half_size; double direction = (double)delta_mid / half_size; - double adjust = 1.0 + settings->floats.audio_rate_control_delta * direction; + double adjust = 1.0 + audio_driver_rate_control_delta * direction; #if 0 RARCH_LOG_OUTPUT("[Audio]: Audio buffer is %u%% full\n", (unsigned)(100 - (avail * 100) / audio_driver_buffer_size)); #endif - audio_driver_free_samples_buf[write_idx] = avail; + audio_driver_free_samples_buf + [write_idx] = avail; audio_source_ratio_current = audio_source_ratio_original * adjust; @@ -590,25 +597,31 @@ static bool audio_driver_flush(const int16_t *data, size_t samples) #endif } - src_data.ratio = audio_source_ratio_current; + src_data.ratio = audio_source_ratio_current; if (is_slowmotion) - src_data.ratio *= settings->floats.slowmotion_ratio; + { + settings_t *settings = config_get_ptr(); + src_data.ratio *= settings->floats.slowmotion_ratio; + } audio_driver_resampler->process(audio_driver_resampler_data, &src_data); - output_data = audio_driver_output_samples_buf; - output_frames = (unsigned)src_data.output_frames; + if (audio_mixer_active) + audio_mixer_mix(audio_driver_output_samples_buf, src_data.output_frames); + + output_data = audio_driver_output_samples_buf; + output_frames = (unsigned)src_data.output_frames; if (audio_driver_use_float) - output_frames *= sizeof(float); + output_frames *= sizeof(float); else { convert_float_to_s16(audio_driver_output_samples_conv_buf, (const float*)output_data, output_frames * 2); - output_data = audio_driver_output_samples_conv_buf; - output_frames *= sizeof(int16_t); + output_data = audio_driver_output_samples_conv_buf; + output_frames *= sizeof(int16_t); } if (current_audio->write(audio_driver_context_audio_data, @@ -754,6 +767,7 @@ void audio_driver_monitor_adjust_system_rates(void) const struct retro_system_timing *info = NULL; struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); float video_refresh_rate = settings->floats.video_refresh_rate; + float max_timing_skew = settings->floats.audio_max_timing_skew; if (av_info) info = (const struct retro_system_timing*)&av_info->timing; @@ -764,7 +778,7 @@ void audio_driver_monitor_adjust_system_rates(void) timing_skew = fabs(1.0f - info->fps / video_refresh_rate); audio_driver_input = info->sample_rate; - if (timing_skew <= settings->floats.audio_max_timing_skew) + if (timing_skew <= max_timing_skew) audio_driver_input *= (video_refresh_rate / info->fps); RARCH_LOG("[Audio]: Set audio input rate to: %.2f Hz.\n", @@ -872,6 +886,7 @@ bool audio_driver_get_devices_list(void **data) bool audio_driver_deinit(void) { + audio_mixer_done(); audio_driver_free_devices_list(); if (!audio_driver_deinit_internal()) return false; @@ -937,14 +952,13 @@ bool audio_driver_has_callback(void) bool audio_driver_toggle_mute(void) { settings_t *settings = config_get_ptr(); - bool new_mute_state = !settings->bools.audio_mute_enable; + bool new_mute_state = !audio_driver_mute_enable; if (!audio_driver_context_audio_data) return false; if (!audio_driver_active) return false; - configuration_set_bool(settings, - settings->bools.audio_mute_enable, new_mute_state); + audio_driver_mute_enable = new_mute_state; if (new_mute_state) command_event(CMD_EVENT_AUDIO_STOP, NULL); @@ -1038,3 +1052,44 @@ void audio_driver_destroy(void) audio_driver_data_own = false; current_audio = NULL; } + +void audio_set_float(enum audio_action action, float val) +{ + switch (action) + { + case AUDIO_ACTION_RATE_CONTROL_DELTA: + audio_driver_rate_control_delta = val; + break; + case AUDIO_ACTION_NONE: + default: + break; + } +} + +float *audio_get_float_ptr(enum audio_action action) +{ + switch (action) + { + case AUDIO_ACTION_RATE_CONTROL_DELTA: + return &audio_driver_rate_control_delta; + case AUDIO_ACTION_NONE: + default: + break; + } + + return NULL; +} + +bool *audio_get_bool_ptr(enum audio_action action) +{ + switch (action) + { + case AUDIO_ACTION_MUTE_ENABLE: + return &audio_driver_mute_enable; + case AUDIO_ACTION_NONE: + default: + break; + } + + return NULL; +} diff --git a/audio/audio_driver.h b/audio/audio_driver.h index 4e4bc795cd..d20aca26c4 100644 --- a/audio/audio_driver.h +++ b/audio/audio_driver.h @@ -33,6 +33,13 @@ RETRO_BEGIN_DECLS #define AUDIO_MAX_RATIO 16 +enum audio_action +{ + AUDIO_ACTION_NONE = 0, + AUDIO_ACTION_RATE_CONTROL_DELTA, + AUDIO_ACTION_MUTE_ENABLE +}; + typedef struct audio_driver { /* Creates and initializes handle to audio driver. @@ -209,6 +216,12 @@ void audio_driver_unset_callback(void); void audio_driver_frame_is_reverse(void); +void audio_set_float(enum audio_action action, float val); + +float *audio_get_float_ptr(enum audio_action action); + +bool *audio_get_bool_ptr(enum audio_action action); + bool audio_driver_deinit(void); bool audio_driver_init(void); diff --git a/audiomixer-test.diff b/audiomixer-test.diff index ffd7bc6aba..1581b11694 100644 --- a/audiomixer-test.diff +++ b/audiomixer-test.diff @@ -1,8 +1,17 @@ diff --git a/audio/audio_driver.c b/audio/audio_driver.c -index 10dcbc5b3..203e89d0a 100644 +index 10dcbc5b3..0d2bb4d85 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c -@@ -597,6 +597,8 @@ static bool audio_driver_flush(const int16_t *data, size_t samples) +@@ -464,6 +464,8 @@ static bool audio_driver_init_internal(bool audio_cb_inited) + + audio_driver_free_samples_count = 0; + ++ audio_mixer_init(48000); ++ + /* Threaded driver is initially stopped. */ + if ( + audio_driver_active +@@ -597,6 +599,8 @@ static bool audio_driver_flush(const int16_t *data, size_t samples) audio_driver_resampler->process(audio_driver_resampler_data, &src_data); @@ -21,7 +30,7 @@ index 0e3a8dc44..4f79b2ed7 100644 if (runloop_cmd_triggered(trigger_input, RARCH_RESET)) + { command_event(CMD_EVENT_RESET, NULL); -+ audio_mixer_load_wav("/home/squarepusher/piano2.wav"); ++ audio_mixer_load_ogg("/home/squarepusher/SumertimeBlues.ogg"); + } cheat_manager_state_checks( diff --git a/command.c b/command.c index 19647df0d0..f2b426a106 100644 --- a/command.c +++ b/command.c @@ -2060,7 +2060,8 @@ bool command_event(enum event_command cmd, void *data) case CMD_EVENT_AUDIO_MUTE_TOGGLE: { settings_t *settings = config_get_ptr(); - const char *msg = !settings->bools.audio_mute_enable ? + bool audio_mute_enable = *(audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE)); + const char *msg = !audio_mute_enable ? msg_hash_to_str(MSG_AUDIO_MUTED): msg_hash_to_str(MSG_AUDIO_UNMUTED); diff --git a/configuration.c b/configuration.c index 066b3b8c07..f309498123 100644 --- a/configuration.c +++ b/configuration.c @@ -1152,7 +1152,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("keyboard_gamepad_enable", &settings->bools.input_keyboard_gamepad_enable, true, true, false); SETTING_BOOL("core_set_supports_no_game_enable", &settings->bools.set_supports_no_game_enable, true, true, false); SETTING_BOOL("audio_enable", &settings->bools.audio_enable, true, audio_enable, false); - SETTING_BOOL("audio_mute_enable", &settings->bools.audio_mute_enable, true, false, false); + SETTING_BOOL("audio_mute_enable", audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE), true, false, false); SETTING_BOOL("location_allow", &settings->bools.location_allow, true, false, false); SETTING_BOOL("video_font_enable", &settings->bools.video_font_enable, true, font_enable, false); SETTING_BOOL("core_updater_auto_extract_archive", &settings->bools.network_buildbot_auto_extract_archive, true, true, false); @@ -1266,7 +1266,7 @@ static struct config_float_setting *populate_settings_float(settings_t *settings SETTING_FLOAT("video_aspect_ratio", &settings->floats.video_aspect_ratio, true, aspect_ratio, false); SETTING_FLOAT("video_scale", &settings->floats.video_scale, false, 0.0f, false); SETTING_FLOAT("video_refresh_rate", &settings->floats.video_refresh_rate, true, refresh_rate, false); - SETTING_FLOAT("audio_rate_control_delta", &settings->floats.audio_rate_control_delta, true, rate_control_delta, false); + SETTING_FLOAT("audio_rate_control_delta", audio_get_float_ptr(AUDIO_ACTION_RATE_CONTROL_DELTA), true, rate_control_delta, false); SETTING_FLOAT("audio_max_timing_skew", &settings->floats.audio_max_timing_skew, true, max_timing_skew, false); SETTING_FLOAT("audio_volume", &settings->floats.audio_volume, true, audio_volume, false); #ifdef HAVE_OVERLAY diff --git a/configuration.h b/configuration.h index 8d9516709e..43d71d40e2 100644 --- a/configuration.h +++ b/configuration.h @@ -74,7 +74,6 @@ typedef struct settings /* Audio */ bool audio_enable; - bool audio_mute_enable; bool audio_sync; bool audio_rate_control; #ifdef HAVE_WASAPI @@ -229,7 +228,6 @@ typedef struct settings float menu_footer_opacity; float menu_header_opacity; - float audio_rate_control_delta; float audio_max_timing_skew; float audio_volume; /* dB scale. */ diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index f5b5d038c0..cf20e13948 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -46,13 +46,16 @@ #define AUDIO_MIXER_MAX_VOICES 8 #define AUDIO_MIXER_TEMP_OGG_BUFFER 8192 -#define AUDIO_MIXER_TYPE_NONE 0 -#define AUDIO_MIXER_TYPE_WAV 1 -#define AUDIO_MIXER_TYPE_OGG 2 - -struct audio_mixer_sound_t +enum audio_mixer_type { - unsigned type; + AUDIO_MIXER_TYPE_NONE = 0, + AUDIO_MIXER_TYPE_WAV, + AUDIO_MIXER_TYPE_OGG +}; + +struct audio_mixer_sound +{ + enum audio_mixer_type type; union { @@ -74,12 +77,12 @@ struct audio_mixer_sound_t } types; }; -struct audio_mixer_voice_t +struct audio_mixer_voice { - unsigned type; bool repeat; + unsigned type; float volume; - audio_mixer_sound_t* sound; + audio_mixer_sound_t *sound; audio_mixer_stop_cb_t stop_cb; union @@ -96,44 +99,39 @@ struct audio_mixer_voice_t /* ogg */ unsigned position; unsigned samples; - stb_vorbis* stream; - float* buffer; unsigned buf_samples; - void* resampler_data; + float* buffer; float ratio; - const retro_resampler_t* resampler; + stb_vorbis *stream; + void *resampler_data; + const retro_resampler_t *resampler; } ogg; #endif } types; }; -static audio_mixer_voice_t s_voices[AUDIO_MIXER_MAX_VOICES]; -static unsigned s_rate = 0; +static struct audio_mixer_voice s_voices[AUDIO_MIXER_MAX_VOICES]; +static unsigned s_rate = 0; -static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out) +static bool wav2float(const rwav_t* wav, float** pcm, size_t samples_out) { size_t i; - float sample = 0.0f; - const uint8_t* u8 = NULL; - const int16_t* s16 = NULL; - float* f = NULL; - /* Allocate on a 16-byte boundary, and pad to a multiple of 16 bytes */ - *samples_out = wav->numsamples * 2; - f = (float*)memalign_alloc(16, - ((*samples_out + 15) & ~15) * sizeof(float)); + float *f = (float*)memalign_alloc(16, + ((samples_out + 15) & ~15) * sizeof(float)); if (!f) return false; *pcm = f; - if (wav->numchannels == 1) + if (wav->bitspersample == 8) { - if (wav->bitspersample == 8) + float sample = 0.0f; + const uint8_t *u8 = (const uint8_t*)wav->samples; + + if (wav->numchannels == 1) { - u8 = (const uint8_t*)wav->samples; - for (i = wav->numsamples; i != 0; i--) { sample = (float)*u8++ / 255.0f; @@ -142,10 +140,29 @@ static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out) *f++ = sample; } } - else + else if (wav->numchannels == 2) + { + for (i = wav->numsamples; i != 0; i--) + { + sample = (float)*u8++ / 255.0f; + sample = sample * 2.0f - 1.0f; + *f++ = sample; + sample = (float)*u8++ / 255.0f; + sample = sample * 2.0f - 1.0f; + *f++ = sample; + } + } + } + else + { + /* TODO/FIXME note to leiradel - can we use audio/conversion/s16_to_float + * functions here? */ + + float sample = 0.0f; + const int16_t *s16 = (const int16_t*)wav->samples; + + if (wav->numchannels == 1) { - s16 = (const int16_t*)wav->samples; - for (i = wav->numsamples; i != 0; i--) { sample = (float)((int)*s16++ + 32768) / 65535.0f; @@ -154,27 +171,8 @@ static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out) *f++ = sample; } } - } - else if (wav->numchannels == 2) - { - if (wav->bitspersample == 8) + else if (wav->numchannels == 2) { - u8 = (const uint8_t*)wav->samples; - - for (i = wav->numsamples; i != 0; i--) - { - sample = (float)*u8++ / 255.0f; - sample = sample * 2.0f - 1.0f; - *f++ = sample; - sample = (float)*u8++ / 255.0f; - sample = sample * 2.0f - 1.0f; - *f++ = sample; - } - } - else - { - s16 = (const int16_t*)wav->samples; - for (i = wav->numsamples; i != 0; i--) { sample = (float)((int)*s16++ + 32768) / 65535.0f; @@ -186,7 +184,7 @@ static bool wav2float(const rwav_t* wav, float** pcm, size_t* samples_out) } } } - + return true; } @@ -254,27 +252,29 @@ audio_mixer_sound_t* audio_mixer_load_wav(const char* path) ssize_t size = 0; /* WAV samples converted to float */ float* pcm = NULL; - float* resampled = NULL; size_t samples = 0; /* Result */ audio_mixer_sound_t* sound = NULL; + enum rwav_state rwav_ret = RWAV_ITERATE_ERROR; if (filestream_read_file(path, &buffer, &size) == 0) return NULL; - if (rwav_load(&wav, buffer, size) != RWAV_ITERATE_DONE) - { - free(buffer); - return NULL; - } - + rwav_ret = rwav_load(&wav, buffer, size); + free(buffer); + + if (rwav_ret != RWAV_ITERATE_DONE) + return NULL; - if (!wav2float(&wav, &pcm, &samples)) + samples = wav.numsamples * 2; + if (!wav2float(&wav, &pcm, samples)) return NULL; if (wav.samplerate != s_rate) { + float* resampled = NULL; + if (!one_shot_resample(pcm, samples, wav.samplerate, &resampled, &samples)) return NULL; @@ -296,6 +296,7 @@ audio_mixer_sound_t* audio_mixer_load_wav(const char* path) sound->types.wav.pcm = pcm; rwav_free(&wav); + return sound; } @@ -329,6 +330,9 @@ audio_mixer_sound_t* audio_mixer_load_ogg(const char* path) void audio_mixer_destroy(audio_mixer_sound_t* sound) { + if (!sound) + return; + switch (sound->type) { case AUDIO_MIXER_TYPE_WAV: @@ -339,6 +343,8 @@ void audio_mixer_destroy(audio_mixer_sound_t* sound) memalign_free((void*)sound->types.ogg.data); #endif break; + case AUDIO_MIXER_TYPE_NONE: + break; } free(sound); @@ -348,11 +354,6 @@ static bool audio_mixer_play_wav(audio_mixer_sound_t* sound, audio_mixer_voice_t* voice, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb) { - voice->type = AUDIO_MIXER_TYPE_WAV; - voice->repeat = repeat; - voice->volume = volume; - voice->sound = sound; - voice->stop_cb = stop_cb; voice->types.wav.position = 0; return true; @@ -366,58 +367,59 @@ static bool audio_mixer_play_ogg( audio_mixer_stop_cb_t stop_cb) { stb_vorbis_info info; - int res = 0; - float ratio = 0.0f; - unsigned samples = 0; - - voice->repeat = repeat; - voice->volume = volume; - voice->sound = sound; - voice->stop_cb = stop_cb; - - voice->types.ogg.stream = stb_vorbis_open_memory( + int res = 0; + float ratio = 0.0f; + unsigned samples = 0; + void *ogg_buffer = NULL; + void *resampler_data = NULL; + const retro_resampler_t* resamp = NULL; + stb_vorbis *stb_vorbis = stb_vorbis_open_memory( (const unsigned char*)sound->types.ogg.data, sound->types.ogg.size, &res, NULL); - if (!voice->types.ogg.stream) + if (!stb_vorbis) return false; - info = stb_vorbis_get_info(voice->types.ogg.stream); + info = stb_vorbis_get_info(stb_vorbis); /* Only stereo supported for now */ if (info.channels != 2) - { - stb_vorbis_close(voice->types.ogg.stream); - return false; - } + goto error; if (info.sample_rate != s_rate) { - voice->types.ogg.ratio = ratio = (double)s_rate / (double)info.sample_rate; + ratio = (double)s_rate / (double)info.sample_rate; - if (!retro_resampler_realloc(&voice->types.ogg.resampler_data, - &voice->types.ogg.resampler, NULL, ratio)) - { - stb_vorbis_close(voice->types.ogg.stream); - return false; - } + if (!retro_resampler_realloc(&resampler_data, + &resamp, NULL, ratio)) + goto error; } - samples = - voice->types.ogg.buf_samples = (unsigned)(AUDIO_MIXER_TEMP_OGG_BUFFER * ratio); - voice->types.ogg.buffer = (float*)memalign_alloc(16, + samples = (unsigned)(AUDIO_MIXER_TEMP_OGG_BUFFER * ratio); + ogg_buffer = (float*)memalign_alloc(16, ((samples + 15) & ~15) * sizeof(float)); - if (!voice->types.ogg.buffer) + if (!ogg_buffer) { - voice->types.ogg.resampler->free(voice->types.ogg.resampler_data); - stb_vorbis_close(voice->types.ogg.stream); - return false; + resamp->free(resampler_data); + goto error; } - voice->type = AUDIO_MIXER_TYPE_OGG; - voice->types.ogg.position = voice->types.ogg.samples = 0; + voice->types.ogg.resampler = resamp; + voice->types.ogg.resampler_data = resampler_data; + voice->types.ogg.buffer = ogg_buffer; + voice->types.ogg.buf_samples = samples; + voice->types.ogg.ratio = ratio; + voice->types.ogg.stream = stb_vorbis; + voice->types.ogg.position = 0; + voice->types.ogg.samples = 0; + voice->type = AUDIO_MIXER_TYPE_OGG; + return true; + +error: + stb_vorbis_close(stb_vorbis); + return false; } #endif @@ -427,30 +429,42 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, unsigned i; bool res = false; audio_mixer_voice_t* voice = s_voices; - + + if (!sound) + return NULL; + for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++) { - if (voice->type == AUDIO_MIXER_TYPE_NONE) + if (voice->type != AUDIO_MIXER_TYPE_NONE) + continue; + + switch (sound->type) { - switch (sound->type) - { - case AUDIO_MIXER_TYPE_WAV: - res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb); - break; - case AUDIO_MIXER_TYPE_OGG: + case AUDIO_MIXER_TYPE_WAV: + res = audio_mixer_play_wav(sound, voice, repeat, volume, stop_cb); + break; + case AUDIO_MIXER_TYPE_OGG: #ifdef HAVE_STB_VORBIS - res = audio_mixer_play_ogg(sound, voice, repeat, volume, stop_cb); + res = audio_mixer_play_ogg(sound, voice, repeat, volume, stop_cb); #endif - break; - } - - break; + break; + case AUDIO_MIXER_TYPE_NONE: + break; } + + break; } - - if (res) - return voice; - return NULL; + + if (!res) + return NULL; + + voice->type = sound->type; + voice->repeat = repeat; + voice->volume = volume; + voice->sound = sound; + voice->stop_cb = stop_cb; + + return voice; } void audio_mixer_stop(audio_mixer_voice_t* voice) @@ -459,15 +473,17 @@ void audio_mixer_stop(audio_mixer_voice_t* voice) voice->stop_cb(voice, AUDIO_MIXER_SOUND_STOPPED); } -static void mix_wav(float* buffer, size_t num_frames, audio_mixer_voice_t* voice) +static void audio_mixer_mix_wav(float* buffer, size_t num_frames, + audio_mixer_voice_t* voice, + float volume) { int i; unsigned buf_free = (unsigned)(num_frames * 2); const audio_mixer_sound_t* sound = voice->sound; unsigned pcm_available = sound->types.wav.frames * 2 - voice->types.wav.position; - const float* pcm = sound->types.wav.pcm + voice->types.wav.position; - float volume = voice->volume; + const float* pcm = sound->types.wav.pcm + + voice->types.wav.position; again: if (pcm_available < buf_free) @@ -502,18 +518,16 @@ again: } #ifdef HAVE_STB_VORBIS -static void mix_ogg(float* buffer, size_t num_frames, audio_mixer_voice_t* voice) +static void audio_mixer_mix_ogg(float* buffer, size_t num_frames, + audio_mixer_voice_t* voice, + float volume) { int i; - float temp_buffer[AUDIO_MIXER_TEMP_OGG_BUFFER]; struct resampler_data info; + float temp_buffer[AUDIO_MIXER_TEMP_OGG_BUFFER]; unsigned buf_free = num_frames * 2; unsigned temp_samples = 0; - float volume = voice->volume; float* pcm = NULL; -#if 0 - const audio_mixer_sound_t* sound = voice->sound; -#endif if (voice->types.ogg.position == voice->types.ogg.samples) { @@ -584,12 +598,21 @@ void audio_mixer_mix(float* buffer, size_t num_frames) for (i = 0; i < AUDIO_MIXER_MAX_VOICES; i++, voice++) { - if (voice->type == AUDIO_MIXER_TYPE_WAV) - mix_wav(buffer, num_frames, voice); + float volume = voice->volume; + + switch (voice->type) + { + case AUDIO_MIXER_TYPE_WAV: + audio_mixer_mix_wav(buffer, num_frames, voice, volume); + break; + case AUDIO_MIXER_TYPE_OGG: #ifdef HAVE_STB_VORBIS - else if (voice->type == AUDIO_MIXER_TYPE_OGG) - mix_ogg(buffer, num_frames, voice); + audio_mixer_mix_ogg(buffer, num_frames, voice, volume); #endif + break; + case AUDIO_MIXER_TYPE_NONE: + break; + } } for (j = 0, sample = buffer; j < num_frames; j++, sample++) diff --git a/libretro-common/file/archive_file.c b/libretro-common/file/archive_file.c index ce6722fc9e..1e300238e9 100644 --- a/libretro-common/file/archive_file.c +++ b/libretro-common/file/archive_file.c @@ -522,31 +522,31 @@ bool file_archive_extract_file( bool ret = true; struct string_list *list = string_split(valid_exts, "|"); + userdata.archive_path[0] = '\0'; + userdata.first_extracted_file_path = NULL; + userdata.extracted_file_path = NULL; + userdata.extraction_directory = extraction_directory; + userdata.archive_path_size = archive_path_size; + userdata.ext = list; + userdata.list = NULL; + userdata.found_file = false; + userdata.list_only = false; + userdata.context = NULL; + userdata.archive_name[0] = '\0'; + userdata.crc = 0; + userdata.dec = NULL; + + userdata.decomp_state.opt_file = NULL; + userdata.decomp_state.needle = NULL; + userdata.decomp_state.size = 0; + userdata.decomp_state.found = NULL; + if (!list) { ret = false; goto end; } - userdata.archive_path[0] = '\0'; - userdata.first_extracted_file_path = NULL; - userdata.extracted_file_path = NULL; - userdata.extraction_directory = extraction_directory; - userdata.archive_path_size = archive_path_size; - userdata.ext = list; - userdata.list = NULL; - userdata.found_file = false; - userdata.list_only = false; - userdata.context = NULL; - userdata.archive_name[0] = '\0'; - userdata.crc = 0; - userdata.dec = NULL; - - userdata.decomp_state.opt_file = NULL; - userdata.decomp_state.needle = NULL; - userdata.decomp_state.size = 0; - userdata.decomp_state.found = NULL; - if (!file_archive_walk(archive_path, valid_exts, file_archive_extract_cb, &userdata)) { diff --git a/libretro-common/formats/wav/rwav.c b/libretro-common/formats/wav/rwav.c index da0bc946db..4929495db0 100644 --- a/libretro-common/formats/wav/rwav.c +++ b/libretro-common/formats/wav/rwav.c @@ -37,128 +37,143 @@ enum ITER_COPY_SAMPLES_16 }; +struct rwav_iterator +{ + rwav_t *out; + const uint8_t *data; + size_t size; + size_t i, j; + int step; +}; + void rwav_init(rwav_iterator_t* iter, rwav_t* out, const void* buf, size_t size) { - iter->out = out; - iter->data = (const uint8_t*)buf; - iter->size = size; - iter->step = ITER_BEGIN; + iter->out = out; + iter->data = (const uint8_t*)buf; + iter->size = size; + iter->step = ITER_BEGIN; out->samples = NULL; } int rwav_iterate(rwav_iterator_t *iter) { - rwav_t *rwav = iter->out; - const uint8_t *data = iter->data; - uint16_t *u16; - void *samples; size_t s; + uint16_t *u16 = NULL; + void *samples = NULL; + rwav_t *rwav = iter->out; + const uint8_t *data = iter->data; switch (iter->step) { - case ITER_BEGIN: - if (iter->size < 44) - return RWAV_ITERATE_ERROR; /* buffer is smaller than an empty wave file */ - - if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F') - return RWAV_ITERATE_ERROR; - - if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E') - return RWAV_ITERATE_ERROR; + case ITER_BEGIN: + if (iter->size < 44) + return RWAV_ITERATE_ERROR; /* buffer is smaller than an empty wave file */ - if (data[12] != 'f' || data[13] != 'm' || data[14] != 't' || data[15] != ' ') - return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */ - - if (data[16] != 16 || data[17] != 0 || data[18] != 0 || data[19] != 0) - return RWAV_ITERATE_ERROR; - - if (data[20] != 1 || data[21] != 0) - return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */ + if (data[0] != 'R' || data[1] != 'I' || data[2] != 'F' || data[3] != 'F') + return RWAV_ITERATE_ERROR; - if (data[36] != 'd' || data[37] != 'a' || data[38] != 't' || data[39] != 'a') - return RWAV_ITERATE_ERROR; - - rwav->bitspersample = data[34] | data[35] << 8; - - if (rwav->bitspersample != 8 && rwav->bitspersample != 16) - return RWAV_ITERATE_ERROR; /* we only support 8 and 16 bps */ - - rwav->subchunk2size = data[40] | data[41] << 8 | data[42] << 16 | data[43] << 24; - - if (rwav->subchunk2size > iter->size - 44) - return RWAV_ITERATE_ERROR; /* too few bytes in buffer */ + if (data[8] != 'W' || data[9] != 'A' || data[10] != 'V' || data[11] != 'E') + return RWAV_ITERATE_ERROR; - samples = malloc(rwav->subchunk2size); - - if (samples == NULL) - return RWAV_ITERATE_ERROR; - - rwav->numchannels = data[22] | data[23] << 8; - rwav->numsamples = rwav->subchunk2size * 8 / rwav->bitspersample / rwav->numchannels; - rwav->samplerate = data[24] | data[25] << 8 | data[26] << 16 | data[27] << 24; - rwav->samples = samples; - - iter->step = ITER_COPY_SAMPLES; - return RWAV_ITERATE_MORE; - - case ITER_COPY_SAMPLES: - iter->i = 0; - - if (rwav->bitspersample == 8) - { - iter->step = ITER_COPY_SAMPLES_8; - - case ITER_COPY_SAMPLES_8: - s = rwav->subchunk2size - iter->i; - - if (s > RWAV_ITERATE_BUF_SIZE) - s = RWAV_ITERATE_BUF_SIZE; - - memcpy((void*)((uint8_t*)rwav->samples + iter->i), (void *)(iter->data + 44 + iter->i), s); - iter->i += s; - - return iter->i < rwav->subchunk2size ? RWAV_ITERATE_MORE : RWAV_ITERATE_DONE; - } - else - { - iter->step = ITER_COPY_SAMPLES_16; - iter->j = 0; - - case ITER_COPY_SAMPLES_16: - s = rwav->subchunk2size - iter->i; - - if (s > RWAV_ITERATE_BUF_SIZE) - s = RWAV_ITERATE_BUF_SIZE; - - u16 = (uint16_t *)rwav->samples; - - while (s != 0) + if (data[12] != 'f' || data[13] != 'm' || data[14] != 't' || data[15] != ' ') + return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */ + + if (data[16] != 16 || data[17] != 0 || data[18] != 0 || data[19] != 0) + return RWAV_ITERATE_ERROR; + + if (data[20] != 1 || data[21] != 0) + return RWAV_ITERATE_ERROR; /* we don't support non-PCM or compressed data */ + + if (data[36] != 'd' || data[37] != 'a' || data[38] != 't' || data[39] != 'a') + return RWAV_ITERATE_ERROR; + + rwav->bitspersample = data[34] | data[35] << 8; + + if (rwav->bitspersample != 8 && rwav->bitspersample != 16) + return RWAV_ITERATE_ERROR; /* we only support 8 and 16 bps */ + + rwav->subchunk2size = data[40] | data[41] << 8 | data[42] << 16 | data[43] << 24; + + if (rwav->subchunk2size > iter->size - 44) + return RWAV_ITERATE_ERROR; /* too few bytes in buffer */ + + samples = malloc(rwav->subchunk2size); + + if (samples == NULL) + return RWAV_ITERATE_ERROR; + + rwav->numchannels = data[22] | data[23] << 8; + rwav->numsamples = rwav->subchunk2size * 8 / rwav->bitspersample / rwav->numchannels; + rwav->samplerate = data[24] | data[25] << 8 | data[26] << 16 | data[27] << 24; + rwav->samples = samples; + + iter->step = ITER_COPY_SAMPLES; + return RWAV_ITERATE_MORE; + + case ITER_COPY_SAMPLES: + iter->i = 0; + + if (rwav->bitspersample == 8) { - u16[iter->j++] = iter->data[44 + iter->i] | iter->data[45 + iter->i] << 8; - iter->i += 2; - s -= 2; + iter->step = ITER_COPY_SAMPLES_8; + + /* TODO/FIXME - what is going on here? */ + case ITER_COPY_SAMPLES_8: + s = rwav->subchunk2size - iter->i; + + if (s > RWAV_ITERATE_BUF_SIZE) + s = RWAV_ITERATE_BUF_SIZE; + + memcpy((void*)((uint8_t*)rwav->samples + iter->i), (void *)(iter->data + 44 + iter->i), s); + iter->i += s; + } + else + { + iter->step = ITER_COPY_SAMPLES_16; + iter->j = 0; + + /* TODO/FIXME - what is going on here? */ + case ITER_COPY_SAMPLES_16: + s = rwav->subchunk2size - iter->i; + + if (s > RWAV_ITERATE_BUF_SIZE) + s = RWAV_ITERATE_BUF_SIZE; + + u16 = (uint16_t *)rwav->samples; + + while (s != 0) + { + u16[iter->j++] = iter->data[44 + iter->i] | iter->data[45 + iter->i] << 8; + iter->i += 2; + s -= 2; + } } - return iter->i < rwav->subchunk2size ? RWAV_ITERATE_MORE : RWAV_ITERATE_DONE; - } } return RWAV_ITERATE_ERROR; } -int rwav_load(rwav_t* out, const void* buf, size_t size) +enum rwav_state rwav_load(rwav_t* out, const void* buf, size_t size) { - int res; - rwav_iterator_t iter = {0}; - + enum rwav_state res; + rwav_iterator_t iter; + + iter.out = NULL; + iter.data = NULL; + iter.size = 0; + iter.i = 0; + iter.j = 0; + iter.step = 0; + rwav_init(&iter, out, buf, size); do { res = rwav_iterate(&iter); }while (res == RWAV_ITERATE_MORE); - + return res; } diff --git a/libretro-common/include/audio/audio_mixer.h b/libretro-common/include/audio/audio_mixer.h index b2b013166f..7e00581879 100644 --- a/libretro-common/include/audio/audio_mixer.h +++ b/libretro-common/include/audio/audio_mixer.h @@ -31,8 +31,8 @@ RETRO_BEGIN_DECLS -typedef struct audio_mixer_sound_t audio_mixer_sound_t; -typedef struct audio_mixer_voice_t audio_mixer_voice_t; +typedef struct audio_mixer_sound audio_mixer_sound_t; +typedef struct audio_mixer_voice audio_mixer_voice_t; typedef void (*audio_mixer_stop_cb_t)(audio_mixer_voice_t* voice, unsigned reason); @@ -42,6 +42,7 @@ typedef void (*audio_mixer_stop_cb_t)(audio_mixer_voice_t* voice, unsigned reaso #define AUDIO_MIXER_SOUND_REPEATED 2 void audio_mixer_init(unsigned rate); + void audio_mixer_done(void); audio_mixer_sound_t* audio_mixer_load_wav(const char* path); @@ -49,8 +50,10 @@ audio_mixer_sound_t* audio_mixer_load_ogg(const char* path); void audio_mixer_destroy(audio_mixer_sound_t* sound); -audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb); -void audio_mixer_stop(audio_mixer_voice_t* voice); +audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, + bool repeat, float volume, audio_mixer_stop_cb_t stop_cb); + +void audio_mixer_stop(audio_mixer_voice_t* voice); void audio_mixer_mix(float* buffer, size_t num_frames); diff --git a/libretro-common/include/formats/rwav.h b/libretro-common/include/formats/rwav.h index 2000059b5d..0c7b705d23 100644 --- a/libretro-common/include/formats/rwav.h +++ b/libretro-common/include/formats/rwav.h @@ -47,28 +47,17 @@ typedef struct /* PCM data */ const void* samples; -} -rwav_t; +} rwav_t; -enum +enum rwav_state { - RWAV_ITERATE_ERROR = -1, - RWAV_ITERATE_MORE = 0, - RWAV_ITERATE_DONE = 1, - + RWAV_ITERATE_ERROR = -1, + RWAV_ITERATE_MORE = 0, + RWAV_ITERATE_DONE = 1, RWAV_ITERATE_BUF_SIZE = 4096 }; -typedef struct -{ - /* internal data, don't touch */ - rwav_t *out; - const uint8_t *data; - size_t size; - size_t i, j; - int step; -} -rwav_iterator_t; +typedef struct rwav_iterator rwav_iterator_t; /** * Initializes the iterator to fill the out structure with data parsed from buf. @@ -86,7 +75,7 @@ int rwav_iterate(rwav_iterator_t *iter); /** * Loads the entire data in one go. */ -int rwav_load(rwav_t* out, const void* buf, size_t size); +enum rwav_state rwav_load(rwav_t* out, const void* buf, size_t size); /** * Frees parsed wave data. diff --git a/libretro-common/streams/file_stream.c b/libretro-common/streams/file_stream.c index f602ba46cf..afd836c835 100644 --- a/libretro-common/streams/file_stream.c +++ b/libretro-common/streams/file_stream.c @@ -225,7 +225,7 @@ RFILE *filestream_open(const char *path, unsigned mode, ssize_t len) stream->fd = sceIoOpen(path, flags, mode_int); #else #if defined(HAVE_BUFFERED_IO) - if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0) + if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 && mode_str) { stream->fp = fopen(path, mode_str); if (!stream->fp) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index c8f76e1a59..79b841c595 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -1478,16 +1478,16 @@ void general_read_handler(void *data) switch (setting->enum_idx) { case MENU_ENUM_LABEL_AUDIO_RATE_CONTROL_DELTA: - *setting->value.target.fraction = settings->floats.audio_rate_control_delta; + *setting->value.target.fraction = *(audio_get_float_ptr(AUDIO_ACTION_RATE_CONTROL_DELTA)); if (*setting->value.target.fraction < 0.0005) { configuration_set_bool(settings, settings->bools.audio_rate_control, false); - settings->floats.audio_rate_control_delta = 0.0; + audio_set_float(AUDIO_ACTION_RATE_CONTROL_DELTA, 0.0f); } else { configuration_set_bool(settings, settings->bools.audio_rate_control, true); - settings->floats.audio_rate_control_delta = *setting->value.target.fraction; + audio_set_float(AUDIO_ACTION_RATE_CONTROL_DELTA, *setting->value.target.fraction); } break; case MENU_ENUM_LABEL_AUDIO_MAX_TIMING_SKEW: @@ -1600,12 +1600,12 @@ void general_write_handler(void *data) if (*setting->value.target.fraction < 0.0005) { configuration_set_bool(settings, settings->bools.audio_rate_control, false); - settings->floats.audio_rate_control_delta = 0.0; + audio_set_float(AUDIO_ACTION_RATE_CONTROL_DELTA, 0.0f); } else { configuration_set_bool(settings, settings->bools.audio_rate_control, true); - settings->floats.audio_rate_control_delta = *setting->value.target.fraction; + audio_set_float(AUDIO_ACTION_RATE_CONTROL_DELTA, *setting->value.target.fraction); } break; case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE_AUTO: @@ -3761,7 +3761,7 @@ static bool setting_append_list( CONFIG_BOOL( list, list_info, - &settings->bools.audio_mute_enable, + audio_get_bool_ptr(AUDIO_ACTION_MUTE_ENABLE), MENU_ENUM_LABEL_AUDIO_MUTE, MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, false, @@ -3853,7 +3853,7 @@ static bool setting_append_list( CONFIG_FLOAT( list, list_info, - &settings->floats.audio_rate_control_delta, + audio_get_float_ptr(AUDIO_ACTION_RATE_CONTROL_DELTA), MENU_ENUM_LABEL_AUDIO_RATE_CONTROL_DELTA, MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, rate_control_delta,