libfluidsynth  2.4.5
Using the MIDI sequencer

FluidSynth's sequencer can be used to play MIDI events in a more flexible way than using the MIDI file player, which expects the events to be stored as Standard MIDI Files. Using the sequencer, you can provide the events one by one, with an optional timestamp for scheduling.

The client program should first initialize the sequencer instance using the function new_fluid_sequencer2(). There is a complementary function delete_fluid_sequencer() to delete it. After creating the sequencer instance, the destinations can be registered using fluid_sequencer_register_fluidsynth() for the synthesizer destination, and optionally using fluid_sequencer_register_client() for the client destination providing a suitable callback function. It can be unregistered using fluid_sequencer_unregister_client(). After the initialization, events can be sent with fluid_sequencer_send_now() and scheduled to the future with fluid_sequencer_send_at(). The registration functions return identifiers, that can be used as destinations of an event using fluid_event_set_dest().

The function fluid_sequencer_get_tick() returns the current playing position. A program may choose a new timescale in milliseconds using fluid_sequencer_set_time_scale().

The following example uses the fluidsynth sequencer to implement a sort of music box. FluidSynth internal clock is used to schedule repetitive sequences of notes. The next sequence is scheduled on advance before the end of the current one, using a timer event that triggers a callback function. The scheduling times are always absolute values, to avoid slippage.

#include "fluidsynth.h"
fluid_sequencer_t* sequencer;
short synthSeqID, mySeqID;
unsigned int now;
unsigned int seqduration;
// prototype
void seq_callback(unsigned int time, fluid_event_t* event, fluid_sequencer_t* seq, void* data);
void createsynth()
{
fluid_settings_t* settings;
settings = new_fluid_settings();
fluid_settings_setint(settings, "synth.reverb.active", 0);
fluid_settings_setint(settings, "synth.chorus.active", 0);
synth = new_fluid_synth(settings);
adriver = new_fluid_audio_driver(settings, synth);
sequencer = new_fluid_sequencer2(0);
// register synth as first destination
synthSeqID = fluid_sequencer_register_fluidsynth(sequencer, synth);
// register myself as second destination
mySeqID = fluid_sequencer_register_client(sequencer, "me", seq_callback, NULL);
// the sequence duration, in ms
seqduration = 1000;
}
void deletesynth()
{
}
void loadsoundfont()
{
int fluid_res;
// put your own path here
fluid_res = fluid_synth_sfload(synth, "Inside:VintageDreamsWaves-v2.sf2", 1);
}
void sendnoteon(int chan, short key, unsigned int date)
{
int fluid_res;
fluid_event_set_dest(evt, synthSeqID);
fluid_event_noteon(evt, chan, key, 127);
fluid_res = fluid_sequencer_send_at(sequencer, evt, date, 1);
}
void schedule_next_callback()
{
int fluid_res;
// I want to be called back before the end of the next sequence
unsigned int callbackdate = now + seqduration/2;
fluid_event_set_dest(evt, mySeqID);
fluid_event_timer(evt, NULL);
fluid_res = fluid_sequencer_send_at(sequencer, evt, callbackdate, 1);
}
void schedule_next_sequence() {
// Called more or less before each sequence start
// the next sequence start date
now = now + seqduration;
// the sequence to play
// the beat : 2 beats per sequence
sendnoteon(0, 60, now + seqduration/2);
sendnoteon(0, 60, now + seqduration);
// melody
sendnoteon(1, 45, now + seqduration/10);
sendnoteon(1, 50, now + 4*seqduration/10);
sendnoteon(1, 55, now + 8*seqduration/10);
// so that we are called back early enough to schedule the next sequence
schedule_next_callback();
}
/* sequencer callback */
void seq_callback(unsigned int time, fluid_event_t* event, fluid_sequencer_t* seq, void* data) {
schedule_next_sequence();
}
int main(void) {
createsynth();
loadsoundfont();
// initialize our absolute date
now = fluid_sequencer_get_tick(sequencer);
schedule_next_sequence();
sleep(100000);
deletesynth();
return 0;
}
struct _fluid_sequencer_t fluid_sequencer_t
Sequencer instance.
Definition: types.h:57
struct _fluid_hashtable_t fluid_settings_t
Configuration settings instance.
Definition: types.h:38
struct _fluid_audio_driver_t fluid_audio_driver_t
Audio driver instance.
Definition: types.h:46
struct _fluid_event_t fluid_event_t
Sequencer event.
Definition: types.h:56
struct _fluid_synth_t fluid_synth_t
Synthesizer instance.
Definition: types.h:39
fluid_audio_driver_t * new_fluid_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
Create a new audio driver.
Definition: fluid_adriver.c:350
void delete_fluid_audio_driver(fluid_audio_driver_t *driver)
Deletes an audio driver instance.
Definition: fluid_adriver.c:443
void fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src)
Set source of a sequencer event.
Definition: fluid_event.c:112
void fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest)
Set destination of this sequencer event, i.e.
Definition: fluid_event.c:123
void fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel)
Set a sequencer event to be a note on event.
Definition: fluid_event.c:150
fluid_event_t * new_fluid_event(void)
Create a new sequencer event structure.
Definition: fluid_event.c:59
void fluid_event_timer(fluid_event_t *evt, void *data)
Set a sequencer event to be a timer event.
Definition: fluid_event.c:134
void delete_fluid_event(fluid_event_t *evt)
Delete a sequencer event structure.
Definition: fluid_event.c:81
fluid_seq_id_t fluid_sequencer_register_client(fluid_sequencer_t *seq, const char *name, fluid_event_callback_t callback, void *data)
Register a sequencer client.
Definition: fluid_seq.c:210
fluid_sequencer_t * new_fluid_sequencer2(int use_system_timer)
Create a new sequencer object.
Definition: fluid_seq.c:113
int fluid_sequencer_send_at(fluid_sequencer_t *seq, fluid_event_t *evt, unsigned int time, int absolute)
Schedule an event for sending at a later time.
Definition: fluid_seq.c:476
fluid_seq_id_t fluid_sequencer_register_fluidsynth(fluid_sequencer_t *seq, fluid_synth_t *synth)
Registers a synthesizer as a destination client of the given sequencer.
Definition: fluid_seqbind.c:111
void delete_fluid_sequencer(fluid_sequencer_t *seq)
Free a sequencer object.
Definition: fluid_seq.c:157
unsigned int fluid_sequencer_get_tick(fluid_sequencer_t *seq)
Get the current tick of the sequencer scaled by the time scale currently set.
Definition: fluid_seq.c:547
fluid_settings_t * new_fluid_settings(void)
Create a new settings object.
Definition: fluid_settings.c:262
int fluid_settings_setint(fluid_settings_t *settings, const char *name, int val)
Set an integer value for a setting.
Definition: fluid_settings.c:1534
int fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets)
Load a SoundFont file (filename is interpreted by SoundFont loaders).
Definition: fluid_synth.c:5402
fluid_synth_t * new_fluid_synth(fluid_settings_t *settings)
Create new FluidSynth instance.
Definition: fluid_synth.c:645
void delete_fluid_synth(fluid_synth_t *synth)
Delete a FluidSynth instance.
Definition: fluid_synth.c:1044