/* FluidSynth Metronome - Sequencer API example
*
* This code is in the public domain.
*
* To compile:
* gcc -o rendermetronome2 -lfluidsynth rendermetronome2.c
*
* To run:
* rendermetronome2 soundfont [beats [tempo]]
*
* [Pedro Lopez-Cabanillas
]
*/
#include
#include
#include
fluid_synth_t *synth;
fluid_sequencer_t *sequencer;
short synth_destination;
unsigned int time_marker;
unsigned int sample_rate = 48000;
/* default tempo, beats per minute */
#define TEMPO 120
unsigned int note_duration = 60000 / TEMPO;
/* metronome click/bell */
unsigned int weak_note = 33;
unsigned int strong_note = 34;
/* number of notes in one pattern */
unsigned int pattern_size = 4;
/* total sequence length in bars */
unsigned int pending_bars = 10;
/* number of audio buffers for each bar */
unsigned int periods_per_bar = 20;
/* schedule a note on message */
void
schedule_noteon (int chan, short key, unsigned int ticks)
{
fluid_event_t *ev = new_fluid_event ();
fluid_event_set_source (ev, -1);
fluid_event_set_dest (ev, synth_destination);
fluid_event_noteon (ev, chan, key, 127);
fluid_sequencer_send_at (sequencer, ev, ticks, 1);
delete_fluid_event (ev);
}
/* schedule the metronome pattern */
void
schedule_pattern ()
{
int i, note_time;
note_time = time_marker;
for (i = 0; i < pattern_size; ++i) {
schedule_noteon (9, i ? weak_note : strong_note, note_time);
note_time += note_duration;
}
time_marker = note_time;
}
void
usage (char* prog_name)
{
printf ("Usage: %s soundfont.sf2 [beats [tempo]]\n", prog_name);
printf ("\t(optional) beats: number of pattern beats, default %d\n",
pattern_size);
printf ("\t(optional) tempo: BPM (Beats Per Minute), default %d\n", TEMPO);
}
int
main (int argc, char *argv[])
{
int i, n;
int total_bar_size, period_size;
fluid_settings_t *settings;
fluid_file_renderer_t* renderer;
if (argc < 2) {
usage (argv[0]);
} else {
if (argc > 2) {
n = atoi (argv[2]);
if (n > 0) pattern_size = n;
}
if (argc > 3) {
n = atoi (argv[3]);
if (n > 0) note_duration = 60000 / n;
}
/* total bar size in frames */
total_bar_size = note_duration * pattern_size * sample_rate / 1000;
/* audio period size. Max is 8192 */
period_size = total_bar_size / periods_per_bar;
if (period_size > 8192) {
printf ("Sorry, max. period size exceeded\n");
return;
}
settings = new_fluid_settings ();
fluid_settings_setstr(settings, "audio.file.name", "rendermetronome2.wav");
fluid_settings_setint(settings, "audio.period-size", period_size);
fluid_settings_setnum(settings, "synth.gain", 2.0);
fluid_settings_setnum(settings, "synth.sample-rate", sample_rate);
/* create the synth and sequencer instances */
synth = new_fluid_synth (settings);
sequencer = new_fluid_sequencer2 (0);
/* register the synth with the sequencer */
synth_destination = fluid_sequencer_register_fluidsynth (sequencer, synth);
/* load a SoundFont */
n = fluid_synth_sfload (synth, argv[1], 1);
if (n != -1) {
renderer = new_fluid_file_renderer (synth);
if (!renderer)
return;
/* get the current time in ticks */
time_marker = fluid_sequencer_get_tick (sequencer);
/* schedule and render patterns */
for (n = 0; n < pending_bars; ++n) {
schedule_pattern ();
for (i = 0; i < periods_per_bar; ++i) {
if (fluid_file_renderer_process_block (renderer) != FLUID_OK) {
break;
}
}
}
delete_fluid_file_renderer (renderer);
}
/* clean and exit */
delete_fluid_sequencer (sequencer);
delete_fluid_synth (synth);
delete_fluid_settings (settings);
}
return 0;
}