diff --git a/Makefile.ps3 b/Makefile.ps3 index d57081e61b..bddcf444f2 100644 --- a/Makefile.ps3 +++ b/Makefile.ps3 @@ -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 diff --git a/ps3/buffer.c b/ps3/buffer.c deleted file mode 100644 index 576cd14841..0000000000 --- a/ps3/buffer.c +++ /dev/null @@ -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 . - */ - -#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; -} diff --git a/ps3/buffer.h b/ps3/buffer.h deleted file mode 100644 index e7cb3497f1..0000000000 --- a/ps3/buffer.h +++ /dev/null @@ -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 . - */ - -#ifndef __BUFFER_H -#define __BUFFER_H - -#include -#include -#include - -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 diff --git a/ps3/ps3_audio.c b/ps3/ps3_audio.c index 761275ecd8..2fc0e8dc3f 100644 --- a/ps3/ps3_audio.c +++ b/ps3/ps3_audio.c @@ -16,27 +16,24 @@ */ #include "../driver.h" +#include "../general.h" #include #include #include #include #include -#include "buffer.h" -#include "resampler.h" +#include "../fifo_buffer.h" #include #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" }; + diff --git a/ps3/resampler.c b/ps3/resampler.c deleted file mode 100644 index 9d07430272..0000000000 --- a/ps3/resampler.c +++ /dev/null @@ -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 . - */ - - -#include "resampler.h" -#include -#include -#include -#include - -#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; -} diff --git a/ps3/resampler.h b/ps3/resampler.h deleted file mode 100644 index e96fb42eda..0000000000 --- a/ps3/resampler.h +++ /dev/null @@ -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 . - */ - -#ifndef RSD_RESAMPLER -#define RSD_RESAMPLER - -#include -#include -#include - -#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