mirror of
https://github.com/libretro/RetroArch
synced 2025-03-28 19:20:35 +00:00
Merge remote-tracking branch 'refs/remotes/libretro/master' into wiiu_controller_patcher
This commit is contained in:
commit
58543a43ff
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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++)
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user