-
-
Notifications
You must be signed in to change notification settings - Fork 291
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
MIDI audio is delayed after suspending the server #160
Comments
This might be fixed now that we've switched to JSyn for event scheduling. I'll do some testing to see if I can reproduce this bug while running the latest version of Alda on the master branch. |
Yep, problem solved after switching to JSyn! |
Nope -- I spoke too soon. This still seems to happen, possibly related to closing and later re-opening my Macbook. |
Just a stab in a dark, but this might be related to some of the top-level things I've defined, like |
I'm still reproducing the issue on my Macbook by doing this:
|
So here's what I did:
Looks like defonce is not the issue. Thanks. |
I did what you did as well,
Also I noticed that if you keep playing the same note after closing the laptop, after a while the lag goes away. |
@firesofmay Yep -- you're doing it right. It does sound like defonce is not the issue. That's very interesting that the lag goes away after a while. It almost seems like either the JSyn SynthesisEngine or the Java MIDI Synthesizer instances are "falling asleep" or dying when the laptop is closed... It does take a few seconds for a MIDI synth to start up, so I wonder if maybe that's related. |
@daveyarwood Yeah could be. But how I am not sure how to confirm that? |
Hmm... this gets a bit complicated, but I think you would need to run the Alda server in a way that you can access it via a Clojure REPL. There are two ways you could do that:
The second way is probably easier -- that link has a good walkthrough on how to use a socket server REPL in Clojure 1.8.0 (the version we're using for Alda). Once you're in a REPL, you'll be able to inspect and interact with anything in any of Alda's Clojure namespaces. One thing to check would be whether the MIDI synthesizer instances in the |
Okay. Will check this on weekend and get back to you. On Wed, Jun 1, 2016 at 8:00 PM, Dave Yarwood notifications@github.com
|
Sorry, Didn't get time to investigate this. Had some office work left. |
I had an interesting observation:
I'm really scratching my head over this. I'm tried googling for some explanation as to how this can happen, but I can't seem to find anything about it. I think I may ask this question on StackOverflow, and see if there is someone out there who happens to know what happens when you have a MIDI synthesizer on a running JVM and you leave the program running and close your laptop lid. |
I've asked this question on StackOverflow: http://stackoverflow.com/questions/38944107/java-midi-audio-is-delayed-after-laptop-comes-out-of-hibernation I also put together a simple Java program that demonstrates the issue: https://github.com/daveyarwood/java-midi-delayed-audio-example So it's definitely not anything Clojure-specific. If we can figure out how to fix the problem in Java, then we can use that knowledge to fix it in Clojure for Alda. |
I messed around with your example code and I wanted to let you know the issue wasn't so much in the computer going to sleep, it's the process being 'suspended' for a period of time. You can reproduce this without sleeping (on debian, running in bash) by:
I guess the java midi synth just isn't happy when it's suspended for any reason. Sounds like this should be submitted as a java bug and fixed upstream? I'm not sure if it's possible to workaround this (perhaps you could somehow intercept waking up and restart the synth?) Glad to know it's not an issue in alda though 😄 |
Ah, that's good to know! I think we're getting closer to figuring this out. I've filed a bug at http://bugreport.java.com -- In my example code, there is a single MidiSynthesizer instance being reused, which I think is part of the problem. I did try changing my example so that each time you press Enter, a new MidiSynthesizer instance is created and used, and that does seem to help. Here is the alternate version on a branch. It's inconvenient to do it this way though, because it takes each MidiSynthesizer instance at least a few seconds to initialize and be ready to play. If you try and use it immediately after calling As a workaround until this gets fixed upstream (assuming that ever happens), I wonder if there is any way for the server to quickly check to see if it is in this state, and if so, it can return a helpful explanation message to the client and then start up a fresh pool of MidiSynthesizer instances before playing the score? Better yet, the server could periodically check for this scenario in the background and quietly fix itself. |
A possible solution has been posted on SO: http://stackoverflow.com/questions/38944107/java-midi-audio-is-delayed-after-laptop-comes-out-of-hibernation/38948413#38948413 TODO: try this out and see if it works... I'm also curious how many people have the Sun implementation of the MIDI Synthesizer. I'm not even sure if I do or not. |
I just tried the solution above with my Java example (here's the modified code on a branch) and it seems to be a great workaround! Next steps:
|
I have this change on a branch and I tried it out. It does solve the issue of delayed audio after suspending and bringing back the server process, but I'm noticing an obvious instability in the timing of the notes, which I find unacceptable. I think jitter correction is something we need... it's just a shame that it carries this bug with it. Even if the bug I filed with Java is fixed, we won't reap the benefit until it makes it into a new version of Java, and then we can't expect everyone using Alda to be on that new version, so I think we need to explore another tactic. I've been playing around with a "one server, multiple workers" architecture for #243 using ZeroMQ. Once we have that in place, I'm thinking the solution for this issue might be to watch for workers getting suspended, and quietly replace them. Each worker could send a heartbeat to the server every X seconds, and if the server doesn't get a heartbeat from a worker within a certain timeframe, then it could assume that the process was suspended or something else went wrong, and replace that worker. |
You might want to look into the style of Erlang, which is a language On Mon, Aug 22, 2016 at 2:00 PM, Dave Yarwood notifications@github.com
|
I think 1.0.0-rc35 inadvertently fixed this issue 😄 As of 1.0.0-rc35, a server will "lay off" a worker process if it hasn't gotten a heartbeat from it in 3+ seconds. The worker process stops receiving heartbeats from the server and shuts itself down. Meanwhile, the server maintains the desired number of worker processes by spawning new ones, so the server will notice that it's low on workers and create more. I left my Alda server running at the end of the day yesterday and shut my laptop (suspending all the processes). When I opened it this morning, there was a brief period of sluggishness caused by there being "11/4" worker processes available (yikes!), but then the stale workers shut themselves down and I had 4/4 workers available again. I ran an I'll leave this issue open for now -- we can improve this by teaching the server to recognize when it's been suspended (easily done*), and when that happens, kill and replace all the workers. That way we can avoid having a bunch of stale workers lingering at the same time the server is trying to start new ones. * The server can keep a reference to the last time it did its message-handling loop (this happens constantly). At the end of the loop it can update the "last run" time. At the beginning of the loop, it can check the "last run" time against the current system time. If it's been more than say, 10 seconds, we can conclude that the server and workers may have been suspended. |
Fixed-ish in 1.0.0-rc38. Now the server will cycle out the workers if it detects it hasn't been active in 10+ seconds. Workers will also shut down if they detect they haven't been active in 10+ seconds. I say "fixed-ish" because the problem still may be observable if you do something like close your laptop lid and then re-open it in under 10 seconds. If you ever observe this problem you can fix it by running |
Unfortunately, I'm not seeing the worker restart happening anymore after upgrading to macOS Sierra (from Mavericks). If I close my laptop and reopen it hours later, the delayed audio problem is still there. I suspect that since the upgrade, my OS is doing something differently re: suspending processes when it goes into sleep mode. I think maybe a better workaround would be to implement a life span (maybe 15-30 mins? we could randomize it so that the workers don't all quit at the same time) for worker processes, after which time the worker quits and the server spawns a new one to replace it. This would at least ensure that if your computer is awake for long enough (i.e. 15+ minutes), you are guaranteed to have a worker available that isn't stale from before your computer woke up. I'll file a new issue in alda-server-clj for this idea. |
I get pretty much immediate responses from the server* after first running it, but after leaving the server running for a while (e.g. if I leave my computer and come back hours later), it may take several seconds or more before I hear anything. Restarting the server fixes it.
*meaning, if I run
alda play -r -c 'piano: c'
, I hear the note immediatelyNo idea what the issue is at this point, but figured I would report it in case anyone has any ideas.
The text was updated successfully, but these errors were encountered: