So, while we figure out a way to get a new RT-safe engine implanted into LMMS (maybe Unison, maybe something else), and we have plans for kickstarters and all that which is still a good idea, but meanwhile, I've also been working on figuring out the possibilities for improving the current engine. Can't hurt to try, right? And it's still doubtful if the "new engine kickstarter" idea will ever even work out, so it's better to keep doing something.
So, I've had some very interesting discussions on irc about this subject, HarryHaaren in particular has been very helpful. So, here are some things we've come up with. 1. Is the removal of the global mixer lock. Entire removal. This is work which I'm already working on, slowly but surely, and in fact I just merged the banish-all-locks branch to master, which is another step towards removing the need for global mixer lock. What still needs to be done is hunt through the code for all places that lock the global lock, and change them so that they use other methods instead - smaller local locks, or some fancy trickery with atomics or other things that subvert the need for mixer thread locking. This is important because the mixer thread must be non-blocking. The mixer thread must never be in a situation where it has to wait for other threads to fiddle things. Other threads (GUI and such) should do their work in such a way that the mixer thread can keep on chuggin' while they do it. 2. Removal of excessive dynamic allocation of objects during playing. This needs a bit of layman-exposition. The problem is the way we handle notes. When notes are played (either live notes or from the pattern), every time a note starts, a new NotePlayHandle -object is constructed. This is bad, because when objects are constructed in that way, they get allocated in the heap, which is a costly, non-RT-safe operation - meaning, it can't be predicted how long it will take to allocate the memory. Heap memory allocations should be avoided for that reason. So what we should do is instead cache the notes and re-use them, so we don't have to keep constantly allocating and deallocating heap memory. I have a hunch that doing this would hugely improve RT-safety and cut down on CPU-spikes, making LMMS faster, and making my project files actually listenable without exporting... So for starters, I'm thinking of setting a discrete "polyphony limit" for all instruments: say, every instrument track gets 128 static NotePlayHandles, which get used and re-used, but never destructed/constructed, instead their state is just reset. Later on, we can make this polyphony limit configurable, so that if there are corner cases where you need more than 128 notes playing at the same time, you can just increase the limit. Even later on, we can make some kind of auto-extension mechanism, which automatically increases the polyphony limit on a track-by-track basis when needed, but for starters I think a static amount is fine. 2.5. NotePlayHandles aren't the only thing suffering from problem #2 Instruments also allocate new synth objects for each note, and attach them to NotePlayHandles. The same fix can be applied here: the synth objects can also be cached and reused, and they can use the same polyphony limit as the NPH's. 3. Speaking of NotePlayHandles - revise the handling of subNotes, ie. chords/arpeggios When chords/arpeggios are enabled, they work by creating subNotes for each NotePlayHandle. These subNotes not only have all the problems that NotePlayHandles have (see #2), but they're also handled very inefficiently: subNotes are added into an array inside the parent NPH, and they're then processed linearily within the processing function of the parent NPH. Obviously, it would be more effective to process the subNotes in parallel, multi-threadedly. So what we'll do is, change subNotes so that they become ordinary NPH's and use the same cacheable/reusable NPH's in the polyphony stack (see #2), and the parent note will only contain pointers to them. The parent note can still control the activation/deactivation of the subNotes like it does now. ------ There are some additional other things where we can improve things by caching and recycling, but I think listing all of them would get a bit repetitive and boring, so I won't - feel free to ask if you're interested, person who has managed to read this email all the way here. Anyway, all of these things listed here are very much doable, even with our current resources. Meaning, that I'm able to imagine in my brain ways to actually make them happen. I also think these can potentially hugely improve the core of LMMS and produce a not insignificant performance boost. So for now, all other plans for 1.2 are taking back seat, and this improvement of core functions is getting priority. Of course, I'm only speaking for myself, everyone else is still free to work on whatever they want to work on... for example, grejppi is making some good progress on his LV2 branch, I wouldn't ask him to interrupt that. ------------------------------------------------------------------------------ _______________________________________________ LMMS-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/lmms-devel
