-
Notifications
You must be signed in to change notification settings - Fork 69
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
Hotfix: excessive CPU use in the MIDI SenderThread #24
base: master
Are you sure you want to change the base?
Hotfix: excessive CPU use in the MIDI SenderThread #24
Conversation
I ran a profiler to determine where the runaway CPU usage appeared, and it showed up as dominated by calls to msleep() in SenderThread. I did the standard replacement of the busy loop with a mutex and wait condition, which solved the problem. Initial interactive testing showed no degradation of timing accuracy in playback.
This fixed the problem on Mac but there's still runaway CPU usage on Windows. The profiler I have there isn't as good, but it thinks the hot spot is somewhere in the graphics rendering (somewhere in quartz.dll which is part of DirectShow, called via dsengine.dll which is Qt's bridge to DirectShow). Still looking... |
Ok, the problem on Windows is definitely coming from the QMediaPlayer used in the metronome, even when the metronome is disabled. The problem goes away if you take out the line that loads the WAV file but of course the metronome is useless then. Removing the low latency flag doesn't help. I checked the WAV file to see if it was actually some weird format that was making QMediaPlayer do extra work (WAV is actually a container format that can hold lots of different encodings of audio inside, including MP3), but it's a plain old 44/16/mono PCM audio file, which shouldn't cause any problems. I wonder if it's worth ditching QMediaPlayer and adding a third party dependency for platform-neutral audio playback. There are lots of them, although dependencies are a pain and it's nice that the program has so few of them. Another alternative without any dependencies would be to do metronome clicks via MIDI output -- just play a closed high hat on the drum channel. That would have some interaction with actual drum tracks, though. What do you think? |
Aha! QMediaPlayer misbehaves like this when you tell it a path to a non-existent audio file. Maybe it's polling the file system to wait for the file to arrive. When it finds the file, the performance is fine. The metronome code refers to the file via a relative local path and my local directory layout didn't match the code's assumption (since I'm running in the build directory rather than using an installer). The WAV file is already embedded in the executable as a resource. I'll try changing the code to load it from there rather than making assumptions about paths. |
This means that the program doesn't need to look for the file in a particular local path since it's embedded in the executable (it was already there anyway). QMediaPlayer doesn't reliably support loading from resources but QSoundEffect does, and the Qt docs recommend using the latter for this kind of purpose anyway.
…plicitly; also tightened timing of the metronome by removing silence from the start of the click file
What do the 500ms in the waitCondition indicate? |
That specifies the maximum amount of time to wait before timing out and returning to the caller. (On the other hand, it will return instantly as soon as there's an event in the queue.) This is much more efficient than unconditionally sleeping for a fixed duration of 1 ms. The reason there's a timeout value (instead of waiting forever, which can be done by omitting the parameter) is so that the thread can be terminated cleanly — for example, if the application is shutting down). |
I ran a profiler to determine where the runaway CPU usage appeared, and it
showed up as dominated by calls to msleep() in SenderThread. I did the
standard replacement of the busy loop with a mutex and wait condition, which
solved the problem. Initial interactive testing showed no degradation of
timing accuracy in playback.