Browse Source

Fixes for fluidsynth >= 2.0.0 (#766)

* Fluidsynths: Ensure fluidsynth's defaults are set once and in one place

This makes transition fluidsynth 1.x -> 2.x a lot easier.

Signed-off-by: Andreas Müller <schnitzeltony@gmail.com>

* Enable support for fluidsynth >= 2.0.0

This reverts commit e67ba7c25b.

* Fixes for fluidsynth >= 2.0.0

* preset iteration and getters have changed
* constants for most defaults are no more available in public headers -
  fluidsynth wants to be asked

Signed-off-by: Andreas Müller <schnitzeltony@gmail.com>
tags/v2.1-alpha1-winvst
Andreas Müller Filipe Coelho <falktx@falktx.com> 6 years ago
parent
commit
fb410954dc
3 changed files with 116 additions and 20 deletions
  1. +1
    -1
      source/Makefile.mk
  2. +110
    -19
      source/backend/plugin/CarlaPluginFluidSynth.cpp
  3. +5
    -0
      source/discovery/carla-discovery.cpp

+ 1
- 1
source/Makefile.mk View File

@@ -223,7 +223,7 @@ endif
endif endif


HAVE_FFMPEG = $(shell pkg-config --exists libavcodec libavformat libavutil && echo true) HAVE_FFMPEG = $(shell pkg-config --exists libavcodec libavformat libavutil && echo true)
HAVE_FLUIDSYNTH = $(shell pkg-config --atleast-version=1.1.7 fluidsynth && pkg-config --max-version=1.9.9 fluidsynth && echo true)
HAVE_FLUIDSYNTH = $(shell pkg-config --atleast-version=1.1.7 fluidsynth && echo true)
HAVE_LIBLO = $(shell pkg-config --exists liblo && echo true) HAVE_LIBLO = $(shell pkg-config --exists liblo && echo true)
HAVE_QT4 = $(shell pkg-config --exists QtCore QtGui && echo true) HAVE_QT4 = $(shell pkg-config --exists QtCore QtGui && echo true)
HAVE_QT5 = $(shell pkg-config --exists Qt5Core Qt5Gui Qt5Widgets && echo true) HAVE_QT5 = $(shell pkg-config --exists Qt5Core Qt5Gui Qt5Widgets && echo true)


+ 110
- 19
source/backend/plugin/CarlaPluginFluidSynth.cpp View File

@@ -73,20 +73,22 @@ public:
fSynth = new_fluid_synth(fSettings); fSynth = new_fluid_synth(fSettings);
CARLA_SAFE_ASSERT_RETURN(fSynth != nullptr,); CARLA_SAFE_ASSERT_RETURN(fSynth != nullptr,);


initializeFluidDefaultsIfNeeded();

fluid_synth_set_sample_rate(fSynth, (float)pData->engine->getSampleRate()); fluid_synth_set_sample_rate(fSynth, (float)pData->engine->getSampleRate());


// set default values // set default values
fluid_synth_set_reverb_on(fSynth, 1); fluid_synth_set_reverb_on(fSynth, 1);
fluid_synth_set_reverb(fSynth, FLUID_REVERB_DEFAULT_ROOMSIZE, FLUID_REVERB_DEFAULT_DAMP, FLUID_REVERB_DEFAULT_WIDTH, FLUID_REVERB_DEFAULT_LEVEL);
fluid_synth_set_reverb(fSynth, sFluidDefaults[FluidSynthReverbRoomSize], sFluidDefaults[FluidSynthReverbDamp], sFluidDefaults[FluidSynthReverbWidth], sFluidDefaults[FluidSynthReverbLevel]);


fluid_synth_set_chorus_on(fSynth, 1); fluid_synth_set_chorus_on(fSynth, 1);
fluid_synth_set_chorus(fSynth, FLUID_CHORUS_DEFAULT_N, FLUID_CHORUS_DEFAULT_LEVEL, FLUID_CHORUS_DEFAULT_SPEED, FLUID_CHORUS_DEFAULT_DEPTH, FLUID_CHORUS_DEFAULT_TYPE);
fluid_synth_set_chorus(fSynth, sFluidDefaults[FluidSynthChorusNr], sFluidDefaults[FluidSynthChorusLevel], sFluidDefaults[FluidSynthChorusSpeedHz], sFluidDefaults[FluidSynthChorusDepthMs], sFluidDefaults[FluidSynthChorusType]);


fluid_synth_set_polyphony(fSynth, FLUID_DEFAULT_POLYPHONY); fluid_synth_set_polyphony(fSynth, FLUID_DEFAULT_POLYPHONY);
fluid_synth_set_gain(fSynth, 1.0f); fluid_synth_set_gain(fSynth, 1.0f);


for (int i=0; i < MAX_MIDI_CHANNELS; ++i) for (int i=0; i < MAX_MIDI_CHANNELS; ++i)
fluid_synth_set_interp_method(fSynth, i, FLUID_INTERP_DEFAULT);
fluid_synth_set_interp_method(fSynth, i, sFluidDefaults[FluidSynthInterpolation]);
} }


