/* FluidSynth Metronome - Sequencer API example * * This code is in the public domain. * * To compile: * gcc -o rendermetronome3 -lfluidsynth -lsndfile rendermetronome3.c * * To run: * rendermetronome3 soundfont [beats [tempo]] * * [Pedro Lopez-Cabanillas ] */ #include #include #include #include #include fluid_synth_t *synth; fluid_sequencer_t *sequencer; short synth_destination; unsigned int time_marker; unsigned int sample_rate = 44100; /* 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; /* schedule a note on message */ void schedule_noteon (int chan, short key, unsigned int ticks) { printf("metronome: noteon %d at %u\n", key, 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; SNDFILE* sndfile; SF_INFO info; size_t buf_size; float* buf; 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; buf_size = 2 * total_bar_size * sizeof (float); printf ("metronome: buffer size = %d frames\n", total_bar_size); memset (&info, 0, sizeof (info)); info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; info.samplerate = sample_rate * 1.0; info.channels = 2; settings = new_fluid_settings (); fluid_settings_setnum(settings, "synth.gain", 2.0); fluid_settings_setnum(settings, "synth.sample-rate", sample_rate); fluid_settings_setint(settings, "synth.verbose", 1); /* 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) { buf = malloc(buf_size); sndfile = sf_open ("rendermetronome3.wav", SFM_WRITE, &info); sf_command (sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE); sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE); /* 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 (); fluid_synth_write_float (synth, total_bar_size, buf, 0, 2, buf, 1, 2); sf_writef_float (sndfile, buf, total_bar_size); } sf_close(sndfile); free(buf); } /* clean and exit */ delete_fluid_sequencer (sequencer); delete_fluid_synth (synth); delete_fluid_settings (settings); } return 0; }