On August 14, 2013 12:00:29 AM Florian Jung wrote: > Hi > > ABSTRACT: > > It is "GUI performance" XOR "crackle-free playback". > Currently, MusE focusses on "crackle-free" only, neglecting "GUI > performance". (Using message passing, delegating work to the audiothread) > With my proposal, we could offer "crackle-free" whenever needed, but can > also offer "GUI performance" when currently not playing back (i.e. most > of the time!) > > tl;dr: skip this until ====SNIP==== > > i'm currently doing a great rework of: > - the Undo system > - the way GUI-actions are synced with the audiothread > - clone parts > and much more... > > I have removed the ModifyPart Undo operation. When you now want to > modify a Part's beginning, length or name, you do not any more create a > copy of the part, modify that, and then replace the old part with the > modified copy, but you just submit a ModifyPartTick. The audio part will > parse and execute that message then. > > However, i want to make this message passing *obligatory*. No GUI part > may have the possibility to directly write into audio-thread-managed > data. (I.e., all GUI routines may only receive const references to the > EventLists.) > > This arises one problem: someevent->setSelected() must be handled by the > audiothread as well. This makes things similarly slow as moving notes in > the score editor. For every operation, we've to wait for the audio > thread to process it. > > ====SNIP==== interesting part starts here: > > Now i'd like to speed this up: > When the song is not playing or recording, the audio thread does not > access its parts in any way, right? > > We could lock a mutex whenever we're playing back, and release it when > transport is "stopped". > > Then, song->applyOperationGroup() can tryLock() this mutex. > (tryLock locks it, if possible. if not, it does not block, but > immediately return!) > If locking succeeds (i.e., if transport is stopped), then the changes > can be applied in the GUI context without any harm. And this is *fast*. > > If locking does not succeed (i.e. transport is playing), then we have to > go over the Audio::sendMessage, and wait for the audiothread to execute > our changes. > > > > There's only one race-condition: When applyOperationGroup() has locked > the mutex, but audio would like to start playing in the very same > moment. MusE can use the transport framework to tell the transport > master "please wait some milliseconds, i'm still initalizing...", so > this won't be an issue. > > > > > I'd really like to hear your opinion about this (further work depends on > this). > > This would enable us to clean up huge part of muse, I even dare to say > this can be the first step towards a easy-to-maintain muse3! > > And it would improve GUI performance notably, especially on setups which > are not trimmed towards minimum audio latency (e.g. MIDI setups!) > > > in await for your reply, Tim, Robert and Orcan, > flo
Before I respond... http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits- for-nothing You may have seen this but if not - please grab a coffee and read it carefully. It is a very good post! It is why we (I) strive to avoid mutexes and favour ring buffers instead. I admit that I break the rules sometimes by manipulating simple variables like booleans across threads. So far we've been lucky, I've never seen a crash due to this, but I suspect with multi-core CPUs there may be a problem... I understand that these simple variables are supposedly atomic on modern CPUs and OSes, but it's still said to be dangerous due to CPU caching and various other reasons, portability etc. Darn, I hate to set up a ring buffer just to pass a boolean! But this is what we may require at some point - we already have safe ring buffers for *control* and *note* events, but we may need to also add a ring buffer for *commands* and operational stuff - such as simple booleans and so on. NOTE: I must expand our usage of ring buffers: Each device has a ring buffer and it is possible that different threads can put things into the ring buffer. This 'multiple writer' operation is wrong - ring buffers should have only *one* writer, and *one* reader (we're safe - only the audio thread reads). So I will need to have ring buffers for each of the possible threads that wish to communicate with the device via the audio thread. That is, instead of a single device->addScheduledEvent() you will see multiple versions dedicated to each writer thread: addScheduledEvent_GUI() and addScheduledEvent_ALSA() and addScheduledEvent_OSC() representing the various threads - GUI, ALSA, and OSC and so on. --------------- So I have read and understand your proposal and... I endorse it (until further notice). I'll let you know if I find anything counter to this. When the transport is playing, the audio callback calls Audio::collectEvents() which is the place where part events are gathered and sent to the device's playback event lists. So this is the section you are concerned with. If someone is manipulating part events via the GUI thread you want to obey threading rules here. I have looked into the future to see if it is possible we would ever need to access these part events from the audio callback during transport stop mode, and I cannot see us doing it except for one possibility: Some day we may want to add what is commonly called a 'scrub' mode where the user moves the cursor around and notes are sounded as the cursor is moved. However that is technically not stop mode - the transport is technically in 'start play' mode then goes back to 'stop' mode after relocation is successful. Regardless, I'm sure it could be worked out somehow... Not to mention it is unlikely the user will be 'scrubbing' and 'editing' at the same time. Another area I'm planning work on, is the concept of what is commonly called a 'setup bar' or a 'bar before bar zero'. There is a special sequence of events that needs to be sent before the transport can roll. These events would be sysex and other messages that need to be sent to the device to ensure it is set up properly. These are the events that the user can enter in the Instrument Editor sysex Editor section which can for example tell the device to switch to GM or GS or XG mode or whatever else required. (User can currently opt out of sending these events when asked via a dialog). However don't worry too much, as these are not part events, they are special instrument event sequences. The other important usage for a 'setup bar' is metronome pre-counts, accessible from the metronome dialog, something which Robert has currently disabled because they weren't working properly. The plan is to re-enable them using the transport waiting feature of Jack (the 'slow sync' callback) to allow us time to do a metronome pre-count before rolling. Again, don't worry too much because these events are not part events, they would be put there by the metronome. Some further info about GUI operations: -------- You'll see that when operating a midi GUI knob or slider, such as in MidiStrip::ctrlChanged(), it will call audio->msgPlayMidiEvent() which I have known for a while is slow - it waits for audio sync. I think I had planned to fix that, likely ran out of time before. Because now that I have added device functions like addScheduledEvent() which passes events to the device via a safe ring buffer, this msgPlayMidiEvent() should be unnecessary. This will also permit the GUI control movement timing to be accurately and faithfully reproduced when the driver gets around to them - something msgPlayMidiEvent() cannot do. After all, I was able to achieve this goal with audio knobs and sliders, so the next logical step is to take care of the midi knobs and sliders. Let me handle this area - kick me if I haven't fixed it soon... Thanks. Tim. ------------------------------------------------------------------------------ Get 100% visibility into Java/.NET code with AppDynamics Lite! It's a free troubleshooting tool designed for production. Get down to code-level detail for bottlenecks, with <2% overhead. Download for free and get started troubleshooting in minutes. http://pubads.g.doubleclick.net/gampad/clk?id=48897031&iu=/4140/ostg.clktrk _______________________________________________ Lmuse-developer mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/lmuse-developer
