yzi wrote:- remove "#define SOUND_USE_SEMAPHORES"
Did you check that it's not only this modification that remove the graphical glich appearing each couple of seconds ?
No, I don't think I tested that in v 0.4. But updating to v 0.5 removed the _graphics_ glitches, even though the semaphore-locking thing was intact. But removing the semaphore-waits removed the audio glitches.
From my debugging, the core was generating more samples than what is expected. So the issue was more on emulation core side. Having more samples generated leads to de-synchronization hence the pause.
That's what I assumed as well, based on my hacking-around with the previous version. But the problem is, there seemed to be several "master clocks" and a complex network of "A waits on B" dependencies.
The semaphore thing looked like, in some circumstances, the emulator core (finish_sound_buffer() is run in and by the emulator core thread, right?) will have to _wait_ for audio output!? To me this seems like a broken idea. And consider that 2048 samples at 44100 Hz rate takes 46 milliseconds to play, which is longer than 2 full PAL 50 Hz frames.
By removing semaphore, you're never have pause but instead you should have buffer overflow: the producer will overlap consumer buffer and audio glich should happens.
Not exactly. No pauses, but no buffer overflows or underflows either.
That's why my audio consumer is comparing the producer position vs. consumer position, and if the consumer is getting close to draining the ready-made producer buffers, it will re-play the latest producer buffer (256 samples per buffer). It is kind of like resampling, but with "grains" of 256 samples.
So i feel like you move the consequence from video to audio side.
Absolutely. That's what needs to be done. There can only be one master clock. HDMI audio+video out might be a special case, but generally speaking, the audio and video output devices have their own independent clocks. Inevitably at some point, the audio clock will have ticked a different number of audio samples clock ticks than what would theoretically be exact for the video clock.
I don't claim to understand too much about UAE or UAE4ARM or emulators, but to me the right way to split the responsibilities between the emulation core's "virtual world" and I/O interfacing to the host world is
* The emulator core runs in total virtual isolation, and it is essentially a "real-time video+audio movie producer". Its clocks are ticking virtual Amiga time, or whatever.
* Audio and video outputs do their best to try and play the "movie" produced by the core. It's some kind of an approximation anyway. Audio outputs have to be able to resample, video outputs will have to do impossible magic like show 50 fps stream on a 60 fps screen, etc.
* Because audio and video outputs (and inputs) can all have their own independent clocks, it must be decided what kind of a compromise we want to make. It is definitely impossible, in the general case, to have EVERYTHING perfectly synchronized at the same time. Only in the special case where multiple external host I/O devices happen to be in sync with each other because they are driven by a common master-clock, can you have all "sample-accurately" in sync and aligned. But even then, there is still only one master clock.
(* Not related to audio/video, but controller inputs and other I/O stuff like that has to be time-stamped and the timings translated to/from virtual time, through some sort of translator layer)
Raspi's HDMI output might be a special case. But anyway, the software has to adapt to whatever APIs we have, and if video goes out with, say, GLES/EGL, and audio goes out with, say, ALSA, then we have to assume that the things are not in sync.
Note that buffer underruns message came from Alsa. So if you're using another audio layer than alsa (SDL1 use ALSA as audio sublayer by default) you don't see the message, it doesn't means there is no buffer underruns.
I'm pretty sure that there are no audio buffer underruns with my current simple audio consumer code, because the audio callback handler _always_ fills the requested buffer _immediately_ without waiting for anything. The question is only, from where it copies the stuff. If the consumer thinks it's is getting behind too much, it will skip over buffers, discarding a producer buffer. If it's ahead, it will re-play a buffer, repeating a producer buffer. But in my experience, repeating or skipping happens very, very rarely. Only with some demo effects like some plasma-type things in Sanity's World of Commodore, the emulator is unable to produce stuff fast enough, and then the audio consumer will play things at half-speed. (Or maybe that's not the problem? I'm not sure why that happens, but the audio consumer just isn't getting stuff and has to slow down)
Anyway, I've been very happy with the simple 256-sample buffering thing.
I'm now trying to make a CRT filter fragment shader. To get shaders working, I had to hack the GLES code a bit towards GLES2. I got a simple "every second line is darker" thing working, though there is the problem that if the physical output is, say, 720p, then half of that is 360 lines and the Amiga screen should be aligned to that grid. But even without aligning it made everything look better.
I will upload these thingies somewhere at some point.
Thanks for your work and comments.