mirror of
https://github.com/libretro/RetroArch
synced 2025-03-11 19:13:36 +00:00
Clean up audio a bit. Less use of nasty statics and VLAs.
This commit is contained in:
parent
becfeb57eb
commit
6b21e6b8a3
32
audio/jack.c
32
audio/jack.c
@ -29,8 +29,7 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define FRAMES(x) (x / (sizeof(int16_t) * 2))
|
||||
#define SAMPLES(x) (x / sizeof(int16_t))
|
||||
#define FRAMES(x) (x / (sizeof(float) * 2))
|
||||
|
||||
typedef struct jack
|
||||
{
|
||||
@ -61,13 +60,6 @@ static int process_cb(jack_nframes_t nframes, void *data)
|
||||
if (min_avail > nframes)
|
||||
min_avail = nframes;
|
||||
|
||||
//static int underrun = 0;
|
||||
//if (min_avail < nframes)
|
||||
//{
|
||||
// SSNES_LOG("JACK: Underrun count: %d\n", underrun++);
|
||||
// fprintf(stderr, "required %d frames, got %d.\n", (int)nframes, (int)min_avail);
|
||||
//}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
jack_default_audio_sample_t *out = jack_port_get_buffer(jd->ports[i], nframes);
|
||||
@ -90,12 +82,6 @@ static void shutdown_cb(void *data)
|
||||
pthread_cond_signal(&jd->cond);
|
||||
}
|
||||
|
||||
static inline void s16_to_float(jack_default_audio_sample_t * restrict out, const int16_t * restrict in, size_t samples)
|
||||
{
|
||||
for (int i = 0; i < samples; i++)
|
||||
out[i] = (float)in[i] / 0x8000;
|
||||
}
|
||||
|
||||
static void parse_ports(const char **dest_ports, const char **jports)
|
||||
{
|
||||
int parsed = 0;
|
||||
@ -142,7 +128,7 @@ static void* __jack_init(const char* device, int rate, int latency)
|
||||
bufsize = (latency * g_settings.audio.out_rate / 1000) > jack_bufsize * 2 ? (latency * g_settings.audio.out_rate / 1000) : jack_bufsize * 2;
|
||||
bufsize *= sizeof(jack_default_audio_sample_t);
|
||||
|
||||
//fprintf(stderr, "jack buffer size: %d\n", (int)bufsize);
|
||||
SSNES_LOG("Jack buffer size: %d bytes: (~%.2f msec latency)\n", (int)bufsize, (float)bufsize * 1000 / (g_settings.audio.out_rate * sizeof(jack_default_audio_sample_t)));
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
jd->buffer[i] = jack_ringbuffer_create(bufsize);
|
||||
@ -181,7 +167,6 @@ static void* __jack_init(const char* device, int rate, int latency)
|
||||
pthread_cond_init(&jd->cond, NULL);
|
||||
pthread_mutex_init(&jd->cond_lock, NULL);
|
||||
|
||||
|
||||
jack_free(jports);
|
||||
return jd;
|
||||
|
||||
@ -191,17 +176,13 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t write_buffer(jack_t *jd, const void *buf, size_t size)
|
||||
static size_t write_buffer(jack_t *jd, const float *buf, size_t size)
|
||||
{
|
||||
//fprintf(stderr, "write_buffer: size: %zu\n", size);
|
||||
// Convert our data to float, deinterleave and write.
|
||||
jack_default_audio_sample_t out_buffer[size / sizeof(int16_t)];
|
||||
jack_default_audio_sample_t out_deinterleaved_buffer[2][FRAMES(size)];
|
||||
s16_to_float(out_buffer, buf, SAMPLES(size));
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
for (size_t j = 0; j < FRAMES(size); j++)
|
||||
out_deinterleaved_buffer[i][j] = out_buffer[j * 2 + i];
|
||||
out_deinterleaved_buffer[i][j] = buf[j * 2 + i];
|
||||
|
||||
for(;;)
|
||||
{
|
||||
@ -216,13 +197,11 @@ static size_t write_buffer(jack_t *jd, const void *buf, size_t size)
|
||||
if (jd->nonblock)
|
||||
{
|
||||
if (min_avail < FRAMES(size) * sizeof(jack_default_audio_sample_t))
|
||||
size = min_avail * 2 * sizeof(int16_t) / sizeof(jack_default_audio_sample_t);
|
||||
size = min_avail * 2;
|
||||
break;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//fprintf(stderr, "Write avail is: %d\n", (int)min_avail);
|
||||
if (min_avail >= FRAMES(size) * sizeof(jack_default_audio_sample_t))
|
||||
break;
|
||||
}
|
||||
@ -290,6 +269,7 @@ const audio_driver_t audio_jack = {
|
||||
.start = __jack_start,
|
||||
.set_nonblock_state = __jack_set_nonblock_state,
|
||||
.free = __jack_free,
|
||||
.float_samples = true,
|
||||
.ident = "jack"
|
||||
};
|
||||
|
||||
|
26
driver.c
26
driver.c
@ -21,6 +21,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "hqflt/filters.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
@ -128,6 +129,9 @@ void uninit_drivers(void)
|
||||
uninit_audio();
|
||||
}
|
||||
|
||||
#define AUDIO_CHUNK_SIZE_BLOCKING 64
|
||||
#define AUDIO_CHUNK_SIZE_NONBLOCKING 2048 // So we don't get complete line-noise when fast-forwarding audio.
|
||||
#define AUDIO_MAX_RATIO 16
|
||||
void init_audio(void)
|
||||
{
|
||||
if (!g_settings.audio.enable)
|
||||
@ -138,17 +142,35 @@ void init_audio(void)
|
||||
|
||||
find_audio_driver();
|
||||
|
||||
g_extern.audio_data.block_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING;
|
||||
g_extern.audio_data.nonblock_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
|
||||
|
||||
driver.audio_data = driver.audio->init(strlen(g_settings.audio.device) ? g_settings.audio.device : NULL, g_settings.audio.out_rate, g_settings.audio.latency);
|
||||
if ( driver.audio_data == NULL )
|
||||
g_extern.audio_active = false;
|
||||
|
||||
|
||||
if (!g_settings.audio.sync && g_extern.audio_active)
|
||||
{
|
||||
driver.audio->set_nonblock_state(driver.audio_data, true);
|
||||
g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size;
|
||||
}
|
||||
else
|
||||
g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size;
|
||||
|
||||
int err;
|
||||
g_extern.source = src_new(g_settings.audio.src_quality, 2, &err);
|
||||
if (!g_extern.source)
|
||||
g_extern.audio_active = false;
|
||||
|
||||
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);
|
||||
assert((g_extern.audio_data.data = malloc(max_bufsamples * sizeof(float))));
|
||||
g_extern.audio_data.data_ptr = 0;
|
||||
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)));
|
||||
}
|
||||
|
||||
void uninit_audio(void)
|
||||
@ -164,6 +186,10 @@ void uninit_audio(void)
|
||||
|
||||
if ( g_extern.source )
|
||||
src_delete(g_extern.source);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void init_video_input(void)
|
||||
|
1
driver.h
1
driver.h
@ -61,6 +61,7 @@ typedef struct audio_driver
|
||||
bool (*start)(void* data);
|
||||
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding.
|
||||
void (*free)(void* data);
|
||||
bool float_samples; // Defines if driver will take standard floating point samples, or int16_t samples.
|
||||
const char *ident;
|
||||
} audio_driver_t;
|
||||
|
||||
|
12
general.h
12
general.h
@ -117,6 +117,18 @@ struct global
|
||||
char savefile_name_bsrm[512];
|
||||
char savestate_name[256];
|
||||
|
||||
struct
|
||||
{
|
||||
float *data;
|
||||
size_t data_ptr;
|
||||
size_t chunk_size;
|
||||
size_t nonblock_chunk_size;
|
||||
size_t block_chunk_size;
|
||||
|
||||
float *outsamples;
|
||||
int16_t *conv_outsamples;
|
||||
} audio_data;
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
ffemu_t *rec;
|
||||
char record_path[256];
|
||||
|
52
ssnes.c
52
ssnes.c
@ -40,10 +40,6 @@ struct global g_extern = {
|
||||
};
|
||||
|
||||
// To avoid continous switching if we hold the button down, we require that the button must go from pressed, unpressed back to pressed to be able to toggle between then.
|
||||
|
||||
#define AUDIO_CHUNK_SIZE_BLOCKING 64
|
||||
#define AUDIO_CHUNK_SIZE_NONBLOCKING 2048 // So we don't get complete line-noise when fast-forwarding audio.
|
||||
static size_t audio_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING;
|
||||
static void set_fast_forward_button(bool new_button_state)
|
||||
{
|
||||
static bool old_button_state = false;
|
||||
@ -55,10 +51,11 @@ static void set_fast_forward_button(bool new_button_state)
|
||||
driver.video->set_nonblock_state(driver.video_data, syncing_state);
|
||||
if (g_extern.audio_active)
|
||||
driver.audio->set_nonblock_state(driver.audio_data, (g_settings.audio.sync) ? syncing_state : true);
|
||||
|
||||
if (syncing_state)
|
||||
audio_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
|
||||
g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size;
|
||||
else
|
||||
audio_chunk_size = AUDIO_CHUNK_SIZE_BLOCKING;
|
||||
g_extern.audio_data.chunk_size = g_extern.audio_data.block_chunk_size;
|
||||
}
|
||||
old_button_state = new_button_state;
|
||||
}
|
||||
@ -163,37 +160,42 @@ static void audio_sample(uint16_t left, uint16_t right)
|
||||
}
|
||||
#endif
|
||||
|
||||
static float data[AUDIO_CHUNK_SIZE_NONBLOCKING];
|
||||
static int data_ptr = 0;
|
||||
g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(*(int16_t*)&left)/0x8000;
|
||||
g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(*(int16_t*)&right)/0x8000;
|
||||
|
||||
data[data_ptr++] = (float)(*(int16_t*)&left)/0x8000;
|
||||
data[data_ptr++] = (float)(*(int16_t*)&right)/0x8000;
|
||||
|
||||
if ( data_ptr >= audio_chunk_size )
|
||||
if (g_extern.audio_data.data_ptr >= g_extern.audio_data.chunk_size)
|
||||
{
|
||||
float outsamples[audio_chunk_size * 16];
|
||||
int16_t temp_outsamples[audio_chunk_size * 16];
|
||||
|
||||
SRC_DATA src_data;
|
||||
|
||||
src_data.data_in = data;
|
||||
src_data.data_out = outsamples;
|
||||
src_data.input_frames = audio_chunk_size / 2;
|
||||
src_data.output_frames = audio_chunk_size * 8;
|
||||
src_data.data_in = g_extern.audio_data.data;
|
||||
src_data.data_out = g_extern.audio_data.outsamples;
|
||||
src_data.input_frames = g_extern.audio_data.chunk_size / 2;
|
||||
src_data.output_frames = g_extern.audio_data.chunk_size * 8;
|
||||
src_data.end_of_input = 0;
|
||||
src_data.src_ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate;
|
||||
|
||||
src_process(g_extern.source, &src_data);
|
||||
|
||||
src_float_to_short_array(outsamples, temp_outsamples, src_data.output_frames_gen * 2);
|
||||
|
||||
if ( driver.audio->write(driver.audio_data, temp_outsamples, src_data.output_frames_gen * 4) < 0 )
|
||||
if (driver.audio->float_samples)
|
||||
{
|
||||
fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n");
|
||||
g_extern.audio_active = false;
|
||||
if (driver.audio->write(driver.audio_data, g_extern.audio_data.outsamples, src_data.output_frames_gen * sizeof(float) * 2) < 0)
|
||||
{
|
||||
fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n");
|
||||
g_extern.audio_active = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
src_float_to_short_array(g_extern.audio_data.outsamples, g_extern.audio_data.conv_outsamples, src_data.output_frames_gen * 2);
|
||||
|
||||
if (driver.audio->write(driver.audio_data, g_extern.audio_data.conv_outsamples, src_data.output_frames_gen * sizeof(int16_t) * 2) < 0)
|
||||
{
|
||||
fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n");
|
||||
g_extern.audio_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
data_ptr = 0;
|
||||
g_extern.audio_data.data_ptr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user