/*
FluidSynth Sequencer simple metronome
Copyright (C) 2009 Pedro Lopez-Cabanillas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Compilation:
$ gcc -o fluid_metro -lfluidsynth fluid_metro.c
*/
#include
#include
#include
fluid_synth_t* synth;
fluid_audio_driver_t* audiodriver;
fluid_sequencer_t* sequencer;
short synth_destination, client_destination;
unsigned int time_marker;
/* 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;
/* prototype */
void sequencer_callback(unsigned int time, fluid_event_t* event, fluid_sequencer_t* seq, void* data);
/* 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 a timer event (shall trigger the callback) */
void schedule_timer_event()
{
fluid_event_t *ev = new_fluid_event();
fluid_event_set_source(ev, -1);
fluid_event_set_dest(ev, client_destination);
fluid_event_timer(ev, NULL);
fluid_sequencer_send_at(sequencer, ev, time_marker, 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 sequencer_callback(unsigned int time, fluid_event_t* event, fluid_sequencer_t* seq, void* data)
{
schedule_timer_event();
schedule_pattern();
}
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: BMP (Beats Per Minute), default %d\n", TEMPO);
}
int main(int argc, char* argv[])
{
int n;
fluid_settings_t* settings;
settings = new_fluid_settings();
#ifdef __linux__
fluid_settings_setstr(settings, "audio.driver", "alsa");
#endif
fluid_settings_setnum(settings, "audio.period-size", 2048);
if (argc < 2) {
usage(argv[0]);
} else {
/* create the synth, driver and sequencer instances */
synth = new_fluid_synth(settings);
audiodriver = new_fluid_audio_driver(settings, synth);
sequencer = new_fluid_sequencer();
/* register the synth with the sequencer */
synth_destination = fluid_sequencer_register_fluidsynth(sequencer, synth);
/* register the client name and callback */
client_destination = fluid_sequencer_register_client(sequencer, "fluid_metro", sequencer_callback, NULL);
/* load a SoundFont */
n = fluid_synth_sfload(synth, argv[1], 1);
if ( n != -1 ) {
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;
}
/* get the current time in ticks */
time_marker = fluid_sequencer_get_tick(sequencer);
/* schedule patterns */
schedule_pattern();
schedule_timer_event();
schedule_pattern();
/* wait for user input */
printf("press to stop\n");
n = getchar();
}
/* clean and exit */
delete_fluid_sequencer(sequencer);
delete_fluid_audio_driver(audiodriver);
delete_fluid_synth(synth);
}
delete_fluid_settings(settings);
return 0;
}