Hi,

Attached is a test program for the sequencer interface of FluidSynth. There 
are two clones of the same idea: one of them plays a metronome pattern, and 
the other an arpeggio. In my tests, the rhythm & timing is fairly good, but 
maybe somebody can hack the test a bit to show the problems. And if so, also  
a patch to fix them, please :)

Regards,
Pedro
/*
    FluidSynth Sequencer simple arpeggio generator
    Copyright (C) 2009 Pedro Lopez-Cabanillas <p...@users.sf.net>

    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_arp -lfluidsynth fluid_arp.c
 */

#include <stdlib.h>
#include <stdio.h>
#include <fluidsynth.h>

fluid_synth_t* synth;
fluid_audio_driver_t* audiodriver;
fluid_sequencer_t* sequencer;
short synth_destination, client_destination;
unsigned int time_marker;
/* duration of the pattern in ticks. */
unsigned int duration = 1440;
/* notes of the arpeggio */
unsigned int notes[] = { 60, 64, 67, 72, 76, 79, 84, 79, 76, 72, 67, 64 };
/* number of notes in one pattern */
unsigned int pattern_size;
/* 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 note off message */
void schedule_noteoff(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_noteoff(ev, chan, key);
    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 arpeggio's notes */
void schedule_pattern()
{
    int i, note_time, note_duration;
    note_time = time_marker;
    note_duration = duration / pattern_size;
    for ( i = 0; i < pattern_size; ++i ) {
        schedule_noteon(0, notes[i], note_time);
        note_time += note_duration;
        schedule_noteoff(0, notes[i], note_time);
    }
    time_marker += duration;
}

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 [steps [duration]]\n", prog_name);
    printf("\t(optional) steps: number of pattern notes, from 2 to %d\n", pattern_size);
    printf("\t(optional) duration: of the pattern in ticks, default %d\n", duration);
}

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", 4096);
    pattern_size = sizeof(notes) / sizeof(int);
    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, "arpeggio", 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 > 1) && (n <= pattern_size))
                    pattern_size = n;
            }
            if (argc > 3) {
                n = atoi(argv[3]);
                if (n > 0) duration = 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 <Enter> 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;
}
/*
    FluidSynth Sequencer simple metronome
    Copyright (C) 2009 Pedro Lopez-Cabanillas <p...@users.sf.net>

    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 <stdlib.h>
#include <stdio.h>
#include <fluidsynth.h>

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 <Enter> 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;
}
_______________________________________________
fluid-dev mailing list
fluid-dev@nongnu.org
http://lists.nongnu.org/mailman/listinfo/fluid-dev

Reply via email to