jazz-soft / JZZ-synth-Fluid

A JZZ wrapper for FluidSynth
2 stars 0 forks source link

FluidSynth stops playing after about 300-400 notes on Rpi, more on Mac #1

Open donundeen opened 2 months ago

donundeen commented 2 months ago

Hi, I'm running this library with fluidsynth on both an RPi and a Mac.

I'm struggling with the fact that after some number of notes, the synth stops playing, but doesn't give any error messages.

on an RPI, it stop between 300 and 400 notes. on my Mac, it stops between 2000 and 3000 notes

Also of note is that the system doesn't fail with any error.

Below is some code the reproduces the error for me:


var JZZ = require('jzz');
require('jzz-synth-fluid')(JZZ);

let env = "mac"; // or "rpi"

let soundfont = './soundfonts/GeneralUserGS/GeneralUserGS.sf2'
let fluidpath = '/usr/bin/fluidsynth';
let arg_a = "pulseaudio";
let args = ["a", arg_a];
if(env == "mac"){
    fluidpath = '/opt/homebrew/bin/fluidsynth';
    soundfont = '/Users/donundeen/Documents/htdocs/icanmusicprojects/server/soundfonts/GeneralUserGS/GeneralUserGS.sf2'
    arg_a = "coreaudio";
    args = ["a", arg_a];
}

let numnotes = 100; // make this number larger for more notes at once (a cluster of notes)
let interval = 100; // how often (in milliseconds) to play each "cluster"
let synth = JZZ.synth.Fluid({ path: fluidpath, 
                sf: soundfont,
                args: args }).or(function(){console.log("some problem starting!")});

setInterval(function(){
    play_notes(numnotes);   
}, interval);

let global_count = 0;
function play_notes(numnotes){
    console.log("playnotes");
    let i = 0;
    while(i < numnotes){
        global_count++;
        console.log(global_count+ "********************************************** " + global_count);
        let note = Math.floor(Math.random() * 127);
        let velocity = Math.floor(Math.random() * 70)+ 50;
        let voice = Math.floor(Math.random() * 100);
        let duration = Math.floor(Math.random() * 200) + 25;
        let channel = Math.floor(Math.random() * 10);
        makenote(channel, voice, note, velocity, duration );
        i++;
    }
}

function makenote(channel, instrument, pitch, velocity, duration){
    console.log("playing note "+ channel + ", " + pitch +","+velocity+","+duration);
    synth.program(channel, instrument)
    .noteOn(channel, pitch, velocity)
    .wait(duration)
    .noteOff(channel,pitch).or(function(msg){
        console.log("some problem! " + msg); // this never is printed
    });
}

I've found that if I count notes, and re-create the synth object before I hit the limit, it will continue to play. But it kill all playing note and creates a pause, which musically isn't great.

If anyone has ideas on what a solution might be, or how to get more insight into how see what's goign on underneath the hood, that would be amazing, thanks!

donundeen commented 2 months ago

I've also noticed that if i DON'T call the .program line, eg

function makenote(channel, instrument, pitch, velocity, duration){
    console.log("playing note "+ channel + ", " + pitch +","+velocity+","+duration);
    synth
    //.program(channel, instrument)
    .noteOn(channel, pitch, velocity)
    .wait(duration)
    .noteOff(channel,pitch).or(function(msg){
        console.log("some problem! " + msg); // this never is printed
    });
}

Then I get about 700 notes on the RPi intead of 400.

donundeen commented 2 weeks ago

hi, wondering if there's a better repo to post this issue on, seems kinda serious. thanks!

donundeen commented 2 weeks ago

after more investitation, I discovered that: if I spawn a child process the way this code does, and send messages to fluidsynthn in the same way, it will stop playing after about 400 notes. So something with how the child process interacts with the fluidsynth in interactive mode is the problem. So instead I'm now running fluidsynth as a background service with its own midi port, and using easymidi to send midi messages to fluidsynth, and no longer encountering this problem.