mirror of
https://github.com/libretro/RetroArch
synced 2025-03-12 04:14:23 +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 <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#define FRAMES(x) (x / (sizeof(int16_t) * 2))
|
#define FRAMES(x) (x / (sizeof(float) * 2))
|
||||||
#define SAMPLES(x) (x / sizeof(int16_t))
|
|
||||||
|
|
||||||
typedef struct jack
|
typedef struct jack
|
||||||
{
|
{
|
||||||
@ -61,13 +60,6 @@ static int process_cb(jack_nframes_t nframes, void *data)
|
|||||||
if (min_avail > nframes)
|
if (min_avail > nframes)
|
||||||
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++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
jack_default_audio_sample_t *out = jack_port_get_buffer(jd->ports[i], nframes);
|
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);
|
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)
|
static void parse_ports(const char **dest_ports, const char **jports)
|
||||||
{
|
{
|
||||||
int parsed = 0;
|
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 = (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);
|
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++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
jd->buffer[i] = jack_ringbuffer_create(bufsize);
|
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_cond_init(&jd->cond, NULL);
|
||||||
pthread_mutex_init(&jd->cond_lock, NULL);
|
pthread_mutex_init(&jd->cond_lock, NULL);
|
||||||
|
|
||||||
|
|
||||||
jack_free(jports);
|
jack_free(jports);
|
||||||
return jd;
|
return jd;
|
||||||
|
|
||||||
@ -191,17 +176,13 @@ error:
|
|||||||
return NULL;
|
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)];
|
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 (int i = 0; i < 2; i++)
|
||||||
for (size_t j = 0; j < FRAMES(size); j++)
|
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(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
@ -216,13 +197,11 @@ static size_t write_buffer(jack_t *jd, const void *buf, size_t size)
|
|||||||
if (jd->nonblock)
|
if (jd->nonblock)
|
||||||
{
|
{
|
||||||
if (min_avail < FRAMES(size) * sizeof(jack_default_audio_sample_t))
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//fprintf(stderr, "Write avail is: %d\n", (int)min_avail);
|
|
||||||
if (min_avail >= FRAMES(size) * sizeof(jack_default_audio_sample_t))
|
if (min_avail >= FRAMES(size) * sizeof(jack_default_audio_sample_t))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -290,6 +269,7 @@ const audio_driver_t audio_jack = {
|
|||||||
.start = __jack_start,
|
.start = __jack_start,
|
||||||
.set_nonblock_state = __jack_set_nonblock_state,
|
.set_nonblock_state = __jack_set_nonblock_state,
|
||||||
.free = __jack_free,
|
.free = __jack_free,
|
||||||
|
.float_samples = true,
|
||||||
.ident = "jack"
|
.ident = "jack"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
26
driver.c
26
driver.c
@ -21,6 +21,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "hqflt/filters.h"
|
#include "hqflt/filters.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -128,6 +129,9 @@ void uninit_drivers(void)
|
|||||||
uninit_audio();
|
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)
|
void init_audio(void)
|
||||||
{
|
{
|
||||||
if (!g_settings.audio.enable)
|
if (!g_settings.audio.enable)
|
||||||
@ -138,17 +142,35 @@ void init_audio(void)
|
|||||||
|
|
||||||
find_audio_driver();
|
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);
|
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 )
|
if ( driver.audio_data == NULL )
|
||||||
g_extern.audio_active = false;
|
g_extern.audio_active = false;
|
||||||
|
|
||||||
|
|
||||||
if (!g_settings.audio.sync && g_extern.audio_active)
|
if (!g_settings.audio.sync && g_extern.audio_active)
|
||||||
|
{
|
||||||
driver.audio->set_nonblock_state(driver.audio_data, true);
|
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;
|
int err;
|
||||||
g_extern.source = src_new(g_settings.audio.src_quality, 2, &err);
|
g_extern.source = src_new(g_settings.audio.src_quality, 2, &err);
|
||||||
if (!g_extern.source)
|
if (!g_extern.source)
|
||||||
g_extern.audio_active = false;
|
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)
|
void uninit_audio(void)
|
||||||
@ -164,6 +186,10 @@ void uninit_audio(void)
|
|||||||
|
|
||||||
if ( g_extern.source )
|
if ( g_extern.source )
|
||||||
src_delete(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)
|
void init_video_input(void)
|
||||||
|
1
driver.h
1
driver.h
@ -61,6 +61,7 @@ typedef struct audio_driver
|
|||||||
bool (*start)(void* data);
|
bool (*start)(void* data);
|
||||||
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding.
|
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about blocking in audio thread? Fast forwarding.
|
||||||
void (*free)(void* data);
|
void (*free)(void* data);
|
||||||
|
bool float_samples; // Defines if driver will take standard floating point samples, or int16_t samples.
|
||||||
const char *ident;
|
const char *ident;
|
||||||
} audio_driver_t;
|
} audio_driver_t;
|
||||||
|
|
||||||
|
12
general.h
12
general.h
@ -117,6 +117,18 @@ struct global
|
|||||||
char savefile_name_bsrm[512];
|
char savefile_name_bsrm[512];
|
||||||
char savestate_name[256];
|
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
|
#ifdef HAVE_FFMPEG
|
||||||
ffemu_t *rec;
|
ffemu_t *rec;
|
||||||
char record_path[256];
|
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.
|
// 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 void set_fast_forward_button(bool new_button_state)
|
||||||
{
|
{
|
||||||
static bool old_button_state = false;
|
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);
|
driver.video->set_nonblock_state(driver.video_data, syncing_state);
|
||||||
if (g_extern.audio_active)
|
if (g_extern.audio_active)
|
||||||
driver.audio->set_nonblock_state(driver.audio_data, (g_settings.audio.sync) ? syncing_state : true);
|
driver.audio->set_nonblock_state(driver.audio_data, (g_settings.audio.sync) ? syncing_state : true);
|
||||||
|
|
||||||
if (syncing_state)
|
if (syncing_state)
|
||||||
audio_chunk_size = AUDIO_CHUNK_SIZE_NONBLOCKING;
|
g_extern.audio_data.chunk_size = g_extern.audio_data.nonblock_chunk_size;
|
||||||
else
|
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;
|
old_button_state = new_button_state;
|
||||||
}
|
}
|
||||||
@ -163,37 +160,42 @@ static void audio_sample(uint16_t left, uint16_t right)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static float data[AUDIO_CHUNK_SIZE_NONBLOCKING];
|
g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(*(int16_t*)&left)/0x8000;
|
||||||
static int data_ptr = 0;
|
g_extern.audio_data.data[g_extern.audio_data.data_ptr++] = (float)(*(int16_t*)&right)/0x8000;
|
||||||
|
|
||||||
data[data_ptr++] = (float)(*(int16_t*)&left)/0x8000;
|
if (g_extern.audio_data.data_ptr >= g_extern.audio_data.chunk_size)
|
||||||
data[data_ptr++] = (float)(*(int16_t*)&right)/0x8000;
|
|
||||||
|
|
||||||
if ( data_ptr >= audio_chunk_size )
|
|
||||||
{
|
{
|
||||||
float outsamples[audio_chunk_size * 16];
|
|
||||||
int16_t temp_outsamples[audio_chunk_size * 16];
|
|
||||||
|
|
||||||
SRC_DATA src_data;
|
SRC_DATA src_data;
|
||||||
|
|
||||||
src_data.data_in = data;
|
src_data.data_in = g_extern.audio_data.data;
|
||||||
src_data.data_out = outsamples;
|
src_data.data_out = g_extern.audio_data.outsamples;
|
||||||
src_data.input_frames = audio_chunk_size / 2;
|
src_data.input_frames = g_extern.audio_data.chunk_size / 2;
|
||||||
src_data.output_frames = audio_chunk_size * 8;
|
src_data.output_frames = g_extern.audio_data.chunk_size * 8;
|
||||||
src_data.end_of_input = 0;
|
src_data.end_of_input = 0;
|
||||||
src_data.src_ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate;
|
src_data.src_ratio = (double)g_settings.audio.out_rate / (double)g_settings.audio.in_rate;
|
||||||
|
|
||||||
src_process(g_extern.source, &src_data);
|
src_process(g_extern.source, &src_data);
|
||||||
|
|
||||||
src_float_to_short_array(outsamples, temp_outsamples, src_data.output_frames_gen * 2);
|
if (driver.audio->float_samples)
|
||||||
|
|
||||||
if ( driver.audio->write(driver.audio_data, temp_outsamples, src_data.output_frames_gen * 4) < 0 )
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "SSNES [ERROR]: Audio backend failed to write. Will continue without sound.\n");
|
if (driver.audio->write(driver.audio_data, g_extern.audio_data.outsamples, src_data.output_frames_gen * sizeof(float) * 2) < 0)
|
||||||
g_extern.audio_active = false;
|
{
|
||||||
|
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