mirror of
https://github.com/libretro/RetroArch
synced 2025-02-09 09:39:56 +00:00
Rewind audio! :D
This commit is contained in:
parent
9c79bf0ba2
commit
b2dd12d186
@ -61,7 +61,7 @@ hermite_resampler_t *hermite_new(unsigned channels)
|
||||
|
||||
void hermite_process(hermite_resampler_t *re, struct hermite_data *data)
|
||||
{
|
||||
double r_step = 1.0 / data->src_ratio;
|
||||
double r_step = 1.0 / data->ratio;
|
||||
size_t processed_out = 0;
|
||||
size_t processed_in = 0;
|
||||
|
||||
|
@ -39,8 +39,7 @@ struct hermite_data
|
||||
size_t input_frames_used;
|
||||
size_t output_frames_gen;
|
||||
|
||||
bool end_of_input; // Just used to clone the SRC API.
|
||||
double src_ratio;
|
||||
double ratio;
|
||||
};
|
||||
|
||||
void hermite_process(hermite_resampler_t *re, struct hermite_data *data);
|
||||
|
9
driver.c
9
driver.c
@ -258,12 +258,18 @@ void init_audio(void)
|
||||
size_t max_bufsamples = g_extern.audio_data.block_chunk_size > g_extern.audio_data.nonblock_chunk_size ?
|
||||
g_extern.audio_data.block_chunk_size : g_extern.audio_data.nonblock_chunk_size;
|
||||
|
||||
assert(g_settings.audio.out_rate < g_settings.audio.in_rate * AUDIO_MAX_RATIO);
|
||||
max_bufsamples *= 2; // Accomodate rewind since at some point we might have two full buffers.
|
||||
|
||||
assert((g_extern.audio_data.data = malloc(max_bufsamples * sizeof(float))));
|
||||
g_extern.audio_data.data_ptr = 0;
|
||||
assert(g_settings.audio.out_rate < g_settings.audio.in_rate * AUDIO_MAX_RATIO);
|
||||
assert((g_extern.audio_data.outsamples = malloc(max_bufsamples * sizeof(float) * AUDIO_MAX_RATIO)));
|
||||
assert((g_extern.audio_data.conv_outsamples = malloc(max_bufsamples * sizeof(int16_t) * AUDIO_MAX_RATIO)));
|
||||
|
||||
// Needs to be able to hold full content of a full max_bufsamples in addition to its own.
|
||||
assert((g_extern.audio_data.rewind_buf = malloc(max_bufsamples * sizeof(int16_t))));
|
||||
g_extern.audio_data.rewind_size = max_bufsamples;
|
||||
|
||||
init_dsp_plugin();
|
||||
}
|
||||
|
||||
@ -284,6 +290,7 @@ void uninit_audio(void)
|
||||
free(g_extern.audio_data.data); g_extern.audio_data.data = NULL;
|
||||
free(g_extern.audio_data.outsamples); g_extern.audio_data.outsamples = NULL;
|
||||
free(g_extern.audio_data.conv_outsamples); g_extern.audio_data.conv_outsamples = NULL;
|
||||
free(g_extern.audio_data.rewind_buf); g_extern.audio_data.rewind_buf = NULL;
|
||||
|
||||
deinit_dsp_plugin();
|
||||
}
|
||||
|
@ -218,6 +218,10 @@ struct global
|
||||
float *outsamples;
|
||||
int16_t *conv_outsamples;
|
||||
|
||||
int16_t *rewind_buf;
|
||||
size_t rewind_ptr;
|
||||
size_t rewind_size;
|
||||
|
||||
dylib_t dsp_lib;
|
||||
const ssnes_dsp_plugin_t *dsp_plugin;
|
||||
void *dsp_handle;
|
||||
|
59
ssnes.c
59
ssnes.c
@ -187,11 +187,8 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
|
||||
|
||||
static bool audio_flush(const int16_t *data, unsigned samples)
|
||||
{
|
||||
for (unsigned i = 0; i < samples; i += 2)
|
||||
{
|
||||
g_extern.audio_data.data[i + 0] = (float)data[i + 0] / 0x8000;
|
||||
g_extern.audio_data.data[i + 1] = (float)data[i + 1] / 0x8000;
|
||||
}
|
||||
for (unsigned i = 0; i < samples; i++)
|
||||
g_extern.audio_data.data[i] = (float)data[i] / 0x8000;
|
||||
|
||||
const float *output_data = NULL;
|
||||
unsigned output_frames = 0;
|
||||
@ -224,10 +221,12 @@ static bool audio_flush(const int16_t *data, unsigned samples)
|
||||
.data_out = g_extern.audio_data.outsamples,
|
||||
.input_frames = dsp_output.samples ? dsp_output.frames : (samples / 2),
|
||||
.output_frames = g_extern.audio_data.chunk_size * 8,
|
||||
.end_of_input = 0,
|
||||
.src_ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate,
|
||||
.ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate,
|
||||
};
|
||||
|
||||
if (g_extern.frame_is_reverse)
|
||||
src_data.output_frames = (samples) * src_data.ratio;
|
||||
|
||||
if (dsp_output.should_resample)
|
||||
{
|
||||
hermite_process(g_extern.audio_data.source, &src_data);
|
||||
@ -267,6 +266,15 @@ static bool audio_flush(const int16_t *data, unsigned samples)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void audio_sample_rewind(uint16_t left, uint16_t right)
|
||||
{
|
||||
if (!g_extern.audio_active)
|
||||
return;
|
||||
|
||||
g_extern.audio_data.rewind_buf[--g_extern.audio_data.rewind_ptr] = right;
|
||||
g_extern.audio_data.rewind_buf[--g_extern.audio_data.rewind_ptr] = left;
|
||||
}
|
||||
|
||||
static void audio_sample(uint16_t left, uint16_t right)
|
||||
{
|
||||
if (!g_extern.audio_active)
|
||||
@ -278,7 +286,9 @@ static void audio_sample(uint16_t left, uint16_t right)
|
||||
if (g_extern.audio_data.data_ptr < g_extern.audio_data.chunk_size)
|
||||
return;
|
||||
|
||||
g_extern.audio_active = audio_flush(g_extern.audio_data.conv_outsamples, g_extern.audio_data.data_ptr);
|
||||
g_extern.audio_active = audio_flush(g_extern.audio_data.conv_outsamples,
|
||||
g_extern.audio_data.data_ptr);
|
||||
|
||||
g_extern.audio_data.data_ptr = 0;
|
||||
}
|
||||
|
||||
@ -1331,9 +1341,36 @@ static void check_input_rate(void)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void flush_rewind_audio(void)
|
||||
{
|
||||
if (g_extern.frame_is_reverse) // We just rewound. Flush rewind audio buffer.
|
||||
{
|
||||
g_extern.audio_active = audio_flush(g_extern.audio_data.rewind_buf + g_extern.audio_data.rewind_ptr,
|
||||
g_extern.audio_data.rewind_size - g_extern.audio_data.rewind_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setup_rewind_audio(void)
|
||||
{
|
||||
// Push audio ready to be played.
|
||||
g_extern.audio_data.rewind_ptr = g_extern.audio_data.rewind_size;
|
||||
for (unsigned i = 0; i < g_extern.audio_data.data_ptr; i += 2)
|
||||
{
|
||||
g_extern.audio_data.rewind_buf[--g_extern.audio_data.rewind_ptr] =
|
||||
g_extern.audio_data.conv_outsamples[i + 1];
|
||||
|
||||
g_extern.audio_data.rewind_buf[--g_extern.audio_data.rewind_ptr] =
|
||||
g_extern.audio_data.conv_outsamples[i + 0];
|
||||
}
|
||||
|
||||
g_extern.audio_data.data_ptr = 0;
|
||||
}
|
||||
|
||||
static void check_rewind(void)
|
||||
{
|
||||
flush_rewind_audio();
|
||||
g_extern.frame_is_reverse = false;
|
||||
|
||||
static bool first = true;
|
||||
if (first)
|
||||
{
|
||||
@ -1351,13 +1388,13 @@ static void check_rewind(void)
|
||||
if (state_manager_pop(g_extern.state_manager, &buf))
|
||||
{
|
||||
g_extern.frame_is_reverse = true;
|
||||
setup_rewind_audio();
|
||||
|
||||
msg_queue_push(g_extern.msg_queue, "Rewinding!", 0, 30);
|
||||
psnes_unserialize(buf, psnes_serialize_size());
|
||||
|
||||
if (g_extern.bsv_movie)
|
||||
{
|
||||
bsv_movie_frame_rewind(g_extern.bsv_movie);
|
||||
}
|
||||
}
|
||||
else
|
||||
msg_queue_push(g_extern.msg_queue, "Reached end of rewind buffer!", 0, 30);
|
||||
@ -1372,6 +1409,8 @@ static void check_rewind(void)
|
||||
state_manager_push(g_extern.state_manager, g_extern.state_buf);
|
||||
}
|
||||
}
|
||||
|
||||
psnes_set_audio_sample(g_extern.frame_is_reverse ? audio_sample_rewind : audio_sample);
|
||||
}
|
||||
|
||||
static void check_movie_record(void)
|
||||
|
Loading…
x
Reference in New Issue
Block a user