2017-08-07 22:59:44 +02:00
|
|
|
/* some code borrowed from scummvm */
|
2017-08-08 22:51:47 -04:00
|
|
|
#ifdef USE_FLUIDSYNTH
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdio.h>
|
2017-08-07 22:59:44 +02:00
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <wchar.h>
|
2017-10-17 01:59:09 -04:00
|
|
|
#include "../86box.h"
|
2017-08-07 22:59:44 +02:00
|
|
|
#include "../config.h"
|
2017-10-10 03:22:22 -04:00
|
|
|
#include "../device.h"
|
2017-10-11 05:47:24 -04:00
|
|
|
#include "../plat.h"
|
|
|
|
|
#include "../plat_dynld.h"
|
2017-10-10 03:24:49 -04:00
|
|
|
#include "../ui.h"
|
2017-08-07 22:59:44 +02:00
|
|
|
#include "midi.h"
|
2017-09-25 04:31:20 -04:00
|
|
|
#include "midi_fluidsynth.h"
|
2017-08-07 22:59:44 +02:00
|
|
|
#include "sound.h"
|
|
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
|
2018-02-26 13:45:11 +01:00
|
|
|
#define FLUID_CHORUS_DEFAULT_N 3
|
|
|
|
|
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f
|
|
|
|
|
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f
|
|
|
|
|
#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f
|
|
|
|
|
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE
|
|
|
|
|
|
2017-08-14 19:43:08 +02:00
|
|
|
#define RENDER_RATE 100
|
|
|
|
|
#define BUFFER_SEGMENTS 10
|
2017-08-07 22:59:44 +02:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
|
2018-02-26 13:45:11 +01:00
|
|
|
enum fluid_chorus_mod {
|
|
|
|
|
FLUID_CHORUS_MOD_SINE = 0,
|
|
|
|
|
FLUID_CHORUS_MOD_TRIANGLE = 1
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum fluid_interp {
|
|
|
|
|
FLUID_INTERP_NONE = 0,
|
|
|
|
|
FLUID_INTERP_LINEAR = 1,
|
|
|
|
|
FLUID_INTERP_DEFAULT = 4,
|
|
|
|
|
FLUID_INTERP_4THORDER = 4,
|
|
|
|
|
FLUID_INTERP_7THORDER = 7,
|
|
|
|
|
FLUID_INTERP_HIGHEST = 7
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2017-08-07 22:59:44 +02:00
|
|
|
extern void givealbuffer_midi(void *buf, uint32_t size);
|
|
|
|
|
extern void al_set_midi(int freq, int buf_size);
|
|
|
|
|
extern int soundon;
|
|
|
|
|
|
2017-08-09 14:22:21 -04:00
|
|
|
static void *fluidsynth_handle; /* handle to FluidSynth DLL */
|
2017-08-08 16:14:50 +02:00
|
|
|
|
|
|
|
|
/* Pointers to the real functions. */
|
2018-02-26 13:45:11 +01:00
|
|
|
static void * (*f_new_fluid_settings)(void);
|
|
|
|
|
static void (*f_delete_fluid_settings)(void *settings);
|
|
|
|
|
static int (*f_fluid_settings_setnum)(void *settings, const char *name, double val);
|
|
|
|
|
static int (*f_fluid_settings_getnum)(void *settings, const char *name, double *val);
|
|
|
|
|
static void * (*f_new_fluid_synth)(void *settings);
|
|
|
|
|
static int (*f_delete_fluid_synth)(void *synth);
|
|
|
|
|
static int (*f_fluid_synth_noteon)(void *synth, int chan, int key, int vel);
|
|
|
|
|
static int (*f_fluid_synth_noteoff)(void *synth, int chan, int key);
|
|
|
|
|
static int (*f_fluid_synth_cc)(void *synth, int chan, int ctrl, int val);
|
|
|
|
|
static int (*f_fluid_synth_sysex)(void *synth, const char *data, int len, char *response, int *response_len, int *handled, int dryrun);
|
|
|
|
|
static int (*f_fluid_synth_pitch_bend)(void *synth, int chan, int val);
|
|
|
|
|
static int (*f_fluid_synth_program_change)(void *synth, int chan, int program);
|
|
|
|
|
static int (*f_fluid_synth_sfload)(void *synth, const char *filename, int reset_presets);
|
|
|
|
|
static int (*f_fluid_synth_set_interp_method)(void *synth, int chan, int interp_method);
|
|
|
|
|
static void (*f_fluid_synth_set_reverb)(void *synth, double roomsize, double damping, double width, double level);
|
|
|
|
|
static void (*f_fluid_synth_set_reverb_on)(void *synth, int on);
|
|
|
|
|
static void (*f_fluid_synth_set_chorus)(void *synth, int nr, double level, double speed, double depth_ms, int type);
|
|
|
|
|
static void (*f_fluid_synth_set_chorus_on)(void *synth, int on);
|
|
|
|
|
static int (*f_fluid_synth_write_s16)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr);
|
|
|
|
|
static int (*f_fluid_synth_write_float)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr);
|
2017-08-08 16:14:50 +02:00
|
|
|
static char* (*f_fluid_version_str)(void);
|
|
|
|
|
static dllimp_t fluidsynth_imports[] = {
|
|
|
|
|
{ "new_fluid_settings", &f_new_fluid_settings },
|
|
|
|
|
{ "delete_fluid_settings", &f_delete_fluid_settings },
|
|
|
|
|
{ "fluid_settings_setnum", &f_fluid_settings_setnum },
|
|
|
|
|
{ "fluid_settings_getnum", &f_fluid_settings_getnum },
|
|
|
|
|
{ "new_fluid_synth", &f_new_fluid_synth },
|
|
|
|
|
{ "delete_fluid_synth", &f_delete_fluid_synth },
|
|
|
|
|
{ "fluid_synth_noteon", &f_fluid_synth_noteon },
|
|
|
|
|
{ "fluid_synth_noteoff", &f_fluid_synth_noteoff },
|
|
|
|
|
{ "fluid_synth_cc", &f_fluid_synth_cc },
|
|
|
|
|
{ "fluid_synth_sysex", &f_fluid_synth_sysex },
|
|
|
|
|
{ "fluid_synth_pitch_bend", &f_fluid_synth_pitch_bend },
|
|
|
|
|
{ "fluid_synth_program_change", &f_fluid_synth_program_change },
|
|
|
|
|
{ "fluid_synth_sfload", &f_fluid_synth_sfload },
|
|
|
|
|
{ "fluid_synth_set_interp_method", &f_fluid_synth_set_interp_method },
|
|
|
|
|
{ "fluid_synth_set_reverb", &f_fluid_synth_set_reverb },
|
|
|
|
|
{ "fluid_synth_set_reverb_on", &f_fluid_synth_set_reverb_on },
|
|
|
|
|
{ "fluid_synth_set_chorus", &f_fluid_synth_set_chorus },
|
|
|
|
|
{ "fluid_synth_set_chorus_on", &f_fluid_synth_set_chorus_on },
|
|
|
|
|
{ "fluid_synth_write_s16", &f_fluid_synth_write_s16 },
|
|
|
|
|
{ "fluid_synth_write_float", &f_fluid_synth_write_float },
|
|
|
|
|
{ "fluid_version_str", &f_fluid_version_str },
|
|
|
|
|
{ NULL, NULL },
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2017-08-09 14:22:21 -04:00
|
|
|
typedef struct fluidsynth
|
2017-08-07 22:59:44 +02:00
|
|
|
{
|
2018-02-26 13:45:11 +01:00
|
|
|
void* settings;
|
|
|
|
|
void* synth;
|
2017-08-07 22:59:44 +02:00
|
|
|
int samplerate;
|
|
|
|
|
int sound_font;
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
thread_t *thread_h;
|
|
|
|
|
event_t *event, *start_event;
|
2017-08-07 22:59:44 +02:00
|
|
|
int buf_size;
|
|
|
|
|
float* buffer;
|
|
|
|
|
int16_t* buffer_int16;
|
|
|
|
|
int midi_pos;
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
int on;
|
2017-08-07 22:59:44 +02:00
|
|
|
} fluidsynth_t;
|
|
|
|
|
|
|
|
|
|
fluidsynth_t fsdev;
|
|
|
|
|
|
2017-08-09 14:22:21 -04:00
|
|
|
int fluidsynth_available(void)
|
2017-08-07 22:59:44 +02:00
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-09 14:22:21 -04:00
|
|
|
void fluidsynth_poll(void)
|
2017-08-07 22:59:44 +02:00
|
|
|
{
|
|
|
|
|
fluidsynth_t* data = &fsdev;
|
|
|
|
|
data->midi_pos++;
|
|
|
|
|
if (data->midi_pos == 48000/RENDER_RATE)
|
|
|
|
|
{
|
|
|
|
|
data->midi_pos = 0;
|
|
|
|
|
thread_set_event(data->event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fluidsynth_thread(void *param)
|
|
|
|
|
{
|
|
|
|
|
fluidsynth_t* data = (fluidsynth_t*)param;
|
2017-08-14 19:43:08 +02:00
|
|
|
int buf_pos = 0;
|
|
|
|
|
int buf_size = data->buf_size / BUFFER_SEGMENTS;
|
2018-10-10 22:33:24 +02:00
|
|
|
|
|
|
|
|
thread_set_event(data->start_event);
|
|
|
|
|
|
|
|
|
|
while (data->on)
|
2017-08-07 22:59:44 +02:00
|
|
|
{
|
|
|
|
|
thread_wait_event(data->event, -1);
|
2018-10-10 22:33:24 +02:00
|
|
|
thread_reset_event(data->event);
|
|
|
|
|
|
2017-08-14 19:43:08 +02:00
|
|
|
if (sound_is_float)
|
|
|
|
|
{
|
|
|
|
|
float *buf = (float*)((uint8_t*)data->buffer + buf_pos);
|
|
|
|
|
memset(buf, 0, buf_size);
|
|
|
|
|
if (data->synth)
|
|
|
|
|
f_fluid_synth_write_float(data->synth, buf_size/(2 * sizeof(float)), buf, 0, 2, buf, 1, 2);
|
|
|
|
|
buf_pos += buf_size;
|
|
|
|
|
if (buf_pos >= data->buf_size)
|
|
|
|
|
{
|
|
|
|
|
if (soundon)
|
|
|
|
|
givealbuffer_midi(data->buffer, data->buf_size / sizeof(float));
|
|
|
|
|
buf_pos = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
int16_t *buf = (int16_t*)((uint8_t*)data->buffer_int16 + buf_pos);
|
|
|
|
|
memset(buf, 0, buf_size);
|
|
|
|
|
if (data->synth)
|
|
|
|
|
f_fluid_synth_write_s16(data->synth, buf_size/(2 * sizeof(int16_t)), buf, 0, 2, buf, 1, 2);
|
|
|
|
|
buf_pos += buf_size;
|
|
|
|
|
if (buf_pos >= data->buf_size)
|
|
|
|
|
{
|
|
|
|
|
if (soundon)
|
|
|
|
|
givealbuffer_midi(data->buffer_int16, data->buf_size / sizeof(int16_t));
|
|
|
|
|
buf_pos = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
2017-08-07 22:59:44 +02:00
|
|
|
if (sound_is_float)
|
|
|
|
|
{
|
|
|
|
|
memset(data->buffer, 0, data->buf_size * sizeof(float));
|
|
|
|
|
if (data->synth)
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_write_float(data->synth, data->buf_size/2, data->buffer, 0, 2, data->buffer, 1, 2);
|
2017-08-07 22:59:44 +02:00
|
|
|
if (soundon)
|
|
|
|
|
givealbuffer_midi(data->buffer, data->buf_size);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
memset(data->buffer, 0, data->buf_size * sizeof(int16_t));
|
|
|
|
|
if (data->synth)
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_write_s16(data->synth, data->buf_size/2, data->buffer_int16, 0, 2, data->buffer_int16, 1, 2);
|
2017-08-07 22:59:44 +02:00
|
|
|
if (soundon)
|
|
|
|
|
givealbuffer_midi(data->buffer_int16, data->buf_size);
|
|
|
|
|
}
|
2017-08-14 19:43:08 +02:00
|
|
|
#endif
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void fluidsynth_msg(uint8_t *msg)
|
|
|
|
|
{
|
|
|
|
|
fluidsynth_t* data = &fsdev;
|
|
|
|
|
|
|
|
|
|
uint32_t val = *((uint32_t*)msg);
|
|
|
|
|
|
|
|
|
|
uint32_t param2 = (uint8_t) ((val >> 16) & 0xFF);
|
|
|
|
|
uint32_t param1 = (uint8_t) ((val >> 8) & 0xFF);
|
|
|
|
|
uint8_t cmd = (uint8_t) (val & 0xF0);
|
|
|
|
|
uint8_t chan = (uint8_t) (val & 0x0F);
|
|
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
case 0x80: /* Note Off */
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_noteoff(data->synth, chan, param1);
|
2017-08-07 22:59:44 +02:00
|
|
|
break;
|
|
|
|
|
case 0x90: /* Note On */
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_noteon(data->synth, chan, param1, param2);
|
2017-08-07 22:59:44 +02:00
|
|
|
break;
|
|
|
|
|
case 0xA0: /* Aftertouch */
|
|
|
|
|
break;
|
|
|
|
|
case 0xB0: /* Control Change */
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_cc(data->synth, chan, param1, param2);
|
2017-08-07 22:59:44 +02:00
|
|
|
break;
|
|
|
|
|
case 0xC0: /* Program Change */
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_program_change(data->synth, chan, param1);
|
2017-08-07 22:59:44 +02:00
|
|
|
break;
|
|
|
|
|
case 0xD0: /* Channel Pressure */
|
|
|
|
|
break;
|
|
|
|
|
case 0xE0: /* Pitch Bend */
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_pitch_bend(data->synth, chan, (param2 << 7) | param1);
|
2017-08-07 22:59:44 +02:00
|
|
|
break;
|
|
|
|
|
case 0xF0: /* SysEx */
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void fluidsynth_sysex(uint8_t* data, unsigned int len)
|
|
|
|
|
{
|
|
|
|
|
fluidsynth_t* d = &fsdev;
|
|
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_sysex(d->synth, (const char *) data, len, 0, 0, 0, 0);
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
void* fluidsynth_init(const device_t *info)
|
2017-08-07 22:59:44 +02:00
|
|
|
{
|
|
|
|
|
fluidsynth_t* data = &fsdev;
|
2018-10-10 22:33:24 +02:00
|
|
|
midi_device_t* dev;
|
|
|
|
|
|
2017-08-07 22:59:44 +02:00
|
|
|
memset(data, 0, sizeof(fluidsynth_t));
|
|
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
/* Try loading the DLL. */
|
2017-10-29 04:20:20 -05:00
|
|
|
#ifdef _WIN32
|
2018-04-25 23:51:13 +02:00
|
|
|
fluidsynth_handle = dynld_module("libfluidsynth-1.dll", fluidsynth_imports);
|
2017-10-28 03:32:46 -04:00
|
|
|
#else
|
|
|
|
|
fluidsynth_handle = dynld_module("libfluidsynth.so", fluidsynth_imports);
|
|
|
|
|
#endif
|
2017-08-08 16:14:50 +02:00
|
|
|
if (fluidsynth_handle == NULL)
|
|
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081);
|
2017-08-08 16:14:50 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data->settings = f_new_fluid_settings();
|
2017-08-07 22:59:44 +02:00
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_settings_setnum(data->settings, "synth.sample-rate", 44100);
|
|
|
|
|
f_fluid_settings_setnum(data->settings, "synth.gain", device_get_config_int("output_gain")/100.0f);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
data->synth = f_new_fluid_synth(data->settings);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
2018-09-06 14:38:43 +02:00
|
|
|
char* sound_font = (char *) device_get_config_string("sound_font");
|
2017-08-08 16:14:50 +02:00
|
|
|
data->sound_font = f_fluid_synth_sfload(data->synth, sound_font, 1);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
|
|
|
|
if (device_get_config_int("chorus"))
|
|
|
|
|
{
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_set_chorus_on(data->synth, 1);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
|
|
|
|
int chorus_voices = device_get_config_int("chorus_voices");
|
|
|
|
|
double chorus_level = device_get_config_int("chorus_level") / 100.0;
|
|
|
|
|
double chorus_speed = device_get_config_int("chorus_speed") / 100.0;
|
|
|
|
|
double chorus_depth = device_get_config_int("chorus_depth") / 10.0;
|
|
|
|
|
|
|
|
|
|
int chorus_waveform = FLUID_CHORUS_MOD_SINE;
|
|
|
|
|
if (device_get_config_int("chorus_waveform") == 0)
|
|
|
|
|
chorus_waveform = FLUID_CHORUS_MOD_SINE;
|
|
|
|
|
else
|
|
|
|
|
chorus_waveform = FLUID_CHORUS_MOD_TRIANGLE;
|
|
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_set_chorus(data->synth, chorus_voices, chorus_level, chorus_speed, chorus_depth, chorus_waveform);
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
else
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_set_chorus_on(data->synth, 0);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
|
|
|
|
if (device_get_config_int("reverb"))
|
|
|
|
|
{
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_set_reverb_on(data->synth, 1);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
|
|
|
|
double reverb_room_size = device_get_config_int("reverb_room_size") / 100.0;
|
|
|
|
|
double reverb_damping = device_get_config_int("reverb_damping") / 100.0;
|
|
|
|
|
int reverb_width = device_get_config_int("reverb_width");
|
|
|
|
|
double reverb_level = device_get_config_int("reverb_level") / 100.0;
|
|
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_set_reverb(data->synth, reverb_room_size, reverb_damping, reverb_width, reverb_level);
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
else
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_set_reverb_on(data->synth, 0);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
|
|
|
|
int interpolation = device_get_config_int("interpolation");
|
|
|
|
|
int fs_interpolation = FLUID_INTERP_4THORDER;
|
|
|
|
|
|
|
|
|
|
if (interpolation == 0)
|
|
|
|
|
fs_interpolation = FLUID_INTERP_NONE;
|
|
|
|
|
else if (interpolation == 1)
|
|
|
|
|
fs_interpolation = FLUID_INTERP_LINEAR;
|
|
|
|
|
else if (interpolation == 2)
|
|
|
|
|
fs_interpolation = FLUID_INTERP_4THORDER;
|
|
|
|
|
else if (interpolation == 3)
|
|
|
|
|
fs_interpolation = FLUID_INTERP_7THORDER;
|
|
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_synth_set_interp_method(data->synth, -1, fs_interpolation);
|
2017-08-07 22:59:44 +02:00
|
|
|
|
|
|
|
|
double samplerate;
|
2017-08-08 16:14:50 +02:00
|
|
|
f_fluid_settings_getnum(data->settings, "synth.sample-rate", &samplerate);
|
2017-08-07 22:59:44 +02:00
|
|
|
data->samplerate = (int)samplerate;
|
|
|
|
|
if (sound_is_float)
|
|
|
|
|
{
|
2017-08-14 19:43:08 +02:00
|
|
|
data->buf_size = (data->samplerate/RENDER_RATE)*2*sizeof(float)*BUFFER_SEGMENTS;
|
|
|
|
|
data->buffer = malloc(data->buf_size);
|
2017-08-07 22:59:44 +02:00
|
|
|
data->buffer_int16 = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-08-14 19:43:08 +02:00
|
|
|
data->buf_size = (data->samplerate/RENDER_RATE)*2*sizeof(int16_t)*BUFFER_SEGMENTS;
|
2017-08-07 22:59:44 +02:00
|
|
|
data->buffer = NULL;
|
2017-08-14 19:43:08 +02:00
|
|
|
data->buffer_int16 = malloc(data->buf_size);
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
al_set_midi(data->samplerate, data->buf_size);
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
dev = malloc(sizeof(midi_device_t));
|
2017-08-07 22:59:44 +02:00
|
|
|
memset(dev, 0, sizeof(midi_device_t));
|
|
|
|
|
|
|
|
|
|
dev->play_msg = fluidsynth_msg;
|
|
|
|
|
dev->play_sysex = fluidsynth_sysex;
|
|
|
|
|
dev->poll = fluidsynth_poll;
|
|
|
|
|
|
|
|
|
|
midi_init(dev);
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
data->on = 1;
|
|
|
|
|
|
|
|
|
|
data->start_event = thread_create_event();
|
|
|
|
|
|
|
|
|
|
data->event = thread_create_event();
|
|
|
|
|
data->thread_h = thread_create(fluidsynth_thread, data);
|
|
|
|
|
|
|
|
|
|
thread_wait_event(data->start_event, -1);
|
|
|
|
|
thread_reset_event(data->start_event);
|
|
|
|
|
|
2017-08-07 22:59:44 +02:00
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void fluidsynth_close(void* p)
|
|
|
|
|
{
|
|
|
|
|
if (!p) return;
|
|
|
|
|
|
|
|
|
|
fluidsynth_t* data = &fsdev;
|
|
|
|
|
|
2018-10-10 22:33:24 +02:00
|
|
|
data->on = 0;
|
|
|
|
|
thread_set_event(data->event);
|
|
|
|
|
thread_wait(data->thread_h, -1);
|
2017-10-14 07:03:19 +02:00
|
|
|
|
|
|
|
|
if (data->synth) {
|
|
|
|
|
f_delete_fluid_synth(data->synth);
|
|
|
|
|
data->synth = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data->settings) {
|
|
|
|
|
f_delete_fluid_settings(data->settings);
|
|
|
|
|
data->settings = NULL;
|
|
|
|
|
}
|
2017-08-07 22:59:44 +02:00
|
|
|
|
|
|
|
|
if (data->buffer)
|
|
|
|
|
{
|
|
|
|
|
free(data->buffer);
|
2017-08-14 19:43:08 +02:00
|
|
|
data->buffer = NULL;
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data->buffer_int16)
|
|
|
|
|
{
|
|
|
|
|
free(data->buffer_int16);
|
2017-08-14 19:43:08 +02:00
|
|
|
data->buffer_int16 = NULL;
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-08 16:14:50 +02:00
|
|
|
/* Unload the DLL if possible. */
|
|
|
|
|
if (fluidsynth_handle != NULL)
|
|
|
|
|
{
|
|
|
|
|
dynld_close(fluidsynth_handle);
|
|
|
|
|
fluidsynth_handle = NULL;
|
|
|
|
|
}
|
2017-08-07 22:59:44 +02:00
|
|
|
}
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
static const device_config_t fluidsynth_config[] =
|
2017-08-07 22:59:44 +02:00
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.name = "sound_font",
|
|
|
|
|
.description = "Sound Font",
|
2017-12-04 11:59:26 -05:00
|
|
|
.type = CONFIG_FNAME,
|
2017-08-07 22:59:44 +02:00
|
|
|
.default_string = "",
|
|
|
|
|
.file_filter =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.description = "SF2 Sound Fonts",
|
|
|
|
|
.extensions =
|
|
|
|
|
{
|
|
|
|
|
"sf2"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "output_gain",
|
|
|
|
|
.description = "Output Gain",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 100
|
|
|
|
|
},
|
|
|
|
|
.default_int = 100
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "chorus",
|
|
|
|
|
.description = "Chorus",
|
|
|
|
|
.type = CONFIG_BINARY,
|
|
|
|
|
.default_int = 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "chorus_voices",
|
|
|
|
|
.description = "Chorus Voices",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 99
|
|
|
|
|
},
|
|
|
|
|
.default_int = 3
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "chorus_level",
|
|
|
|
|
.description = "Chorus Level",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 100
|
|
|
|
|
},
|
|
|
|
|
.default_int = 100
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "chorus_speed",
|
|
|
|
|
.description = "Chorus Speed",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 30,
|
|
|
|
|
.max = 500
|
|
|
|
|
},
|
|
|
|
|
.default_int = 30
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "chorus_depth",
|
|
|
|
|
.description = "Chorus Depth",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 210
|
|
|
|
|
},
|
|
|
|
|
.default_int = 80
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "chorus_waveform",
|
|
|
|
|
.description = "Chorus Waveform",
|
|
|
|
|
.type = CONFIG_SELECTION,
|
|
|
|
|
.selection =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.description = "Sine",
|
|
|
|
|
.value = 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "Triangle",
|
|
|
|
|
.value = 1
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.default_int = 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "reverb",
|
|
|
|
|
.description = "Reverb",
|
|
|
|
|
.type = CONFIG_BINARY,
|
|
|
|
|
.default_int = 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "reverb_room_size",
|
|
|
|
|
.description = "Reverb Room Size",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 120
|
|
|
|
|
},
|
|
|
|
|
.default_int = 20
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "reverb_damping",
|
|
|
|
|
.description = "Reverb Damping",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 100
|
|
|
|
|
},
|
|
|
|
|
.default_int = 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "reverb_width",
|
|
|
|
|
.description = "Reverb Width",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 100
|
|
|
|
|
},
|
|
|
|
|
.default_int = 1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "reverb_level",
|
|
|
|
|
.description = "Reverb Level",
|
|
|
|
|
.type = CONFIG_SPINNER,
|
|
|
|
|
.spinner =
|
|
|
|
|
{
|
|
|
|
|
.min = 0,
|
|
|
|
|
.max = 100
|
|
|
|
|
},
|
|
|
|
|
.default_int = 90
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.name = "interpolation",
|
|
|
|
|
.description = "Interpolation Method",
|
|
|
|
|
.type = CONFIG_SELECTION,
|
|
|
|
|
.selection =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
.description = "None",
|
|
|
|
|
.value = 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "Linear",
|
|
|
|
|
.value = 1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "4th Order",
|
|
|
|
|
.value = 2
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.description = "7th Order",
|
|
|
|
|
.value = 3
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
.default_int = 2
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
.type = -1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
const device_t fluidsynth_device =
|
2017-08-07 22:59:44 +02:00
|
|
|
{
|
|
|
|
|
"FluidSynth",
|
|
|
|
|
0,
|
2017-10-07 16:45:54 +02:00
|
|
|
0,
|
2017-08-07 22:59:44 +02:00
|
|
|
fluidsynth_init,
|
|
|
|
|
fluidsynth_close,
|
2017-10-07 16:45:54 +02:00
|
|
|
NULL,
|
2017-08-07 22:59:44 +02:00
|
|
|
fluidsynth_available,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
fluidsynth_config
|
|
|
|
|
};
|
2017-08-08 22:51:47 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif /*USE_FLUIDSYNTH*/
|