mirror of
https://github.com/libretro/RetroArch
synced 2025-03-28 08:37:41 +00:00
Should improve the state of audio.
This commit is contained in:
parent
fc43e7155e
commit
a5079bdda1
@ -43,7 +43,7 @@ INCDIRS = -I. -Icommon
|
||||
MAKE_FSELF_NPDRM = $(CELL_SDK)/$(HOST_DIR)/bin/make_fself_npdrm
|
||||
MAKE_PACKAGE_NPDRM = $(CELL_SDK)/$(HOST_DIR)/bin/make_package_npdrm
|
||||
|
||||
OBJ = ps3/buffer.o ps3/ps3_audio.o ps3/resampler.o ps3/ps3_input.o ps3/pad_input.o getopt.o ssnes.o driver.o file.o settings.o message.o rewind.o movie.o gfx/gfx_common.o ps3/ps3_video_psgl.o gfx/shader_cg.o gfx/snes_state.o ups.o bps.o strl.o screenshot.o audio/hermite.o dynamic.o ps3/main.o audio/utils.o
|
||||
OBJ = fifo_buffer.o ps3/ps3_audio.o ps3/ps3_input.o ps3/pad_input.o getopt.o ssnes.o driver.o file.o settings.o message.o rewind.o movie.o gfx/gfx_common.o ps3/ps3_video_psgl.o gfx/shader_cg.o gfx/snes_state.o ups.o bps.o strl.o screenshot.o audio/hermite.o dynamic.o ps3/main.o audio/utils.o
|
||||
|
||||
LIBS = -ldbgfont -lPSGL -lgcm_cmd -lgcm_sys_stub -lsnes -lresc_stub -lm -lio_stub -lfs_stub -lsysutil_stub -lsysmodule_stub -laudio_stub -lnet_stub -lpthread
|
||||
|
||||
|
101
ps3/buffer.c
101
ps3/buffer.c
@ -1,101 +0,0 @@
|
||||
/* RSound - A PCM audio client/server
|
||||
* Copyright (C) 2010 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RSound is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RSound is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RSound.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
struct fifo_buffer
|
||||
{
|
||||
char *buffer;
|
||||
size_t bufsize;
|
||||
size_t first;
|
||||
size_t end;
|
||||
};
|
||||
|
||||
fifo_buffer_t* fifo_new(size_t size)
|
||||
{
|
||||
fifo_buffer_t *buf = calloc(1, sizeof(*buf));
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
buf->buffer = calloc(1, size + 1);
|
||||
if (buf->buffer == NULL)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
buf->bufsize = size + 1;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void fifo_free(fifo_buffer_t* buffer)
|
||||
{
|
||||
free(buffer->buffer);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
size_t fifo_read_avail(fifo_buffer_t* buffer)
|
||||
{
|
||||
size_t first = buffer->first;
|
||||
size_t end = buffer->end;
|
||||
if (end < first)
|
||||
end += buffer->bufsize;
|
||||
return end - first;
|
||||
}
|
||||
|
||||
size_t fifo_write_avail(fifo_buffer_t* buffer)
|
||||
{
|
||||
size_t first = buffer->first;
|
||||
size_t end = buffer->end;
|
||||
if (end < first)
|
||||
end += buffer->bufsize;
|
||||
|
||||
return (buffer->bufsize - 1) - (end - first);
|
||||
}
|
||||
|
||||
void fifo_write(fifo_buffer_t* buffer, const void* in_buf, size_t size)
|
||||
{
|
||||
size_t first_write = size;
|
||||
size_t rest_write = 0;
|
||||
if (buffer->end + size > buffer->bufsize)
|
||||
{
|
||||
first_write = buffer->bufsize - buffer->end;
|
||||
rest_write = size - first_write;
|
||||
}
|
||||
|
||||
memcpy(buffer->buffer + buffer->end, in_buf, first_write);
|
||||
if (rest_write > 0)
|
||||
memcpy(buffer->buffer, (const char*)in_buf + first_write, rest_write);
|
||||
|
||||
buffer->end = (buffer->end + size) % buffer->bufsize;
|
||||
}
|
||||
|
||||
|
||||
void fifo_read(fifo_buffer_t* buffer, void* in_buf, size_t size)
|
||||
{
|
||||
size_t first_read = size;
|
||||
size_t rest_read = 0;
|
||||
if (buffer->first + size > buffer->bufsize)
|
||||
{
|
||||
first_read = buffer->bufsize - buffer->first;
|
||||
rest_read = size - first_read;
|
||||
}
|
||||
|
||||
memcpy(in_buf, (const char*)buffer->buffer + buffer->first, first_read);
|
||||
if (rest_read > 0)
|
||||
memcpy((char*)in_buf + first_read, buffer->buffer, rest_read);
|
||||
|
||||
buffer->first = (buffer->first + size) % buffer->bufsize;
|
||||
}
|
32
ps3/buffer.h
32
ps3/buffer.h
@ -1,32 +0,0 @@
|
||||
/* RSound - A PCM audio client/server
|
||||
* Copyright (C) 2010 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RSound is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RSound is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RSound.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BUFFER_H
|
||||
#define __BUFFER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct fifo_buffer fifo_buffer_t;
|
||||
|
||||
fifo_buffer_t* fifo_new(size_t size);
|
||||
void fifo_write(fifo_buffer_t* buffer, const void* in_buf, size_t size);
|
||||
void fifo_read(fifo_buffer_t* buffer, void* in_buf, size_t size);
|
||||
void fifo_free(fifo_buffer_t* buffer);
|
||||
size_t fifo_read_avail(fifo_buffer_t* buffer);
|
||||
size_t fifo_write_avail(fifo_buffer_t* buffer);
|
||||
|
||||
#endif
|
@ -16,27 +16,24 @@
|
||||
*/
|
||||
|
||||
#include "../driver.h"
|
||||
#include "../general.h"
|
||||
#include <stdlib.h>
|
||||
#include <cell/audio.h>
|
||||
#include <sys/timer.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "buffer.h"
|
||||
#include "resampler.h"
|
||||
#include "../fifo_buffer.h"
|
||||
#include <sys/event.h>
|
||||
|
||||
#define AUDIO_BLOCKS 8 // 8 or 16. Guess what we choose? :)
|
||||
#define AUDIO_CHANNELS 2 // All hail glorious stereo!
|
||||
#define AUDIO_OUT_RATE (48000.0)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float tmp_data[CELL_AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS];
|
||||
uint32_t audio_port;
|
||||
bool nonblocking;
|
||||
volatile bool quit_thread;
|
||||
fifo_buffer_t *buffer;
|
||||
uint64_t input_rate;
|
||||
|
||||
pthread_t thread;
|
||||
pthread_mutex_t lock;
|
||||
@ -44,27 +41,6 @@ typedef struct
|
||||
pthread_cond_t cond;
|
||||
} ps3_audio_t;
|
||||
|
||||
static size_t drain_fifo(void *cb_data, float **data)
|
||||
{
|
||||
ps3_audio_t *aud = cb_data;
|
||||
|
||||
int16_t tmp[CELL_AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS];
|
||||
|
||||
if (fifo_read_avail(aud->buffer) >= sizeof(tmp))
|
||||
{
|
||||
pthread_mutex_lock(&aud->lock);
|
||||
fifo_read(aud->buffer, tmp, sizeof(tmp));
|
||||
pthread_mutex_unlock(&aud->lock);
|
||||
resampler_s16_to_float(aud->tmp_data, tmp, CELL_AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(aud->tmp_data, 0, sizeof(aud->tmp_data));
|
||||
}
|
||||
*data = aud->tmp_data;
|
||||
return CELL_AUDIO_BLOCK_SAMPLES;
|
||||
}
|
||||
|
||||
static void *event_loop(void *data)
|
||||
{
|
||||
ps3_audio_t *aud = data;
|
||||
@ -75,37 +51,41 @@ static void *event_loop(void *data)
|
||||
cellAudioCreateNotifyEventQueue(&id, &key);
|
||||
cellAudioSetNotifyEventQueue(key);
|
||||
|
||||
resampler_t *resampler = resampler_new(drain_fifo, AUDIO_OUT_RATE/aud->input_rate, 2, data);
|
||||
|
||||
float out_tmp[CELL_AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS] __attribute__((aligned(16)));
|
||||
|
||||
while (!aud->quit_thread)
|
||||
{
|
||||
sys_event_queue_receive(id, &event, SYS_NO_TIMEOUT);
|
||||
resampler_cb_read(resampler, CELL_AUDIO_BLOCK_SAMPLES, out_tmp);
|
||||
|
||||
pthread_mutex_lock(&aud->lock);
|
||||
if (fifo_read_avail(aud->buffer) >= sizeof(out_tmp))
|
||||
fifo_read(aud->buffer, out_tmp, sizeof(out_tmp));
|
||||
else
|
||||
memset(out_tmp, 0, sizeof(out_tmp));
|
||||
pthread_mutex_unlock(&aud->lock);
|
||||
|
||||
cellAudioAddData(aud->audio_port, out_tmp, CELL_AUDIO_BLOCK_SAMPLES, 1.0);
|
||||
pthread_cond_signal(&aud->cond);
|
||||
}
|
||||
|
||||
cellAudioRemoveNotifyEventQueue(key);
|
||||
resampler_free(resampler);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* __ps3_init(const char* device, unsigned rate, unsigned latency)
|
||||
static void *ps3_audio_init(const char *device, unsigned rate, unsigned latency)
|
||||
{
|
||||
(void)latency;
|
||||
(void)device;
|
||||
(void)rate; // Always use 48kHz.
|
||||
g_settings.audio.out_rate = 48000.0;
|
||||
|
||||
ps3_audio_t *data = calloc(1, sizeof(*data));
|
||||
if (data == NULL)
|
||||
if (!data)
|
||||
return NULL;
|
||||
|
||||
CellAudioPortParam params;
|
||||
|
||||
cellAudioInit();
|
||||
|
||||
params.nChannel = AUDIO_CHANNELS;
|
||||
params.nBlock = AUDIO_BLOCKS;
|
||||
params.attr = 0;
|
||||
@ -113,12 +93,11 @@ static void* __ps3_init(const char* device, unsigned rate, unsigned latency)
|
||||
if (cellAudioPortOpen(¶ms, &data->audio_port) != CELL_OK)
|
||||
{
|
||||
cellAudioQuit();
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a small fifo buffer. :)
|
||||
data->buffer = fifo_new(CELL_AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS * AUDIO_BLOCKS * sizeof(int16_t));
|
||||
data->input_rate = rate;
|
||||
data->buffer = fifo_new(CELL_AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS * AUDIO_BLOCKS * sizeof(float));
|
||||
|
||||
pthread_mutex_init(&data->lock, NULL);
|
||||
pthread_mutex_init(&data->cond_lock, NULL);
|
||||
@ -129,12 +108,10 @@ static void* __ps3_init(const char* device, unsigned rate, unsigned latency)
|
||||
return data;
|
||||
}
|
||||
|
||||
// Should make some noise at least. :)
|
||||
static ssize_t __ps3_write(void* data, const void* buf, size_t size) // Recieve exactly 1024 bytes at a time.
|
||||
static ssize_t ps3_audio_write(void *data, const void *buf, size_t size)
|
||||
{
|
||||
ps3_audio_t *aud = data;
|
||||
|
||||
// We will continuously write slightly more data than we should per second, and rely on blocking mechanisms to ensure we don't write too much.
|
||||
if (aud->nonblocking)
|
||||
{
|
||||
if (fifo_write_avail(aud->buffer) < size)
|
||||
@ -156,31 +133,32 @@ static ssize_t __ps3_write(void* data, const void* buf, size_t size) // Recieve
|
||||
return size;
|
||||
}
|
||||
|
||||
static bool __ps3_stop(void *data)
|
||||
static bool ps3_audio_stop(void *data)
|
||||
{
|
||||
//ps3_audio_t *aud = data;
|
||||
//cellAudioPortStop(aud->audio_port);
|
||||
ps3_audio_t *aud = data;
|
||||
cellAudioPortStop(aud->audio_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __ps3_start(void *data)
|
||||
static bool ps3_audio_start(void *data)
|
||||
{
|
||||
//ps3_audio_t *aud = data;
|
||||
//cellAudioPortStart(aud->audio_port);
|
||||
ps3_audio_t *aud = data;
|
||||
cellAudioPortStart(aud->audio_port);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __ps3_set_nonblock_state(void *data, bool state)
|
||||
static void ps3_audio_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
ps3_audio_t *aud = data;
|
||||
aud->nonblocking = state;
|
||||
}
|
||||
|
||||
static void __ps3_free(void *data)
|
||||
static void ps3_audio_free(void *data)
|
||||
{
|
||||
ps3_audio_t *aud = data;
|
||||
|
||||
aud->quit_thread = true;
|
||||
cellAudioPortStart(aud->audio_port);
|
||||
pthread_join(aud->thread, NULL);
|
||||
|
||||
cellAudioPortStop(aud->audio_port);
|
||||
@ -195,12 +173,20 @@ static void __ps3_free(void *data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
static bool ps3_audio_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return true;
|
||||
}
|
||||
|
||||
const audio_driver_t audio_ps3 = {
|
||||
.init = __ps3_init,
|
||||
.write = __ps3_write,
|
||||
.stop = __ps3_stop,
|
||||
.start = __ps3_start,
|
||||
.set_nonblock_state = __ps3_set_nonblock_state,
|
||||
.free = __ps3_free,
|
||||
.init = ps3_audio_init,
|
||||
.write = ps3_audio_write,
|
||||
.stop = ps3_audio_stop,
|
||||
.start = ps3_audio_start,
|
||||
.set_nonblock_state = ps3_audio_set_nonblock_state,
|
||||
.use_float = ps3_audio_use_float,
|
||||
.free = ps3_audio_free,
|
||||
.ident = "ps3"
|
||||
};
|
||||
|
||||
|
225
ps3/resampler.c
225
ps3/resampler.c
@ -1,225 +0,0 @@
|
||||
/* RSound - A PCM audio client/server
|
||||
* Copyright (C) 2010 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RSound is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RSound is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RSound.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "resampler.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SAMPLES_TO_FRAMES(x,y) ((x)/(y)->channels)
|
||||
#define FRAMES_TO_SAMPLES(x,y) ((x)*(y)->channels)
|
||||
|
||||
struct resampler
|
||||
{
|
||||
float *data;
|
||||
double ratio;
|
||||
size_t data_ptr;
|
||||
size_t data_size;
|
||||
void *cb_data;
|
||||
int channels;
|
||||
resampler_cb_t func;
|
||||
uint64_t sum_output_frames;
|
||||
uint64_t sum_input_frames;
|
||||
};
|
||||
|
||||
resampler_t* resampler_new(resampler_cb_t func, double ratio, int channels, void* cb_data)
|
||||
{
|
||||
if (func == NULL)
|
||||
return NULL;
|
||||
|
||||
if (channels < 1)
|
||||
return NULL;
|
||||
|
||||
resampler_t* state = calloc(1, sizeof(resampler_t));
|
||||
if (state == NULL)
|
||||
return NULL;
|
||||
|
||||
state->func = func;
|
||||
state->ratio = ratio;
|
||||
state->channels = channels;
|
||||
state->cb_data = cb_data;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void resampler_free(resampler_t* state)
|
||||
{
|
||||
if (state && state->data)
|
||||
free(state->data);
|
||||
if (state)
|
||||
free(state);
|
||||
}
|
||||
|
||||
void resampler_float_to_s16(int16_t * restrict out, const float * restrict in, size_t samples)
|
||||
{
|
||||
for (int i = 0; i < (int)samples; i++)
|
||||
{
|
||||
int32_t temp = in[i] * 0x7FFF;
|
||||
if (temp > 0x7FFE)
|
||||
out[i] = 0x7FFE;
|
||||
else if (temp < -0x7FFF)
|
||||
out[i] = -0x7FFF;
|
||||
else
|
||||
out[i] = (int16_t)temp;
|
||||
}
|
||||
}
|
||||
|
||||
void resampler_s16_to_float(float * restrict out, const int16_t * restrict in, size_t samples)
|
||||
{
|
||||
for (int i = 0; i < (int)samples; i++)
|
||||
out[i] = (float)in[i]/0x7FFF;
|
||||
}
|
||||
|
||||
static size_t resampler_get_required_frames(resampler_t* state, size_t frames)
|
||||
{
|
||||
assert(state);
|
||||
|
||||
size_t after_sum = state->sum_output_frames + frames;
|
||||
|
||||
size_t min_input_frames = (size_t)((after_sum / state->ratio) + 2.0);
|
||||
return min_input_frames - state->sum_input_frames;
|
||||
}
|
||||
|
||||
static void poly_create_3(float *poly, float *y)
|
||||
{
|
||||
poly[2] = (y[0] - 2*y[1] + y[2])/2;
|
||||
poly[1] = -1.5*y[0] + 2*y[1] - 0.5*y[2];
|
||||
poly[0] = y[0];
|
||||
}
|
||||
|
||||
static size_t resampler_process(resampler_t *state, size_t frames, float *out_data)
|
||||
{
|
||||
size_t frames_used = 0;
|
||||
uint64_t pos_out;
|
||||
double pos_in = 0.0;
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "=========================================\n");
|
||||
fprintf(stderr, "Output: %zu frames.\n", frames);
|
||||
fprintf(stderr, "Output frames: %zu - %zu\n", state->sum_output_frames, state->sum_output_frames + frames);
|
||||
fprintf(stderr, "Needed input frames: %zu - %zu\n", (size_t)(state->sum_output_frames/state->ratio), (size_t)((state->sum_output_frames + frames)/state->ratio + 1.0));
|
||||
fprintf(stderr, "Current input frames: %zu - %zu\n", state->sum_input_frames, state->sum_input_frames + SAMPLES_TO_FRAMES(state->data_ptr, state));
|
||||
fprintf(stderr, "=========================================\n");
|
||||
|
||||
assert(state->sum_input_frames <= (size_t)(state->sum_output_frames/state->ratio));
|
||||
assert(state->sum_input_frames + SAMPLES_TO_FRAMES(state->data_ptr, state) - 1 >= (size_t)((state->sum_output_frames + frames - 1)/state->ratio + 1.0));
|
||||
#endif
|
||||
|
||||
for (uint64_t x = state->sum_output_frames; x < state->sum_output_frames + frames; x++)
|
||||
{
|
||||
pos_out = x - state->sum_output_frames;
|
||||
pos_in = ((double)x / state->ratio) - (double)state->sum_input_frames;
|
||||
//pos_in = pos_out / state->ratio;
|
||||
//fprintf(stderr, "pos_in: %15.7lf\n", pos_in + state->sum_input_frames);
|
||||
for (int c = 0; c < state->channels; c++)
|
||||
{
|
||||
|
||||
|
||||
float poly[3];
|
||||
float data[3];
|
||||
float x_val;
|
||||
|
||||
if ((int)pos_in == 0)
|
||||
{
|
||||
data[0] = state->data[0 * state->channels + c];
|
||||
data[1] = state->data[1 * state->channels + c];
|
||||
data[2] = state->data[2 * state->channels + c];
|
||||
x_val = pos_in;
|
||||
}
|
||||
else
|
||||
{
|
||||
data[0] = state->data[((int)pos_in - 1) * state->channels + c];
|
||||
data[1] = state->data[((int)pos_in + 0) * state->channels + c];
|
||||
data[2] = state->data[((int)pos_in + 1) * state->channels + c];
|
||||
x_val = pos_in - (int)pos_in + 1.0;
|
||||
}
|
||||
|
||||
poly_create_3(poly, data);
|
||||
|
||||
out_data[pos_out * state->channels + c] = poly[2] * x_val * x_val + poly[1] * x_val + poly[0];
|
||||
}
|
||||
}
|
||||
frames_used = (int)pos_in;
|
||||
return frames_used;
|
||||
}
|
||||
|
||||
ssize_t resampler_cb_read(resampler_t *state, size_t frames, float *data)
|
||||
{
|
||||
assert(state);
|
||||
assert(data);
|
||||
|
||||
|
||||
// How many frames must we have to resample?
|
||||
size_t req_frames = resampler_get_required_frames(state, frames);
|
||||
|
||||
// Do we need to read more data?
|
||||
if (SAMPLES_TO_FRAMES(state->data_ptr, state) < req_frames)
|
||||
{
|
||||
size_t must_read = req_frames - SAMPLES_TO_FRAMES(state->data_ptr, state);
|
||||
float temp_buf[FRAMES_TO_SAMPLES(must_read, state)];
|
||||
|
||||
size_t has_read = 0;
|
||||
|
||||
size_t copy_size = 0;
|
||||
size_t ret = 0;
|
||||
float *ptr = NULL;
|
||||
while (has_read < must_read)
|
||||
{
|
||||
ret = state->func(state->cb_data, &ptr);
|
||||
|
||||
if (ret == 0 || ptr == NULL) // We're done.
|
||||
return -1;
|
||||
|
||||
copy_size = (ret > must_read - has_read) ? (must_read - has_read) : ret;
|
||||
memcpy(temp_buf + FRAMES_TO_SAMPLES(has_read, state), ptr, FRAMES_TO_SAMPLES(copy_size, state) * sizeof(float));
|
||||
|
||||
has_read += ret;
|
||||
}
|
||||
|
||||
// We might have gotten a lot of data from the callback. We should realloc our buffer if needed.
|
||||
size_t req_buffer_frames = SAMPLES_TO_FRAMES(state->data_ptr, state) + has_read;
|
||||
|
||||
if (req_buffer_frames > SAMPLES_TO_FRAMES(state->data_size, state))
|
||||
{
|
||||
state->data = realloc(state->data, FRAMES_TO_SAMPLES(req_buffer_frames, state) * sizeof(float));
|
||||
if (state->data == NULL)
|
||||
return -1;
|
||||
|
||||
state->data_size = FRAMES_TO_SAMPLES(req_buffer_frames, state);
|
||||
}
|
||||
|
||||
memcpy(state->data + state->data_ptr, temp_buf, FRAMES_TO_SAMPLES(must_read, state) * sizeof(float));
|
||||
state->data_ptr += FRAMES_TO_SAMPLES(must_read, state);
|
||||
|
||||
// We have some data from the callback we need to copy over as well.
|
||||
if (ret > copy_size)
|
||||
{
|
||||
memcpy(state->data + state->data_ptr, ptr + FRAMES_TO_SAMPLES(copy_size, state), FRAMES_TO_SAMPLES(ret - copy_size, state) * sizeof(float));
|
||||
state->data_ptr += FRAMES_TO_SAMPLES(ret - copy_size, state);
|
||||
}
|
||||
}
|
||||
|
||||
// Phew. We should have enough data in our buffer now to be able to process the data we need.
|
||||
|
||||
size_t frames_used = resampler_process(state, frames, data);
|
||||
state->sum_input_frames += frames_used;
|
||||
memmove(state->data, state->data + FRAMES_TO_SAMPLES(frames_used, state), (state->data_ptr - FRAMES_TO_SAMPLES(frames_used, state)) * sizeof(float));
|
||||
state->data_ptr -= FRAMES_TO_SAMPLES(frames_used, state);
|
||||
state->sum_output_frames += frames;
|
||||
|
||||
return frames;
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/* RSound - A PCM audio client/server
|
||||
* Copyright (C) 2010 - Hans-Kristian Arntzen
|
||||
*
|
||||
* RSound is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RSound is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RSound.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RSD_RESAMPLER
|
||||
#define RSD_RESAMPLER
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef size_t (*resampler_cb_t) (void *cb_data, float **data);
|
||||
|
||||
typedef struct resampler resampler_t;
|
||||
|
||||
resampler_t* resampler_new(resampler_cb_t func, double ratio, int channels, void* cb_data);
|
||||
ssize_t resampler_cb_read(resampler_t *state, size_t frames, float *data);
|
||||
void resampler_free(resampler_t* state);
|
||||
|
||||
void resampler_float_to_s16(int16_t * restrict out, const float * restrict in, size_t samples);
|
||||
void resampler_s16_to_float(float * restrict out, const int16_t * restrict in, size_t samples);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user