~CarlaPluginFluidSynth() override ~CarlaPluginFluidSynth() override
@@ -195,7 +197,7 @@ public:
case 1: case 1:
return FLUID_CHORUS_MOD_TRIANGLE; return FLUID_CHORUS_MOD_TRIANGLE;
default: default:
return FLUID_CHORUS_DEFAULT_TYPE;
return sFluidDefaults[FluidSynthChorusType];
} }
case FluidSynthInterpolation: case FluidSynthInterpolation:
switch (scalePointId) switch (scalePointId)
@@ -209,7 +211,7 @@ public:
case 3: case 3:
return FLUID_INTERP_7THORDER; return FLUID_INTERP_7THORDER;
default: default:
return FLUID_INTERP_DEFAULT;
return sFluidDefaults[FluidSynthInterpolation];
} }
default: default:
return 0.0f; return 0.0f;
@@ -721,7 +723,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 1.0f; pData->param.ranges[j].max = 1.0f;
pData->param.ranges[j].def = 1.0f;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 1.0f; pData->param.ranges[j].step = 1.0f;
pData->param.ranges[j].stepSmall = 1.0f; pData->param.ranges[j].stepSmall = 1.0f;
pData->param.ranges[j].stepLarge = 1.0f; pData->param.ranges[j].stepLarge = 1.0f;
@@ -734,7 +736,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 1.2f; pData->param.ranges[j].max = 1.2f;
pData->param.ranges[j].def = FLUID_REVERB_DEFAULT_ROOMSIZE;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 0.01f; pData->param.ranges[j].step = 0.01f;
pData->param.ranges[j].stepSmall = 0.0001f; pData->param.ranges[j].stepSmall = 0.0001f;
pData->param.ranges[j].stepLarge = 0.1f; pData->param.ranges[j].stepLarge = 0.1f;
@@ -747,7 +749,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 1.0f; pData->param.ranges[j].max = 1.0f;
pData->param.ranges[j].def = FLUID_REVERB_DEFAULT_DAMP;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 0.01f; pData->param.ranges[j].step = 0.01f;
pData->param.ranges[j].stepSmall = 0.0001f; pData->param.ranges[j].stepSmall = 0.0001f;
pData->param.ranges[j].stepLarge = 0.1f; pData->param.ranges[j].stepLarge = 0.1f;
@@ -761,7 +763,7 @@ public:
pData->param.data[j].midiCC = MIDI_CONTROL_REVERB_SEND_LEVEL; pData->param.data[j].midiCC = MIDI_CONTROL_REVERB_SEND_LEVEL;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 1.0f; pData->param.ranges[j].max = 1.0f;
pData->param.ranges[j].def = FLUID_REVERB_DEFAULT_LEVEL;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 0.01f; pData->param.ranges[j].step = 0.01f;
pData->param.ranges[j].stepSmall = 0.0001f; pData->param.ranges[j].stepSmall = 0.0001f;
pData->param.ranges[j].stepLarge = 0.1f; pData->param.ranges[j].stepLarge = 0.1f;
@@ -774,7 +776,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 10.0f; // should be 100, but that sounds too much pData->param.ranges[j].max = 10.0f; // should be 100, but that sounds too much
pData->param.ranges[j].def = FLUID_REVERB_DEFAULT_WIDTH;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 0.01f; pData->param.ranges[j].step = 0.01f;
pData->param.ranges[j].stepSmall = 0.0001f; pData->param.ranges[j].stepSmall = 0.0001f;
pData->param.ranges[j].stepLarge = 0.1f; pData->param.ranges[j].stepLarge = 0.1f;
@@ -787,7 +789,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 1.0f; pData->param.ranges[j].max = 1.0f;
pData->param.ranges[j].def = 1.0f;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 1.0f; pData->param.ranges[j].step = 1.0f;
pData->param.ranges[j].stepSmall = 1.0f; pData->param.ranges[j].stepSmall = 1.0f;
pData->param.ranges[j].stepLarge = 1.0f; pData->param.ranges[j].stepLarge = 1.0f;
@@ -800,7 +802,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 99.0f; pData->param.ranges[j].max = 99.0f;
pData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_N;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 1.0f; pData->param.ranges[j].step = 1.0f;
pData->param.ranges[j].stepSmall = 1.0f; pData->param.ranges[j].stepSmall = 1.0f;
pData->param.ranges[j].stepLarge = 10.0f; pData->param.ranges[j].stepLarge = 10.0f;
@@ -813,7 +815,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 10.0f; pData->param.ranges[j].max = 10.0f;
pData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_LEVEL;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 0.01f; pData->param.ranges[j].step = 0.01f;
pData->param.ranges[j].stepSmall = 0.0001f; pData->param.ranges[j].stepSmall = 0.0001f;
pData->param.ranges[j].stepLarge = 0.1f; pData->param.ranges[j].stepLarge = 0.1f;
@@ -826,7 +828,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.29f; pData->param.ranges[j].min = 0.29f;
pData->param.ranges[j].max = 5.0f; pData->param.ranges[j].max = 5.0f;
pData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_SPEED;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 0.01f; pData->param.ranges[j].step = 0.01f;
pData->param.ranges[j].stepSmall = 0.0001f; pData->param.ranges[j].stepSmall = 0.0001f;
pData->param.ranges[j].stepLarge = 0.1f; pData->param.ranges[j].stepLarge = 0.1f;
@@ -839,7 +841,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = float(2048.0 * 1000.0 / pData->engine->getSampleRate()); // FIXME? pData->param.ranges[j].max = float(2048.0 * 1000.0 / pData->engine->getSampleRate()); // FIXME?
pData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_DEPTH;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 0.01f; pData->param.ranges[j].step = 0.01f;
pData->param.ranges[j].stepSmall = 0.0001f; pData->param.ranges[j].stepSmall = 0.0001f;
pData->param.ranges[j].stepLarge = 0.1f; pData->param.ranges[j].stepLarge = 0.1f;
@@ -852,7 +854,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = FLUID_CHORUS_MOD_SINE; pData->param.ranges[j].min = FLUID_CHORUS_MOD_SINE;
pData->param.ranges[j].max = FLUID_CHORUS_MOD_TRIANGLE; pData->param.ranges[j].max = FLUID_CHORUS_MOD_TRIANGLE;
pData->param.ranges[j].def = FLUID_CHORUS_DEFAULT_TYPE;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 1.0f; pData->param.ranges[j].step = 1.0f;
pData->param.ranges[j].stepSmall = 1.0f; pData->param.ranges[j].stepSmall = 1.0f;
pData->param.ranges[j].stepLarge = 1.0f; pData->param.ranges[j].stepLarge = 1.0f;
@@ -865,7 +867,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 1.0f; pData->param.ranges[j].min = 1.0f;
pData->param.ranges[j].max = 512.0f; // max theoric is 65535 pData->param.ranges[j].max = 512.0f; // max theoric is 65535
pData->param.ranges[j].def = (float)fluid_synth_get_polyphony(fSynth);
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 1.0f; pData->param.ranges[j].step = 1.0f;
pData->param.ranges[j].stepSmall = 1.0f; pData->param.ranges[j].stepSmall = 1.0f;
pData->param.ranges[j].stepLarge = 10.0f; pData->param.ranges[j].stepLarge = 10.0f;
@@ -878,7 +880,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = FLUID_INTERP_NONE; pData->param.ranges[j].min = FLUID_INTERP_NONE;
pData->param.ranges[j].max = FLUID_INTERP_HIGHEST; pData->param.ranges[j].max = FLUID_INTERP_HIGHEST;
pData->param.ranges[j].def = FLUID_INTERP_DEFAULT;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 1.0f; pData->param.ranges[j].step = 1.0f;
pData->param.ranges[j].stepSmall = 1.0f; pData->param.ranges[j].stepSmall = 1.0f;
pData->param.ranges[j].stepLarge = 1.0f; pData->param.ranges[j].stepLarge = 1.0f;
@@ -891,7 +893,7 @@ public:
pData->param.data[j].rindex = j; pData->param.data[j].rindex = j;
pData->param.ranges[j].min = 0.0f; pData->param.ranges[j].min = 0.0f;
pData->param.ranges[j].max = 65535.0f; pData->param.ranges[j].max = 65535.0f;
pData->param.ranges[j].def = 0.0f;
pData->param.ranges[j].def = sFluidDefaults[j];
pData->param.ranges[j].step = 1.0f; pData->param.ranges[j].step = 1.0f;
pData->param.ranges[j].stepSmall = 1.0f; pData->param.ranges[j].stepSmall = 1.0f;
pData->param.ranges[j].stepLarge = 1.0f; pData->param.ranges[j].stepLarge = 1.0f;
@@ -941,6 +943,7 @@ public:


