Load fluidsynth entrypoints dynamically (and make them optional)

This removes the static dependency on fluidsynth being present
at buildtime (even headers aren't needed anymore).

Even though midi is a default format for the RPG XP/VX series,
it has fallen more and more out of use, with VX Ace completely
abandoning it from the RTP and making ogg vorbis the de facto
standard. Midi support is kept for legacy reasons, but isn't
encouraged. On top of all this, fluidsynth together with glib
is a heavy dependency that often times won't even be used.
Making it optional at build time is an attempt to unify and
keep build config fragmentation low.

In RGSS3, fluidsynth / midi is not initialized at all by
default, but rather on demand when either a midi track is
played back or Audio.setup_midi is called.
This commit is contained in:
Jonas Kulla 2014-09-07 05:23:10 +02:00
parent 673a25f811
commit 757a1d5e39
13 changed files with 223 additions and 120 deletions

View file

@ -61,9 +61,7 @@ ALDataSource *createSDLSource(SDL_RWops &ops,
ALDataSource *createVorbisSource(SDL_RWops &ops,
bool looped);
#ifdef MIDI
ALDataSource *createMidiSource(SDL_RWops &ops,
bool looped);
#endif
#endif // ALDATASOURCE_H

View file

@ -22,8 +22,10 @@
#include "alstream.h"
#include "sharedstate.h"
#include "sharedmidistate.h"
#include "filesystem.h"
#include "aldatasource.h"
#include "fluid-fun.h"
#include <SDL_mutex.h>
#include <SDL_thread.h>
@ -198,32 +200,26 @@ void ALStream::openSource(const std::string &filename)
shState->fileSystem().openRead(srcOps, filename.c_str(), FileSystem::Audio, false, &ext);
needsRewind = false;
bool readSig = rgssVer >= 2;
/* Try to read ogg file signature */
char sig[5] = { 0 };
SDL_RWread(&srcOps, sig, 1, 4);
SDL_RWseek(&srcOps, 0, RW_SEEK_SET);
#ifdef MIDI
readSig = true;
#endif
if (readSig)
if (!strcmp(sig, "OggS"))
{
/* Try to read ogg file signature */
char sig[5] = { 0 };
SDL_RWread(&srcOps, sig, 1, 4);
SDL_RWseek(&srcOps, 0, RW_SEEK_SET);
source = createVorbisSource(srcOps, looped);
return;
}
if (!strcmp(sig, "OggS"))
{
source = createVorbisSource(srcOps, looped);
return;
}
if (!strcmp(sig, "MThd"))
{
shState->midiState().initIfNeeded(shState->config());
#ifdef MIDI
if (!strcmp(sig, "MThd"))
if (HAVE_FLUID)
{
source = createMidiSource(srcOps, looped);
return;
}
#endif
}
source = createSDLSource(srcOps, ext, STREAM_BUF_SIZE, looped);

View file

@ -24,10 +24,7 @@
#include "audiostream.h"
#include "soundemitter.h"
#include "sharedstate.h"
#ifdef MIDI
#include "sharedmidistate.h"
#endif
#include <string>
@ -317,9 +314,7 @@ void Audio::seStop()
void Audio::setupMidi()
{
#ifdef MIDI
shState->midiState().initDefaultSynths();
#endif
shState->midiState().initIfNeeded(shState->config());
}
float Audio::bgmPos()

View file

@ -340,10 +340,8 @@ FileSystem::FileSystem(const char *argv0,
if (rgssVer >= 2 && !contains(p->extensions[Audio], std::string("ogg")))
p->extensions[Audio].push_back("ogg");
#if MIDI
p->extensions[Audio].push_back("mid");
p->extensions[Audio].push_back("midi");
#endif
/* Font extensions */
p->extensions[Font].push_back("ttf");

73
src/fluid-fun.cpp Normal file
View file

@ -0,0 +1,73 @@
#include "fluid-fun.h"
#include <string.h>
#include <SDL_loadso.h>
#include <SDL_platform.h>
#include "debugwriter.h"
#ifdef SHARED_FLUID
#include <fluidsynth.h>
#endif
#ifdef __LINUX__
#define FLUID_LIB "libfluidsynth.so.1"
#elif __MACOSX__
#define FLUID_LIB "libfluidsynth.dylib.1"
#elif __WINDOWS__
#define FLUID_LIB "fluidsynth.dll"
#else
#error "platform not recognized"
#endif
struct FluidFunctions fluid;
static void *so;
void initFluidFunctions()
{
#ifdef SHARED_FLUID
#define FLUID_FUN(name, type) \
fluid.name = fluid_##name;
#define FLUID_FUN2(name, type, real_name) \
fluid.name = real_name;
#else
so = SDL_LoadObject(FLUID_LIB);
if (!so)
goto fail;
#define FLUID_FUN(name, type) \
fluid.name = (type) SDL_LoadFunction(so, "fluid_" #name); \
if (!fluid.name) \
goto fail;
#define FLUID_FUN2(name, type, real_name) \
fluid.name = (type) SDL_LoadFunction(so, #real_name); \
if (!fluid.name) \
goto fail;
#endif
FLUID_FUNCS
FLUID_FUNCS2
return;
#ifndef SHARED_FLUID
fail:
Debug() << "Failed to load " FLUID_LIB ". Midi playback is disabled.";
memset(&fluid, 0, sizeof(fluid));
finiFluidFunctions();
#endif
}
void finiFluidFunctions()
{
#ifndef SHARED_FLUID
SDL_UnloadObject(so);
#endif
}

60
src/fluid-fun.h Normal file
View file

@ -0,0 +1,60 @@
#ifndef FLUIDFUN_H
#define FLUIDFUN_H
typedef struct _fluid_hashtable_t fluid_settings_t;
typedef struct _fluid_synth_t fluid_synth_t;
typedef fluid_settings_t* (*NEWFLUIDSETTINGSPROC)(void);
typedef int (*FLUIDSETTINGSSETNUMPROC)(fluid_settings_t* settings, const char *name, double val);
typedef int (*FLUIDSETTINGSSETSTRPROC)(fluid_settings_t* settings, const char *name, const char *str);
typedef void (*DELETEFLUIDSETTINGSPROC)(fluid_settings_t* settings);
typedef fluid_synth_t* (*NEWFLUIDSYNTHPROC)(fluid_settings_t* settings);
typedef int (*DELETEFLUIDSYNTHPROC)(fluid_synth_t* synth);
typedef int (*FLUIDSYNTHSFLOADPROC)(fluid_synth_t* synth, const char* filename, int reset_presets);
typedef int (*FLUIDSYNTHSYSTEMRESETPROC)(fluid_synth_t* synth);
typedef int (*FLUIDSYNTHWRITES16PROC)(fluid_synth_t* synth, int len, void* lout, int loff, int lincr, void* rout, int roff, int rincr);
typedef int (*FLUIDSYNTHNOTEONPROC)(fluid_synth_t* synth, int chan, int key, int vel);
typedef int (*FLUIDSYNTHNOTEOFFPROC)(fluid_synth_t* synth, int chan, int key);
typedef int (*FLUIDSYNTHCHANNELPRESSUREPROC)(fluid_synth_t* synth, int chan, int val);
typedef int (*FLUIDSYNTHPITCHBENDPROC)(fluid_synth_t* synth, int chan, int val);
typedef int (*FLUIDSYNTHCCPROC)(fluid_synth_t* synth, int chan, int ctrl, int val);
typedef int (*FLUIDSYNTHPROGRAMCHANGEPROC)(fluid_synth_t* synth, int chan, int program);
#define FLUID_FUNCS \
FLUID_FUN(settings_setnum, FLUIDSETTINGSSETNUMPROC) \
FLUID_FUN(settings_setstr, FLUIDSETTINGSSETSTRPROC) \
FLUID_FUN(synth_sfload, FLUIDSYNTHSFLOADPROC) \
FLUID_FUN(synth_system_reset, FLUIDSYNTHSYSTEMRESETPROC) \
FLUID_FUN(synth_write_s16, FLUIDSYNTHWRITES16PROC) \
FLUID_FUN(synth_noteon, FLUIDSYNTHNOTEONPROC) \
FLUID_FUN(synth_noteoff, FLUIDSYNTHNOTEOFFPROC) \
FLUID_FUN(synth_channel_pressure, FLUIDSYNTHCHANNELPRESSUREPROC) \
FLUID_FUN(synth_pitch_bend, FLUIDSYNTHPITCHBENDPROC) \
FLUID_FUN(synth_cc, FLUIDSYNTHCCPROC) \
FLUID_FUN(synth_program_change, FLUIDSYNTHPROGRAMCHANGEPROC)
/* Functions that don't fit into the default prefix naming scheme */
#define FLUID_FUNCS2 \
FLUID_FUN2(new_settings, NEWFLUIDSETTINGSPROC, new_fluid_settings) \
FLUID_FUN2(new_synth, NEWFLUIDSYNTHPROC, new_fluid_synth) \
FLUID_FUN2(delete_settings, DELETEFLUIDSETTINGSPROC, delete_fluid_settings) \
FLUID_FUN2(delete_synth, DELETEFLUIDSYNTHPROC, delete_fluid_synth)
struct FluidFunctions
{
#define FLUID_FUN(name, type) type name;
#define FLUID_FUN2(name, type, rn) type name;
FLUID_FUNCS
FLUID_FUNCS2
#undef FLUID_FUN
#undef FLUID_FUN2
};
#define HAVE_FLUID fluid.new_synth
extern FluidFunctions fluid;
void initFluidFunctions();
void finiFluidFunctions();
#endif // FLUIDFUN_H

View file

@ -27,8 +27,8 @@
#include "sharedmidistate.h"
#include "util.h"
#include "debugwriter.h"
#include "fluid-fun.h"
#include <fluidsynth.h>
#include <SDL_rwops.h>
#include <assert.h>
@ -648,22 +648,22 @@ struct MidiSource : ALDataSource, MidiReadHandler
switch (e.type)
{
case NoteOn:
fluid_synth_noteon(synth, e.e.note.chan, key, e.e.note.vel);
fluid.synth_noteon(synth, e.e.note.chan, key, e.e.note.vel);
break;
case NoteOff:
fluid_synth_noteoff(synth, e.e.note.chan, key);
fluid.synth_noteoff(synth, e.e.note.chan, key);
break;
case ChanTouch:
fluid_synth_channel_pressure(synth, e.e.chanTouch.chan, e.e.chanTouch.val);
fluid.synth_channel_pressure(synth, e.e.chanTouch.chan, e.e.chanTouch.val);
break;
case PitchBend:
fluid_synth_pitch_bend(synth, e.e.pitchBend.chan, e.e.pitchBend.val);
fluid.synth_pitch_bend(synth, e.e.pitchBend.chan, e.e.pitchBend.val);
break;
case CC:
fluid_synth_cc(synth, e.e.cc.chan, e.e.cc.ctrl, e.e.cc.val);
fluid.synth_cc(synth, e.e.cc.chan, e.e.cc.ctrl, e.e.cc.val);
break;
case PC:
fluid_synth_program_change(synth, e.e.pc.chan, e.e.pc.prog);
fluid.synth_program_change(synth, e.e.pc.chan, e.e.pc.prog);
break;
case Tempo:
updatePlaybackSpeed(e.e.tempo.bpm);
@ -679,7 +679,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
int len = count * TICK_FRAMES;
void *buffer = &synthBuf[bufOffset];
fluid_synth_write_s16(synth, len, buffer, 0, 2, buffer, 1, 2);
fluid.synth_write_s16(synth, len, buffer, 0, 2, buffer, 1, 2);
}
/* MidiReadHandler */
@ -817,7 +817,7 @@ struct MidiSource : ALDataSource, MidiReadHandler
void seekToOffset(float)
{
/* Reset synth */
fluid_synth_system_reset(synth);
fluid.synth_system_reset(synth);
/* Reset runtime variables */
genDeltasCarry = 0;

View file

@ -24,8 +24,7 @@
#include "config.h"
#include "debugwriter.h"
#include <fluidsynth.h>
#include "fluid-fun.h"
#include <assert.h>
#include <vector>
@ -50,58 +49,52 @@ struct SharedMidiState
SharedMidiState(const Config &conf)
: inited(false),
soundFont(conf.midi.soundFont)
{
flSettings = new_fluid_settings();
fluid_settings_setnum(flSettings, "synth.gain", 1.0);
fluid_settings_setnum(flSettings, "synth.sample-rate", SYNTH_SAMPLERATE);
fluid_settings_setstr(flSettings, "synth.chorus.active", conf.midi.chorus ? "yes" : "no");
fluid_settings_setstr(flSettings, "synth.reverb.active", conf.midi.reverb ? "yes" : "no");
}
{}
~SharedMidiState()
{
delete_fluid_settings(flSettings);
if (!HAVE_FLUID || !inited)
return;
fluid.delete_settings(flSettings);
for (size_t i = 0; i < synths.size(); ++i)
{
assert(!synths[i].inUse);
delete_fluid_synth(synths[i].synth);
fluid.delete_synth(synths[i].synth);
}
finiFluidFunctions();
}
fluid_synth_t *addSynth(bool usedNow)
{
fluid_synth_t *syn = new_fluid_synth(flSettings);
if (!soundFont.empty())
fluid_synth_sfload(syn, soundFont.c_str(), 1);
else
Debug() << "Warning: No soundfont specified, sound might be mute";
Synth synth;
synth.inUse = usedNow;
synth.synth = syn;
synths.push_back(synth);
return syn;
}
void initDefaultSynths()
void initIfNeeded(const Config &conf)
{
if (inited)
return;
inited = true;
initFluidFunctions();
if (!HAVE_FLUID)
return;
flSettings = fluid.new_settings();
fluid.settings_setnum(flSettings, "synth.gain", 1.0);
fluid.settings_setnum(flSettings, "synth.sample-rate", SYNTH_SAMPLERATE);
fluid.settings_setstr(flSettings, "synth.chorus.active", conf.midi.chorus ? "yes" : "no");
fluid.settings_setstr(flSettings, "synth.reverb.active", conf.midi.reverb ? "yes" : "no");
for (size_t i = 0; i < SYNTH_INIT_COUNT; ++i)
addSynth(false);
inited = true;
}
fluid_synth_t *allocateSynth()
{
size_t i;
assert(HAVE_FLUID);
assert(inited);
initDefaultSynths();
size_t i;
for (i = 0; i < synths.size(); ++i)
if (!synths[i].inUse)
@ -110,7 +103,7 @@ struct SharedMidiState
if (i < synths.size())
{
fluid_synth_t *syn = synths[i].synth;
fluid_synth_system_reset(syn);
fluid.synth_system_reset(syn);
synths[i].inUse = true;
return syn;
@ -133,6 +126,24 @@ struct SharedMidiState
synths[i].inUse = false;
}
private:
fluid_synth_t *addSynth(bool usedNow)
{
fluid_synth_t *syn = fluid.new_synth(flSettings);
if (!soundFont.empty())
fluid.synth_sfload(syn, soundFont.c_str(), 1);
else
Debug() << "Warning: No soundfont specified, sound might be mute";
Synth synth;
synth.inUse = usedNow;
synth.synth = syn;
synths.push_back(synth);
return syn;
}
};
#endif // SHAREDMIDISTATE_H

View file

@ -36,10 +36,7 @@
#include "quad.h"
#include "binding.h"
#include "exception.h"
#ifdef MIDI
#include "sharedmidistate.h"
#endif
#include <unistd.h>
#include <stdio.h>
@ -74,9 +71,7 @@ struct SharedStatePrivate
RGSSThreadData &rtData;
Config &config;
#ifdef MIDI
SharedMidiState midiState;
#endif
Graphics graphics;
Input input;
@ -109,9 +104,7 @@ struct SharedStatePrivate
eThread(*threadData->ethread),
rtData(*threadData),
config(threadData->config),
#ifdef MIDI
midiState(threadData->config),
#endif
graphics(threadData),
audio(threadData->config),
fontState(threadData->config),
@ -164,10 +157,8 @@ struct SharedStatePrivate
/* RGSS3 games will call setup_midi, so there's
* no need to do it on startup */
#if MIDI
if (rgssVer <= 2)
midiState.initDefaultSynths();
#endif
midiState.initIfNeeded(threadData->config);
}
~SharedStatePrivate()
@ -245,10 +236,7 @@ GSATT(ShaderSet&, shaders)
GSATT(TexPool&, texPool)
GSATT(Quad&, gpQuad)
GSATT(SharedFontState&, fontState)
#ifdef MIDI
GSATT(SharedMidiState&, midiState)
#endif
void SharedState::setBindingData(void *data)
{

View file

@ -49,10 +49,7 @@ class SharedFontState;
struct GlobalIBO;
struct Config;
struct Vec2i;
#ifdef MIDI
struct SharedMidiState;
#endif
struct SharedState
{
@ -83,9 +80,7 @@ struct SharedState
SharedFontState &fontState() const;
Font &defaultFont() const;
#ifdef MIDI
SharedMidiState &midiState() const;
#endif
sigc::signal<void> prepareDraw;