diff --git a/projects/VisualStudio2013/mupen64plus-ui-console.vcxproj b/projects/VisualStudio2013/mupen64plus-ui-console.vcxproj
index a76eca7..28e288f 100644
--- a/projects/VisualStudio2013/mupen64plus-ui-console.vcxproj
+++ b/projects/VisualStudio2013/mupen64plus-ui-console.vcxproj
@@ -122,22 +122,34 @@ copy ..\..\..\mupen64plus-win32-deps\zlib-1.2.3\bin\*.dll "$(OutDir)"
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/projects/unix/Makefile b/projects/unix/Makefile
index a4a05e3..9611dad 100755
--- a/projects/unix/Makefile
+++ b/projects/unix/Makefile
@@ -229,7 +229,18 @@ SOURCE = \
$(SRCDIR)/compare_core.c \
$(SRCDIR)/core_interface.c \
$(SRCDIR)/main.c \
- $(SRCDIR)/plugin.c
+ $(SRCDIR)/object_factory.c \
+ $(SRCDIR)/plugin.c \
+ $(SRCDIR)/audio_backends/circular_buffer.c \
+ $(SRCDIR)/audio_backends/dummy_audio_backend.c \
+ $(SRCDIR)/resamplers/resampler.c \
+ $(SRCDIR)/resamplers/trivial_resampler.c
+
+# optional audio backends
+ifeq ($(HAVE_SDL_AUDIO_BACKEND),1)
+ CFLAGS += '-DHAVE_SDL_AUDIO_BACKEND'
+ SOURCE += $(SRCDIR)/audio_backends/sdl_audio_backend.c
+endif
ifeq ($(OS), MINGW)
SOURCE += \
@@ -265,7 +276,9 @@ targets:
@echo " OPTFLAGS=flags == compiler optimization (default: -O3 -flto)"
@echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)"
@echo " PIE=(1|0) == Force enable/disable of position independent executables"
- @echo " POSTFIX=name == String added to the name of the the build (default: '')"
+ @echo " POSTFIX=name == String added to the name of the the build (default: '')"
+ @echo " Optional modules:"
+ @echo " HAVE_SDL_AUDIO_BACKEND=(1|0) == enable|disable SDL audio backend compilation (default:0)"
@echo " Install Options:"
@echo " PREFIX=path == install/uninstall prefix (default: /usr/local/)"
@echo " BINDIR=path == path to install mupen64plus binary (default: PREFIX/bin/)"
diff --git a/src/audio_backends/circular_buffer.c b/src/audio_backends/circular_buffer.c
new file mode 100644
index 0000000..f7f18ab
--- /dev/null
+++ b/src/audio_backends/circular_buffer.c
@@ -0,0 +1,83 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - circular_buffer.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "circular_buffer.h"
+
+#include
+#include
+#include
+
+
+int init_cbuff(struct circular_buffer* cbuff, size_t capacity)
+{
+ void* data = malloc(capacity);
+
+ if (data == NULL)
+ {
+ return -1;
+ }
+
+ cbuff->data = data;
+ cbuff->size = capacity;
+ cbuff->head = 0;
+
+ return 0;
+}
+
+void release_cbuff(struct circular_buffer* cbuff)
+{
+ free(cbuff->data);
+ memset(cbuff, 0, sizeof(*cbuff));
+}
+
+
+void* cbuff_head(const struct circular_buffer* cbuff, size_t* available)
+{
+ assert(cbuff->head <= cbuff->size);
+
+ *available = cbuff->size - cbuff->head;
+ return (void*)((char*)cbuff->data + cbuff->head);
+}
+
+
+void* cbuff_tail(const struct circular_buffer* cbuff, size_t* available)
+{
+ *available = cbuff->head;
+ return cbuff->data;
+}
+
+
+void produce_cbuff_data(struct circular_buffer* cbuff, size_t amount)
+{
+ assert(cbuff->head + amount <= cbuff->size);
+
+ cbuff->head += amount;
+}
+
+
+void consume_cbuff_data(struct circular_buffer* cbuff, size_t amount)
+{
+ assert(cbuff->head >= amount);
+
+ memmove(cbuff->data, cbuff->data + amount, cbuff->head - amount);
+ cbuff->head -= amount;
+}
+
diff --git a/src/audio_backends/circular_buffer.h b/src/audio_backends/circular_buffer.h
new file mode 100644
index 0000000..07b45c8
--- /dev/null
+++ b/src/audio_backends/circular_buffer.h
@@ -0,0 +1,46 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - circular_buffer.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef M64P_CIRCULAR_BUFFER_H
+#define M64P_CIRCULAR_BUFFER_H
+
+#include
+
+struct circular_buffer
+{
+ void* data;
+ size_t size;
+ size_t head;
+};
+
+int init_cbuff(struct circular_buffer* cbuff, size_t capacity);
+
+void release_cbuff(struct circular_buffer* cbuff);
+
+void* cbuff_head(const struct circular_buffer* cbuff, size_t* available);
+
+void* cbuff_tail(const struct circular_buffer* cbuff, size_t* available);
+
+void produce_cbuff_data(struct circular_buffer* cbuff, size_t amount);
+
+void consume_cbuff_data(struct circular_buffer* cbuff, size_t amount);
+
+#endif
diff --git a/src/audio_backends/dummy_audio_backend.c b/src/audio_backends/dummy_audio_backend.c
new file mode 100644
index 0000000..c2e57c5
--- /dev/null
+++ b/src/audio_backends/dummy_audio_backend.c
@@ -0,0 +1,45 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - dummy_audio_backend.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "dummy_audio_backend.h"
+
+#include "m64p_types.h"
+
+#include
+
+/* dummy audio backend factory implementation */
+static m64p_error init(void* object)
+{
+ struct m64p_audio_backend* backend = (struct m64p_audio_backend*)object;
+
+ /* set to NULL all members to trigger dummy audio backend behavior in the core */
+ memset(backend, 0, sizeof(*backend));
+
+ return M64ERR_SUCCESS;
+}
+
+static void release(void* object)
+{
+}
+
+
+const struct object_factory dummy_audio_backend_factory = { "dummy", init, release };
+
diff --git a/src/audio_backends/dummy_audio_backend.h b/src/audio_backends/dummy_audio_backend.h
new file mode 100644
index 0000000..a314c2b
--- /dev/null
+++ b/src/audio_backends/dummy_audio_backend.h
@@ -0,0 +1,29 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - dummy_audio_backend.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef M64P_DUMMY_AUDIO_BACKEND_H
+#define M64P_DUMMY_AUDIO_BACKEND_H
+
+#include "object_factory.h"
+
+const struct object_factory dummy_audio_backend_factory;
+
+#endif
diff --git a/src/audio_backends/sdl_audio_backend.c b/src/audio_backends/sdl_audio_backend.c
new file mode 100644
index 0000000..35a843c
--- /dev/null
+++ b/src/audio_backends/sdl_audio_backend.c
@@ -0,0 +1,390 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - sdl_audio_backend.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "sdl_audio_backend.h"
+
+#include "circular_buffer.h"
+#include "m64p_types.h"
+#include "main.h"
+#include "object_factory.h"
+#include "resamplers/resampler.h"
+
+#include
+
+#include
+#include
+
+
+struct sdl_data
+{
+ struct circular_buffer primary_buffer;
+ size_t target;
+ size_t secondary_buffer_size;
+
+ unsigned int last_cb_time;
+ unsigned int input_frequency;
+ unsigned int output_frequency;
+ unsigned int speed_factor;
+
+ struct m64p_resampler resampler;
+ void (*release_resampler)(void* object);
+
+ unsigned int error;
+ unsigned int swap_channels;
+};
+
+
+static struct sdl_data* new_sdl_data(size_t primary_buffer_size,
+ size_t target,
+ size_t secondary_buffer_size,
+ const struct object_factory* resampler_factory,
+ unsigned int swap_channels)
+{
+ /* allocate sdl_data */
+ struct sdl_data* sdl_data = malloc(sizeof(*sdl_data));
+ if (sdl_data == NULL)
+ return NULL;
+
+ /* init primary bugffer */
+ if (init_cbuff(&sdl_data->primary_buffer, primary_buffer_size) != 0)
+ goto free_sdl_data;
+
+ /* init resampler */
+ if (resampler_factory->init(&sdl_data->resampler) != M64ERR_SUCCESS)
+ goto release_primary_buffer;
+
+ /* init other fields */
+ sdl_data->target = target;
+ sdl_data->secondary_buffer_size = secondary_buffer_size;
+ sdl_data->last_cb_time = 0;
+ sdl_data->input_frequency = 0;
+ sdl_data->output_frequency = 0;
+ sdl_data->speed_factor = 100;
+ sdl_data->release_resampler = resampler_factory->release;
+ sdl_data->error = 0;
+ sdl_data->swap_channels = swap_channels;
+
+ return sdl_data;
+
+release_primary_buffer:
+ release_cbuff(&sdl_data->primary_buffer);
+free_sdl_data:
+ free(sdl_data);
+ return NULL;
+}
+
+static void delete_sdl_data(struct sdl_data* sdl_data)
+{
+ sdl_data->release_resampler(&sdl_data->resampler);
+ release_cbuff(&sdl_data->primary_buffer);
+ free(sdl_data);
+}
+
+/* SDL audio callback.
+ * Pop and resample a certain amount of samples from the primary buffer
+ */
+static void audio_cb(void* userdata, unsigned char* stream, int len)
+{
+ unsigned int old_sample_rate;
+ unsigned int new_sample_rate;
+ size_t available;
+ size_t needed;
+ size_t consumed;
+ const void* src;
+ struct sdl_data* sdl_data = (struct sdl_data*)userdata;
+
+ /* update last_cb_time */
+ sdl_data->last_cb_time = SDL_GetTicks();
+
+ /* compute samples rates, and needed number of bytes */
+ old_sample_rate = sdl_data->input_frequency;
+ new_sample_rate = sdl_data->output_frequency * 100 / sdl_data->speed_factor;
+ needed = len * old_sample_rate / new_sample_rate;
+
+ src = cbuff_tail(&sdl_data->primary_buffer, &available);
+ if ((available > 0) && (available >= needed))
+ {
+ /* consume samples */
+ consumed = resample(&sdl_data->resampler, src, available, old_sample_rate, stream, len, new_sample_rate);
+ consume_cbuff_data(&sdl_data->primary_buffer, consumed);
+ }
+ else
+ {
+ /* buffer underflow */
+ DebugMessage(M64MSG_VERBOSE, "buffer underflow");
+ memset(stream, 0, len);
+ }
+}
+
+
+/* Select output frequency depending on input_frequency */
+static unsigned int select_output_frequency(unsigned int input_frequency)
+{
+ if (input_frequency <= 11025) { return 11025; }
+ else if (input_frequency <= 22050) { return 22050; }
+ else { return 44100; }
+}
+
+
+/* Initialize the audio device. */
+static void init_audio_device(struct sdl_data* sdl_data)
+{
+ SDL_AudioSpec desired, obtained;
+
+ if (SDL_WasInit(SDL_INIT_AUDIO | SDL_INIT_TIMER) == (SDL_INIT_AUDIO | SDL_INIT_TIMER))
+ {
+ SDL_PauseAudio(1);
+ SDL_CloseAudio();
+ }
+ else
+ {
+ /* initilize sdl subsystems */
+ if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0)
+ {
+ DebugMessage(M64MSG_ERROR, "Failed to initialize SDL audio subsystem");
+ sdl_data->error = 1;
+ return;
+ }
+ }
+
+ memset(&desired, 0, sizeof(desired));
+ desired.freq = select_output_frequency(sdl_data->input_frequency);
+ desired.format = AUDIO_S16SYS;
+ desired.channels = 2;
+ desired.samples = sdl_data->secondary_buffer_size / (2 * 2);
+ desired.callback = audio_cb;
+ desired.userdata = sdl_data;
+
+ if (SDL_OpenAudio(&desired, &obtained) < 0)
+ {
+ DebugMessage(M64MSG_ERROR, "Failed to open the audio device: %s", SDL_GetError());
+ sdl_data->error = 1;
+ return;
+ }
+
+ sdl_data->output_frequency = obtained.freq;
+
+ if (sdl_data->last_cb_time == 0)
+ sdl_data->last_cb_time = SDL_GetTicks();
+
+ sdl_data->error = 0;
+
+ DebugMessage(M64MSG_INFO, "Audio device initialized: freq=%dHz (input freq=%dHz)",
+ sdl_data->output_frequency, sdl_data->input_frequency);
+}
+
+
+static void memcpy_swap_LR16(void* dst, const void* src, size_t size)
+{
+ /* assume a size multiple of 4 */
+ size_t i;
+ uint32_t v;
+ const uint32_t* src_ = src;
+ uint32_t* dst_ = dst;
+
+ for(i = 0; i < size; i += 4)
+ {
+ v = *src_;
+ *dst_ = (v << 16) | (v >> 16);
+
+ ++src_;
+ ++dst_;
+ }
+}
+
+static void push_incoming_samples(struct sdl_data* sdl_data, const void* buffer, size_t size)
+{
+ size_t available;
+ void* dst = cbuff_head(&sdl_data->primary_buffer, &available);
+
+ if (size > available)
+ {
+ DebugMessage(M64MSG_VERBOSE, "Audio buffer overflow. Requested %d Available %d", size, available);
+ }
+ else
+ {
+ SDL_LockAudio();
+
+ if (sdl_data->swap_channels == 0)
+ {
+ memcpy(dst, buffer, size);
+ }
+ else
+ {
+ memcpy_swap_LR16(dst, buffer, size);
+ }
+
+ SDL_UnlockAudio();
+
+ produce_cbuff_data(&sdl_data->primary_buffer, size);
+ }
+}
+
+static size_t estimate_consumable_size_at_next_audio_cb(const struct sdl_data* sdl_data)
+{
+ size_t available;
+ size_t current_size, expected_size;
+ unsigned int current_time, expected_cb_time; /* in ms */
+
+
+ cbuff_tail(&sdl_data->primary_buffer, &available);
+
+
+ current_size = (available * sdl_data->output_frequency * 100)
+ / (sdl_data->input_frequency * sdl_data->speed_factor);
+
+ current_time = SDL_GetTicks();
+
+ /* estimate time to next audio_cb */
+ expected_cb_time = sdl_data->last_cb_time
+ + (1000 * sdl_data->secondary_buffer_size / 4) / sdl_data->output_frequency;
+
+ /* estimate consumable size at next audio_cb */
+ expected_size = current_size;
+ if (current_time < expected_cb_time)
+ {
+ expected_size += (expected_cb_time - current_time) * sdl_data->output_frequency * 4 / 1000;
+ }
+
+ return expected_size;
+}
+
+/* handle SDL Audio Thread / Core synchronization to avoid {over,under}flows */
+static void synchronize_audio(struct sdl_data* sdl_data)
+{
+ size_t expected_size = estimate_consumable_size_at_next_audio_cb(sdl_data);
+
+ if (expected_size >= sdl_data->target + sdl_data->output_frequency / 100)
+ {
+ /* Core is ahead of SDL audio thread,
+ * delay emulation to allow the SDL audio thread to catch up */
+ unsigned int wait_time = (expected_size - sdl_data->target) * 1000 / (4*sdl_data->output_frequency);
+
+ SDL_PauseAudio(0);
+ SDL_Delay(wait_time);
+ }
+ else if (expected_size < sdl_data->secondary_buffer_size)
+ {
+ /* Core is behind SDL audio thread (predicting an underflow),
+ * pause the audio to let the Core catch up */
+ SDL_PauseAudio(1);
+ }
+ else
+ {
+ /* expected size is within tolerance, everything is okay */
+ SDL_PauseAudio(0);
+ }
+}
+
+
+static void set_audio_format(void* user_data, unsigned int frequency, unsigned int bits)
+{
+ struct sdl_data* sdl_data = (struct sdl_data*)user_data;
+
+ //DebugMessage(M64MSG_WARNING, "SDL audio backend set format: %dHz %d bits", frequency, bits);
+
+ /* XXX: assume 16bit samples whatever */
+ if (bits != 16)
+ {
+ DebugMessage(M64MSG_WARNING, "Incoming samples are not 16 bits (%d)", bits);
+ }
+
+ sdl_data->input_frequency = frequency;
+ init_audio_device(sdl_data);
+}
+
+static void push_audio_samples(void* user_data, const void* buffer, size_t size)
+{
+ struct sdl_data* sdl_data = (struct sdl_data*)user_data;
+
+ //DebugMessage(M64MSG_WARNING, "SDL audio backend push samples: @%p 0x%x bytes", buffer, size);
+
+ if (sdl_data->error != 0 || sdl_data->input_frequency == 0 || sdl_data->output_frequency == 0)
+ return;
+
+ push_incoming_samples(sdl_data, buffer, size);
+ synchronize_audio(sdl_data);
+}
+
+
+static m64p_error init(void* object)
+{
+ const struct object_factory* resampler_factory;
+ struct sdl_data* sdl_data;
+
+ /* XXX: parse config file to retrieve the values */
+ size_t primary_buffer_size = 16384 * 4;
+ size_t target = 10240 * 4;
+ size_t secondary_buffer_size = 2048 * 4;
+ unsigned int swap_channels = 1;
+ const char* resampler_name = "trivial";
+
+ struct m64p_audio_backend* backend = (struct m64p_audio_backend*)object;
+
+ /* get resampler factory */
+ resampler_factory = get_object_factory(resampler_factories, resampler_name);
+ if (resampler_factory == NULL)
+ {
+ DebugMessage(M64MSG_ERROR, "Couldn't find resampler factory: %s", resampler_name);
+ return M64ERR_INPUT_INVALID;
+ }
+
+ /* allocate and initialize sdl_data */
+ sdl_data = new_sdl_data(primary_buffer_size,
+ target,
+ secondary_buffer_size,
+ resampler_factory,
+ swap_channels);
+ if (sdl_data == NULL)
+ {
+ DebugMessage(M64MSG_ERROR, "Couldn't create new sdl_data !");
+ return M64ERR_NO_MEMORY;
+ }
+
+ /* fill backend structure */
+ backend->user_data = sdl_data;
+ backend->set_audio_format = set_audio_format;
+ backend->push_audio_samples = push_audio_samples;
+
+ return M64ERR_SUCCESS;
+}
+
+static void release(void* object)
+{
+ struct m64p_audio_backend* backend = (struct m64p_audio_backend*)object;
+ struct sdl_data* sdl_data = (struct sdl_data*)backend->user_data;
+
+ if (SDL_WasInit(SDL_INIT_AUDIO) != 0)
+ {
+ SDL_PauseAudio(1);
+ SDL_CloseAudio();
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+ }
+
+ if (SDL_WasInit(SDL_INIT_TIMER) != 0)
+ SDL_QuitSubSystem(SDL_INIT_TIMER);
+
+ delete_sdl_data(sdl_data);
+ memset(backend, 0, sizeof(*backend));
+}
+
+const struct object_factory sdl_audio_backend_factory = { "sdl", init, release };
+
diff --git a/src/audio_backends/sdl_audio_backend.h b/src/audio_backends/sdl_audio_backend.h
new file mode 100644
index 0000000..52d0bbe
--- /dev/null
+++ b/src/audio_backends/sdl_audio_backend.h
@@ -0,0 +1,29 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - sdl_audio_backend.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef M64P_SDL_AUDIO_BACKEND_H
+#define M64P_SDL_AUDIO_BACKEND_H
+
+#include "object_factory.h"
+
+const struct object_factory sdl_audio_backend_factory;
+
+#endif
diff --git a/src/main.c b/src/main.c
index 6ddf47d..ff846c8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -36,6 +36,7 @@
#include "core_interface.h"
#include "m64p_types.h"
#include "main.h"
+#include "object_factory.h"
#include "osal_preproc.h"
#include "plugin.h"
#include "version.h"
@@ -633,6 +634,8 @@ __attribute__ ((visibility("default")))
int main(int argc, char *argv[])
{
int i;
+ const struct object_factory* l_AudioBackendFactory;
+ struct m64p_audio_backend l_AudioBackend = { 0 };
printf(" __ __ __ _ _ ____ _ \n");
printf("| \\/ |_ _ _ __ ___ _ __ / /_ | || | | _ \\| |_ _ ___ \n");
@@ -677,6 +680,54 @@ int main(int argc, char *argv[])
return 5;
}
+ /* list available audio backends if requested */
+ if (g_AudioPlugin != NULL)
+ {
+ if (strcmp(g_AudioPlugin,"list") == 0)
+ {
+ DebugMessage(M64MSG_INFO, "List of available audio backends:");
+ for(i = 0; audio_backend_factories[i] != NULL; ++i)
+ {
+ DebugMessage(M64MSG_INFO, "%d. %s", i, audio_backend_factories[i]->name);
+ }
+
+ (*CoreShutdown)();
+ DetachCoreLib();
+ return 0;
+ }
+ }
+
+ /* test if audio argument is an audio backend factory */
+ l_AudioBackendFactory = get_object_factory(audio_backend_factories, g_AudioPlugin);
+ if (l_AudioBackendFactory != NULL)
+ {
+ /* call audio backend init procedure */
+ if (l_AudioBackendFactory->init(&l_AudioBackend) != M64ERR_SUCCESS)
+ {
+ DebugMessage(M64MSG_ERROR, "failed initialization of %s audio backend", l_AudioBackendFactory->name);
+ memset(&l_AudioBackend, 0, sizeof(l_AudioBackend));
+ l_AudioBackendFactory = NULL;
+ }
+ else
+ {
+
+ /* let the core know about the audio backend */
+ if ((*CoreDoCommand)(M64CMD_SET_AUDIO_INTERFACE_BACKEND, M64P_AUDIO_BACKEND_VERSION, &l_AudioBackend) != M64ERR_SUCCESS)
+ {
+ DebugMessage(M64MSG_ERROR, "core error while setting %s audio backend", l_AudioBackendFactory->name);
+ l_AudioBackendFactory->release(&l_AudioBackend);
+ memset(&l_AudioBackend, 0, sizeof(l_AudioBackend));
+ l_AudioBackendFactory = NULL;
+ }
+ else
+ {
+ DebugMessage(M64MSG_INFO, "using audio backend %s", l_AudioBackendFactory->name);
+ /* disable audio plugin if audio backend was successfully set */
+ g_AudioPlugin = "dummy";
+ }
+ }
+ }
+
/* Handle the core comparison feature */
if (l_CoreCompareMode != 0 && !(g_CoreCapabilities & M64CAPS_CORE_COMPARE))
{
@@ -786,6 +837,14 @@ int main(int argc, char *argv[])
(*CoreDetachPlugin)(g_PluginMap[i].type);
PluginUnload();
+ /* release audio backend */
+ if (l_AudioBackendFactory != NULL)
+ {
+ l_AudioBackendFactory->release(&l_AudioBackend);
+ memset(&l_AudioBackend, 0, sizeof(l_AudioBackend));
+ l_AudioBackendFactory = NULL;
+ }
+
/* close the ROM image */
(*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
diff --git a/src/object_factory.c b/src/object_factory.c
new file mode 100644
index 0000000..54e134b
--- /dev/null
+++ b/src/object_factory.c
@@ -0,0 +1,67 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - object_factory.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "object_factory.h"
+
+#include "audio_backends/dummy_audio_backend.h"
+#include "resamplers/trivial_resampler.h"
+
+#ifdef HAVE_SDL_AUDIO_BACKEND
+#include "audio_backends/sdl_audio_backend.h"
+#endif
+
+#include
+
+
+const struct object_factory* const audio_backend_factories[] =
+{
+ &dummy_audio_backend_factory,
+#ifdef HAVE_SDL_AUDIO_BACKEND
+ &sdl_audio_backend_factory,
+#endif
+ NULL /* end of array sentinel */
+};
+
+const struct object_factory* const resampler_factories[] =
+{
+ &trivial_resampler_factory,
+ NULL /* end of array sentinel */
+};
+
+
+const struct object_factory* get_object_factory(const struct object_factory* const* factories, const char* name)
+{
+ if (factories != NULL && name != NULL)
+ {
+ while((*factories) != NULL)
+ {
+ if (strcmp(name, (*factories)->name) == 0)
+ {
+ return *factories;
+ }
+
+ ++factories;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/src/object_factory.h b/src/object_factory.h
new file mode 100644
index 0000000..498a5a9
--- /dev/null
+++ b/src/object_factory.h
@@ -0,0 +1,40 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - object_factory.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef M64P_OBJECT_FACTORY_H
+#define M64P_OBJECT_FACTORY_H
+
+#include "m64p_types.h"
+
+struct object_factory
+{
+ const char* name;
+ m64p_error (*init)(void* object);
+ void (*release)(void* object);
+};
+
+const struct object_factory*
+get_object_factory(const struct object_factory* const* factories, const char* name);
+
+extern const struct object_factory* const audio_backend_factories[];
+extern const struct object_factory* const resampler_factories[];
+
+#endif
diff --git a/src/resamplers/resampler.c b/src/resamplers/resampler.c
new file mode 100644
index 0000000..e211466
--- /dev/null
+++ b/src/resamplers/resampler.c
@@ -0,0 +1,32 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - resampler.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "resampler.h"
+
+size_t resample(struct m64p_resampler* resampler,
+ const void* src, size_t src_size, unsigned int input_frequency,
+ void* dst, size_t dst_size, unsigned int output_frequency)
+{
+ return resampler->resample(resampler->resampler_data,
+ src, src_size, input_frequency,
+ dst, dst_size, output_frequency);
+}
+
diff --git a/src/resamplers/resampler.h b/src/resamplers/resampler.h
new file mode 100644
index 0000000..a22d62d
--- /dev/null
+++ b/src/resamplers/resampler.h
@@ -0,0 +1,39 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - resampler.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef M64P_RESAMPLER_H
+#define M64P_RESAMPLER_H
+
+#include
+
+struct m64p_resampler
+{
+ void* resampler_data;
+ size_t (*resample)(void* resampler_data,
+ const void* src, size_t src_size, unsigned int input_frequency,
+ void* dst, size_t dst_size, unsigned int output_frequency);
+};
+
+size_t resample(struct m64p_resampler* resampler,
+ const void* src, size_t src_size, unsigned int input_frequency,
+ void* dst, size_t dst_size, unsigned int output_frequency);
+
+#endif
diff --git a/src/resamplers/trivial_resampler.c b/src/resamplers/trivial_resampler.c
new file mode 100644
index 0000000..bf0518f
--- /dev/null
+++ b/src/resamplers/trivial_resampler.c
@@ -0,0 +1,87 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - trivial_resampler.c *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#include "trivial_resampler.h"
+#include "resampler.h"
+
+#include "m64p_types.h"
+
+#include
+
+static size_t trivial_resample(void* resampler_data,
+ const void* src, size_t src_size, unsigned int input_frequency,
+ void* dst, size_t dst_size, unsigned int output_frequency)
+{
+ size_t i, j;
+
+ if (output_frequency >= input_frequency)
+ {
+ int sldf = input_frequency;
+ int const2 = 2*sldf;
+ int dldf = output_frequency;
+ int const1 = const2 - 2*dldf;
+ int criteria = const2 - dldf;
+
+ for (i = 0; i < dst_size/4; ++i)
+ {
+ ((uint32_t*)dst)[i] = ((uint32_t*)src)[j];
+
+ if (criteria >= 0)
+ {
+ ++j;
+ criteria += const1;
+ }
+ else
+ {
+ criteria += const2;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < dst_size/4; ++i)
+ {
+ j = i * input_frequency / output_frequency;
+ ((uint32_t*)dst)[i] = ((uint32_t*)src)[j];
+ }
+ }
+
+ return j * 4;
+}
+
+
+static m64p_error init(void* object)
+{
+ struct m64p_resampler* resampler = (struct m64p_resampler*)object;
+
+ /* fill resampler structure */
+ resampler->resampler_data = NULL;
+ resampler->resample = trivial_resample;
+
+ return M64ERR_SUCCESS;
+}
+
+static void release(void* object)
+{
+}
+
+const struct object_factory trivial_resampler_factory = { "trivial", init, release };
+
diff --git a/src/resamplers/trivial_resampler.h b/src/resamplers/trivial_resampler.h
new file mode 100644
index 0000000..565e50b
--- /dev/null
+++ b/src/resamplers/trivial_resampler.h
@@ -0,0 +1,29 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Mupen64plus-ui-console - trivial_resampler.h *
+ * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
+ * Copyright (C) 2015 Bobby Smiles *
+ * *
+ * This program 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 Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program 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 this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+#ifndef M64P_TRIVIAL_RESAMPLER_H
+#define M64P_TRIVIAL_RESAMPLER_H
+
+#include "object_factory.h"
+
+const struct object_factory trivial_resampler_factory;
+
+#endif