if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(fSynth, fSynthId)) if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(fSynth, fSynthId))
{ {
#if FLUIDSYNTH_VERSION_MAJOR < 2
fluid_preset_t f_preset; fluid_preset_t f_preset;


// initial check to know how many midi-programs we have // initial check to know how many midi-programs we have
@@ -969,6 +972,36 @@ public:
pData->midiprog.data[i].program = (tmp >= 0) ? static_cast<uint32_t>(tmp) : 0; pData->midiprog.data[i].program = (tmp >= 0) ? static_cast<uint32_t>(tmp) : 0;


pData->midiprog.data[i].name = carla_strdup(f_preset.get_name(&f_preset)); pData->midiprog.data[i].name = carla_strdup(f_preset.get_name(&f_preset));
#else
fluid_preset_t* f_preset;

// initial check to know how many midi-programs we have
fluid_sfont_iteration_start(f_sfont);
for (; fluid_sfont_iteration_next(f_sfont);)
++count;

// sound kits must always have at least 1 midi-program
CARLA_SAFE_ASSERT_RETURN(count > 0,);

pData->midiprog.createNew(count);

// Update data
int tmp;
uint32_t i = 0;
fluid_sfont_iteration_start(f_sfont);

for (; (f_preset = fluid_sfont_iteration_next(f_sfont));)
{
CARLA_SAFE_ASSERT_BREAK(i < count);

tmp = fluid_preset_get_banknum(f_preset);
pData->midiprog.data[i].bank = (tmp >= 0) ? static_cast<uint32_t>(tmp) : 0;

tmp = fluid_preset_get_num(f_preset);
pData->midiprog.data[i].program = (tmp >= 0) ? static_cast<uint32_t>(tmp) : 0;

pData->midiprog.data[i].name = carla_strdup(fluid_preset_get_name(f_preset));
#endif


if (pData->midiprog.data[i].bank == 128 && ! hasDrums) if (pData->midiprog.data[i].bank == 128 && ! hasDrums)
{ {
@@ -1656,6 +1689,58 @@ public:
} }


private: private:
void initializeFluidDefaultsIfNeeded()
{
if (sFluidDefaultsStored)
return;
sFluidDefaultsStored = true;
// reverb defaults
sFluidDefaults[FluidSynthReverbOnOff] = 1.0f;
#if FLUIDSYNTH_VERSION_MAJOR < 2
sFluidDefaults[FluidSynthReverbRoomSize] = FLUID_REVERB_DEFAULT_ROOMSIZE;
sFluidDefaults[FluidSynthReverbDamp] = FLUID_REVERB_DEFAULT_DAMP;
sFluidDefaults[FluidSynthReverbLevel] = FLUID_REVERB_DEFAULT_LEVEL;
sFluidDefaults[FluidSynthReverbWidth] = FLUID_REVERB_DEFAULT_WIDTH;
#else
double reverbVal;
fluid_settings_getnum_default(fSettings, "synth.reverb.room-size", &reverbVal);
sFluidDefaults[FluidSynthReverbRoomSize] = reverbVal;
fluid_settings_getnum_default(fSettings, "synth.reverb.damp", &reverbVal);
sFluidDefaults[FluidSynthReverbDamp] = reverbVal;
fluid_settings_getnum_default(fSettings, "synth.reverb.level", &reverbVal);
sFluidDefaults[FluidSynthReverbLevel] = reverbVal;
fluid_settings_getnum_default(fSettings, "synth.reverb.width", &reverbVal);
sFluidDefaults[FluidSynthReverbWidth] = reverbVal;
#endif

// chorus defaults
sFluidDefaults[FluidSynthChorusOnOff] = 1.0f;
#if FLUIDSYNTH_VERSION_MAJOR < 2
sFluidDefaults[FluidSynthChorusNr] = FLUID_CHORUS_DEFAULT_N;
sFluidDefaults[FluidSynthChorusLevel] = FLUID_CHORUS_DEFAULT_LEVEL;
sFluidDefaults[FluidSynthChorusSpeedHz] = FLUID_CHORUS_DEFAULT_SPEED;
sFluidDefaults[FluidSynthChorusDepthMs] = FLUID_CHORUS_DEFAULT_DEPTH;
sFluidDefaults[FluidSynthChorusType] = FLUID_CHORUS_DEFAULT_TYPE;
#else
double chorusVal;
fluid_settings_getnum_default(fSettings, "synth.chorus.nr", &chorusVal);
sFluidDefaults[FluidSynthChorusNr] = chorusVal;
fluid_settings_getnum_default(fSettings, "synth.chorus.level", &chorusVal);
sFluidDefaults[FluidSynthChorusLevel] = chorusVal;
fluid_settings_getnum_default(fSettings, "synth.chorus.speed", &chorusVal);
sFluidDefaults[FluidSynthChorusSpeedHz] = chorusVal;
fluid_settings_getnum_default(fSettings, "synth.chorus.depth", &chorusVal);
sFluidDefaults[FluidSynthChorusDepthMs] = chorusVal;
// There is no settings for chorus default type
sFluidDefaults[FluidSynthChorusType] = (float)fluid_synth_get_chorus_type(fSynth);
#endif

// misc. defaults
sFluidDefaults[FluidSynthPolyphony] = (float)fluid_synth_get_polyphony(fSynth);
sFluidDefaults[FluidSynthInterpolation] = FLUID_INTERP_DEFAULT;
sFluidDefaults[FluidSynthVoiceCount] = 0.0f;
}

enum FluidSynthParameters { enum FluidSynthParameters {
FluidSynthReverbOnOff = 0, FluidSynthReverbOnOff = 0,
FluidSynthReverbRoomSize = 1, FluidSynthReverbRoomSize = 1,
@@ -1683,6 +1768,9 @@ private:
float** fAudio16Buffers; float** fAudio16Buffers;
float fParamBuffers[FluidSynthParametersMax]; float fParamBuffers[FluidSynthParametersMax];


static bool sFluidDefaultsStored;
static float sFluidDefaults[FluidSynthParametersMax];

int32_t fCurMidiProgs[MAX_MIDI_CHANNELS]; int32_t fCurMidiProgs[MAX_MIDI_CHANNELS];


const char* fLabel; const char* fLabel;
@@ -1690,6 +1778,9 @@ private:
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginFluidSynth) CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginFluidSynth)
}; };


bool CarlaPluginFluidSynth::sFluidDefaultsStored = false;
float CarlaPluginFluidSynth::sFluidDefaults[FluidSynthParametersMax];

CARLA_BACKEND_END_NAMESPACE CARLA_BACKEND_END_NAMESPACE


#endif // HAVE_FLUIDSYNTH #endif // HAVE_FLUIDSYNTH


+ 5
- 0
source/discovery/carla-discovery.cpp View File

@@ -1323,10 +1323,15 @@ static void do_fluidsynth_check(const char* const filename, const bool doInit)


if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(f_synth, static_cast<uint>(f_id))) if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(f_synth, static_cast<uint>(f_id)))
{ {
#if FLUIDSYNTH_VERSION_MAJOR < 2
fluid_preset_t f_preset; fluid_preset_t f_preset;


f_sfont->iteration_start(f_sfont); f_sfont->iteration_start(f_sfont);
for (; f_sfont->iteration_next(f_sfont, &f_preset);) for (; f_sfont->iteration_next(f_sfont, &f_preset);)
#else
fluid_sfont_iteration_start(f_sfont);
for (; fluid_sfont_iteration_next(f_sfont);)
#endif
++programs; ++programs;
} }




Loading…
Cancel
Save