Hi,

> I don't have
> time to write another test program version. Anyway, I don't see why
> fluid_synth_write_float() should impose any limit on the buffer size.

But I finally did, and attached is a third test. It uses libsndfile 
directly, so you need to link against it in addition to fluidsynth. 

Running the program with its default values produces wrong results. 
Executing the program with tempo >= 330 the results are correct (buffer size 
= 31928 frames) but with tempo <= 320 the output is wrong (buffer size = 
32986 frames). Looks like a signed short int variable is used somewhere with 
time calculations. By the way, there is also a constant SR = 44100 hanging 
around.

Regards,
Pedro
/* 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 <p...@users.sf.net>]
 */

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

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

Reply via email to