aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sfx/softseq/fluidsynth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/sfx/softseq/fluidsynth.cpp')
-rw-r--r--engines/sci/sfx/softseq/fluidsynth.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/engines/sci/sfx/softseq/fluidsynth.cpp b/engines/sci/sfx/softseq/fluidsynth.cpp
new file mode 100644
index 0000000000..a44d75e5bd
--- /dev/null
+++ b/engines/sci/sfx/softseq/fluidsynth.cpp
@@ -0,0 +1,262 @@
+/***************************************************************************
+ fluidsynth.c Copyright (C) 2008 Walter van Niftrik
+
+ This program may be modified and copied freely according to the terms of
+ the GNU general public license (GPL), as long as the above copyright
+ notice and the licensing information contained herein are preserved.
+
+ Please refer to www.gnu.org for licensing details.
+
+ This work is provided AS IS, without warranty of any kind, expressed or
+ implied, including but not limited to the warranties of merchantibility,
+ noninfringement, and fitness for a specific purpose. The author will not
+ be held liable for any damage caused by this work or derivatives of it.
+
+ By using this source code, you agree to the licensing terms as stated
+ above.
+
+
+ Please contact the maintainer for bug reports or inquiries.
+
+ Current Maintainer:
+
+ Walter van Niftrik <w.f.b.w.v.niftrik@stud.tue.nl>
+
+***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_FLUIDSYNTH_H
+
+#include <fluidsynth.h>
+
+#include "../softseq.h"
+#include "../sequencer.h"
+#include "../device.h"
+#include "resource.h"
+
+static sfx_sequencer_t *gmseq;
+static fluid_settings_t* settings;
+static fluid_synth_t* synth;
+static guint8 status;
+static char *soundfont = "/etc/midi/8MBGMSFX.SF2";
+static int rpn[16];
+
+#define SAMPLE_RATE 44100
+#define CHANNELS SFX_PCM_STEREO_LR
+
+/* MIDI writer */
+
+static int
+fluidsynth_midi_init(struct _midi_writer *self)
+{
+ return SFX_OK;
+}
+
+static int
+fluidsynth_midi_set_option(struct _midi_writer *self, char *name, char *value)
+{
+ return SFX_ERROR;
+}
+
+static int
+fluidsynth_midi_write(struct _midi_writer *self, unsigned char *buf, int len)
+{
+ if (buf[0] == 0xf0)
+ sciprintf("FluidSynth: Skipping sysex message.\n");
+ else if (len == 2) {
+ guint8 command, channel;
+
+ command = buf[0] & 0xf0;
+ channel = buf[0] & 0x0f;
+
+ switch(command) {
+ case 0xc0:
+ fluid_synth_program_change(synth, channel, buf[1]);
+ break;
+ default:
+ printf("FluidSynth: MIDI command [%02x %02x] not supported\n", buf[0], buf[1]);
+ }
+ }
+ else if (len == 3) {
+ guint8 command, channel;
+
+ command = buf[0] & 0xf0;
+ channel = buf[0] & 0x0f;
+
+ switch(command) {
+ case 0x80:
+ fluid_synth_noteoff(synth, channel, buf[1]);
+ break;
+ case 0x90:
+ fluid_synth_noteon(synth, channel, buf[1], buf[2]);
+ break;
+ case 0xb0:
+ switch (buf[1]) {
+ case 0x06:
+ /* Data Entry Slider - course */
+ if (rpn[channel] == 0)
+ fluid_synth_pitch_wheel_sens(synth, channel, buf[2]);
+ else
+ sciprintf("FluidSynth: RPN %i not supported\n", rpn[channel]);
+ case 0x64:
+ /* Registered Parameter Number (RPN) - fine */
+ rpn[channel] &= ~0x7f;
+ rpn[channel] |= buf[2] & 0x7f;
+ break;
+ case 0x65:
+ /* Registered Parameter Number (RPN) - course */
+ rpn[channel] &= ~0x3f80;
+ rpn[channel] |= (buf[2] & 0x7f) << 7;
+ break;
+ default:
+ fluid_synth_cc(synth, channel, buf[1], buf[2]);
+ }
+ break;
+ case 0xe0:
+ fluid_synth_pitch_bend(synth, channel, (buf[2] << 7) | buf[1]);
+ break;
+ default:
+ sciprintf("FluidSynth: MIDI command [%02x %02x %02x] not supported\n", buf[0], buf[1], buf[2]);
+ }
+ }
+ else
+ sciprintf("FluidSynth: Skipping invalid message of %i bytes.\n", len);
+
+ return SFX_OK;
+}
+
+static void
+fluidsynth_midi_delay(struct _midi_writer *self, int ticks)
+{
+}
+
+static void
+fluidsynth_midi_reset_timer(struct _midi_writer *self)
+{
+}
+
+static void
+fluidsynth_midi_close(struct _midi_writer *self)
+{
+}
+
+static midi_writer_t midi_writer_fluidsynth = {
+ "fluidsynth",
+ fluidsynth_midi_init,
+ fluidsynth_midi_set_option,
+ fluidsynth_midi_write,
+ fluidsynth_midi_delay,
+ NULL,
+ fluidsynth_midi_reset_timer,
+ fluidsynth_midi_close
+};
+
+/* Software sequencer */
+
+static void
+fluidsynth_poll(sfx_softseq_t *self, byte *dest, int count)
+{
+ fluid_synth_write_s16(synth, count, dest, 0, 2, dest + 2, 0, 2);
+}
+
+static int
+fluidsynth_init(sfx_softseq_t *self, byte *data_ptr, int data_length,
+ byte *data2_ptr, int data2_length)
+{
+ int sfont_id;
+ double min, max;
+
+ if (0) {
+ sciprintf("FluidSynth ERROR: Mono sound output not supported.\n");
+ return SFX_ERROR;
+ }
+
+ gmseq = sfx_find_sequencer("General MIDI");
+ if (!gmseq) {
+ sciprintf("FluidSynth ERROR: Unable to find General MIDI sequencer.\n");
+ return SFX_ERROR;
+ }
+
+ settings = new_fluid_settings();
+
+ fluid_settings_getnum_range(settings, "synth.sample-rate", &min, &max);
+ if (SAMPLE_RATE < min || SAMPLE_RATE > max) {
+ sciprintf("FluidSynth ERROR: Sample rate '%i' not supported. Valid "
+ "range is (%i-%i).\n", SAMPLE_RATE, (int) min, (int) max);
+ delete_fluid_settings(settings);
+ return SFX_ERROR;
+ }
+
+ fluid_settings_setnum(settings, "synth.sample-rate", SAMPLE_RATE);
+ fluid_settings_setnum(settings, "synth.gain", 0.5f);
+
+ synth = new_fluid_synth(settings);
+
+ if ((sfont_id = fluid_synth_sfload(synth, soundfont, 1)) < 0) {
+ delete_fluid_synth(synth);
+ delete_fluid_settings(settings);
+ return SFX_ERROR;
+ }
+
+ gmseq->open(data_length, data_ptr, data2_length, data2_ptr,
+ &midi_writer_fluidsynth);
+
+ return SFX_OK;
+}
+
+static void
+fluidsynth_exit(sfx_softseq_t *self)
+{
+ delete_fluid_synth(synth);
+ delete_fluid_settings(settings);
+}
+
+static void
+fluidsynth_allstop(sfx_softseq_t *self)
+{
+ if (gmseq->allstop)
+ gmseq->allstop();
+}
+
+static void
+fluidsynth_volume(sfx_softseq_t *self, int volume)
+{
+ if (gmseq->volume)
+ gmseq->volume(volume);
+}
+
+static int
+fluidsynth_set_option(sfx_softseq_t *self, char *name, char *value)
+{
+ return SFX_ERROR;
+}
+
+static void
+fluidsynth_event(sfx_softseq_t *self, byte cmd, int argc, byte *argv)
+{
+ gmseq->event(cmd, argc, argv);
+}
+
+sfx_softseq_t sfx_softseq_fluidsynth = {
+ "fluidsynth",
+ "0.1",
+ fluidsynth_set_option,
+ fluidsynth_init,
+ fluidsynth_exit,
+ fluidsynth_volume,
+ fluidsynth_event,
+ fluidsynth_poll,
+ fluidsynth_allstop,
+ NULL,
+ 004, /* patch.004 */
+ 001, /* patch.001 */
+ 0x01, /* playflag */
+ 1, /* do play channel 9 */
+ 32, /* Max polypgony */
+ {SAMPLE_RATE, CHANNELS, SFX_PCM_FORMAT_S16_NATIVE}
+};
+
+#endif /* HAVE_FLUIDSYNTH_H */