I'm not saying sample-accurate, because it turns out, Fluidsynth has an internal buffer size and thus timing granularity of 64 frames. So 64 frames is the max. accuracy attainable for SF2. But it's better than nothing. Big thanks to David Henningsson of the Fluidsynth dev team, who very helpfully answered questions. A great guy.
In addition, there are some fixes to earlier commits here, which I ran into while working on the SF2 timing.
Change in handling of frameoffset for multistreamed instruments and sampletracks.
- Instead of holding the offset for the lifetime of the playhandle, negate the offset in the first period
- Multistream-instruments require some small changes: they have to now check for the offset and accordingly leave empty space in the start of the period (already done in this commit)
- There are possibly optimizations that can be done later
- This change is necessary so that we can have sample-exact models, and sample-exact vol/pan knobs for all instruments. Earlier multistream instruments were always rendering some frames ahead-of-time, so applying sample-exact data for them would have been impossible, since we don't have the future-values yet...
Fixes#865. Added a check so we don't add subnotes to a note that is already released (can happen with very short midinotes, eg. sliding the mouse accross the gui piano).
I also added a mutex to incoming midievent handling in instrumenttrack. Not sure if strictly necessary, but seems like this would prevent problems in the long run.
Also fixed a glitch in noteplayhandle where silent master notes got stuck playing indefinitely ( isMasternote() returns true even if the nph just hadChildren, so it never gets ended if it did - instead we check if we still have subnotes).
- currently only affects Vestige
- no idea whether this can also be used for Zyn and OpulenZ, I'm not sure if Zyn has any kind of mechanism for communicating frame offset to the synth, as for OpulenZ, @softrabbit would know the answer better
- basically, I made it happen by simply adding an extra parameter in the processMidi{In|Out} functions, which is 0 by default, and made the necessary changes in instrumentTrack and nph to utilize it
- I based this against 1.1 because I didn't think it's a very big change, and I don't see much possibility for things going wrong here, since we're basically just using the existing functionality in Vestige (there already was a frame offset being communicated to the remote plugin, just that it was always set to 0). However, if @tobydox thinks this is better to bump up to 1.2, I can rebase it for master...
Instead of having various flags for realizing the arpeggion functionality
use a more generic approach here using the recently introduced "origin"
property.
In order to keep compatibility with projects created with LMMS < 1.0.0
we maintain a property specifying the base velocity (i.e. the velocity
sent to MIDI-based instruments at volume=100%). For new projects this
always will be 64 while compat code enforces a value of 127 for old
projects.
We can also think about hiding the new groupbox in order to hide
complexity from the user.
Closes#430.
Instead of emitting InstrumentTrack::midiNoteOff() in destructor of
NotePlayHandle do this where it actually happens -> noteOff().
Fixes length of recorded notes when there's e.g. a long release.
Closes#378.
The volume of an InstrumentTrack is applied separately when post-processing
the audio buffer and is not related to MIDI processing. It therefore should
not be included into MIDI velocity calculation.
Closes#301.
Next big coding style update - this time all PlayHandle classes are
affected. Functions like done() and released() were renamed to
isFinished() and isReleased().