Ableton / link

Ableton Link
Other
1.09k stars 149 forks source link

Metronome demo is flawed #133

Open cmaughan opened 1 year ago

cmaughan commented 1 year ago

I recently integrated the sample code for PortAudio/AudioEngine into a test app. Everything worked, but the audio quality for the metronome was poor; with annoying distortion of the sound on occasion.

The root cause of this problem is that the metronome calculates a simple sin/cos wave using the current time information. Inevitably from one audio frame to the next, the time value used in the sin() calculation will drift as tempo is synced across the network. This means that the waveform being filled into the audio buffers will have discontinuities of phase, and distortion is heard.

I'm sure many users who have integrated the metronome into their code will have heard this.

One simple solution would be to trigger a complete 'ping' for every beat and fill the buffer with the wave until the ping has timed out. In this way, discontinuities between audio frames are removed. I tried this and it makes a nice clean sound.

I know that using sin/cos won't be typical, and wavetables, etc. are more likely, but it's a shame that the sample source code generates poor audio!

fgo-ableton commented 1 year ago

Ja. Back when we wrote this we chose this approach to have the sample code as simple as possible. Also in my experience this has been working fairly well for most audio drivers on most platforms. But yes, if the timestamps coming from the driver have too much jitter for the host time filter to smoothen them out it gets nasty. What platform/driver are you using PortAudio with?

cmaughan commented 1 year ago

On my main machine, I have something called a 'Realtek USB2.0 audio' output. I tried using DirectSound, MME, WASAPI drivers. I also tried it on my laptop (not sure what that has in it). Increasing the size of the audio frames helps, because then you get less phase differences / second of the wave. And it does usually settle down and get cleaner. I'm really surprised others don't encounter this. Maybe I'm just unlucky with my setup.

fgo-ableton commented 1 year ago

I see. In Live on Windows we actually disable Link when not using an ASIO driver because there is just too much jitter in the timestamps. It turns out using i.e. ASIO4ALL leads to way better results than using the default Windows APIs.

cmaughan commented 1 year ago

My point in the bug is really that the approach is incorrect: you can't guarantee consistent phase between audio frames using the current approach. 'Use a better driver' is one solution. Generate a complete audio sample for each click is another.... it is simple enough to figure out a click is due, and generate 'n' audio samples for the duration, filling the buffers till they are done. Note that the effect is also more pronounced with smaller audio frames, say 256 samples.... I will paste my crude fix here as an example...

fgo-ableton commented 1 year ago

Yes, I understand. I'm just saying we chose this route to have easier example code knowing that this will lead to bad results in some scenarios. I'll consider updating the examples.