-
Notifications
You must be signed in to change notification settings - Fork 260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some MIDI files never finish playing, with a note lingering forever at the end, since FluidSynth v2.3.1 #1257
Comments
So as I understand, it keeps playing forever because programs like the Church Organ usually (as defined by the SoundFont) keep producing a sound in the sustain section until the note is released. And since there is no "Note Off" event, the voice will stay active forever and the logic in #1159 will never let the MIDI stop playing. PR #1167 deals with a similar problem, but it does not apply here since the note is not being kept on by the pedals but rather by the program definition itself. A simple fix is to add an diff --git a/src/midi/fluid_midi.c b/src/midi/fluid_midi.c
index c8ad9d2..f3edcb7 100644
--- a/src/midi/fluid_midi.c
+++ b/src/midi/fluid_midi.c
@@ -2201,6 +2201,7 @@ fluid_player_callback(void *data, unsigned int msec)
{
fluid_synth_cc(player->synth, i, SUSTAIN_SWITCH, 0);
fluid_synth_cc(player->synth, i, SOSTENUTO_SWITCH, 0);
+ fluid_synth_cc(player->synth, i, ALL_NOTES_OFF, 0);
}
player->end_pedals_disabled = 1; Though this seems a bit too aggressive, since it can also force a note in the attack/decay section to go to the release section. This can be mitigated by So perhaps there should be a grace period before the noteoff, or a "smart noteoff" that causes the note to skip the sustain section but otherwise play the entire note. Does that make sense? |
Thanks for the report and for already having investigated (I didn't have any time yet). What you describe sounds plausible and the change seems to be reasonable. I wouldn't consider this change to be "aggressive" though. That if-clause is only ever triggered when the player has processed all events of the MIDI file. Any pending notes should be turned off after this point. This is equivalent to having sent a regular note-off event before that point. I am not aware of anything like a "smart noteoff" in the SoundFont / MIDI world. That missing note-off is simply an error in the MIDI file. If it had turned off a note which is still in attack section (while not indented), one should better fix the MIDI file to add the missing off event to get the desired behavior. Using |
Maybe "agressive" wasn't the right word, but what I meant is that if you have a (broken) MIDI whose last noteon's timing matches the end of track, with my patch, that note will get immediately released, so the MIDI will end in a pretty abrupt/anticlimactic way. E.g. with this MIDI file: three_notes.mid.zip if you play it without my patch, all three notes will sound the same, but with my patch, the last note will be much shorter. Though this MIDI is broken due to missing noteoff events and bad end of track timing so maybe we shouldn't care too much. OTOH, no problem with including this change in the next release :) |
Today I observed an issue that might be related to this one. When the process did not finish, I noticed the output file was already 90 GB big. Weirdly, when I tried it a second time, the process finished after 700MB, still 1.5h instead of the 3 minutes. Fixing this issue by forcing an ALL_NOTES_OFF is not a good idea in my opinion. You never know, how long this note was supposed to last. And even if you wait for 10 seconds, you are behaving undefined and you're concealing the fact that there is something wrong. I think, the best solution would be to throw an error, when a MIDI file ends with notes not being turned off. Just don't keep playing forever. |
Ok. But consider, that there might be multiple MIDIs files queued in fluidsynth's player. Should we really terminate fluidsynth with an error, just because there is one broken MIDI file in the queue? What about printing a warning, sending ALL_NOTES_OFF and continuing?
Should not happen when using fluidsynth 2.3.3 |
I'm not very familiar with the fluidsynth landscape. Is the player some kind of desktop / smartphone midi audio player? I agree then, it shouldn't terminate just because there is one corrupted midi file in the queue. From my perspective of using fluidsynth programmatically, it would be nice if calling it with a corrupted midi file would raise an exception eventually. midi2audio calls fluidsynth like this:
My version of FluidSynth is 2.3.2. The file was indeed 90GB big when I terminated the process manually. I can reproduce this issue when using FluidSynth from the command line using the file I have uploaded above. The sound font I am using is FluidR3_GM The full command I use:
Stopped the process after a few seconds and the file |
With FluidSynth v2.3.3 at least it will stop after writing a few GBs of data. |
The FluidSynth MIDI file player is not really a robust bullet proof MIDI file player and I don't know how much effort should be put into making it deal gracefully with bad files. I suppose one could argue that a MIDI file turning on a note and leaving it on might even be intentional. In the beginning MIDI was a very dumb protocol and that dumb simplicity made it successful and long lived. Trying to make MIDI smarter can get you in trouble. If we are going to make the MIDI file player smarter, can it match Note ON events to Note OFF events and remove Note ON events for which there is not a matching Note OFF event? This would be sort of like dealing with unmatched parenthesis. One possible complication is that multiple Note ONs for the same note can all be terminated by a single Note OFF, although I don't know if that is really a proper valid MIDI file. |
I don't want to attempt fixing misplaced parentheses. I don't think you can anyway. We are only facing this issue because a contributor wanted the MIDI player to respect notes that have been OFFed and are still playing in release phase at the very end of a song. Before that, the MIDI player would have just canceled any note, no matter kept ON intentionally or not. This type of broken MIDI files has never been supported. So just issuing a warning and sending ALL_NOTES_OFF at the end is good enough, IMO. |
I just created a PR for this, see above. |
Thanks! I built FluidSynth with the PR and ran some quick tests and everything is working fine. |
FluidSynth version
(On Arch Linux)
Describe the bug
In one of the MIDI files I have: "Day of mourning.mid" by Stuart Rynn (downloadable from here), when trying to play or render the MIDI to a file using the FluidSynth command line, it never terminates playing the MIDI file. Instead, one note appears to linger at the end forever, never decreasing in intensity.
Expected behavior
I expect FluidSynth to eventually terminate playing or rendering the MIDI file.
Steps to reproduce
If I try to play that MIDI from the command line like this:
foo@bar$ fluidsynth /usr/share/soundfonts/FluidR3_GM.sf2 "Day of Mourning.mid" -v
It will play the MIDI correctly (it should be about 5 minutes long), but at the end, one note will keep playing forever, with no further events being produced.
If instead I try to render the MIDI to a WAV file like this:
foo@bar$ fluidsynth /usr/share/soundfonts/FluidR3_GM.sf2 "Day of Mourning.mid" -T wav -F DOM.wav
The WAV file will keep growing and growing (until at least 4GB in size, at which point I killed FluidSynth).
It's possible that the MIDI file has some sort of incorrect/invalid event, though I have tried to inspect the file with programs such as
pw-mididump
and MuseScore and all tracks have an End-Of-Track event at 326 seconds and no further events afterwards.Additional context
I have been able to reduce the original MIDI to the following simple test case containing a single note:
OrganKeepsPlayingOnFluidSynth.mid.zip
The events in this MIDI file are:
In particular, it appears that the problem is related to the instrument ("Church Organ" or other kinds of organs), changing it to for example "program 3 (Honky-Tonky)" makes the MIDI terminate.
Additionally, the problem doesn't happen in older versions of FluidSynth. I have bisected the issue to #1159 (FluidSynth ≥ v2.3.1).
I also found this PR: #1167 which appeared to solve a similar problem in the past, so maybe something similar is needed to make this case terminate.
The text was updated successfully, but these errors were encountered: