dagargo / overwitch

JACK client for Overbridge devices

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Handle Jack buffer size changes

szszoke opened this issue · comments

Hello!

I just got a Digitone and I tried it with overwitch on my system running PipeWire as the Jack server. It seems to work well except one thing: reacting to buffer size changes.

When I change the buffer size of a running Jack server, I get a ton of nasty sounds and a ton of these lines printed to the console:

ERROR:overbridge.c:255:(set_usb_input_data_blks): o2j: Audio ring buffer overflow. Discarding data...

I did some digging in the source code and I found that overwitch doesn't set a callback for buffer size changes.

I suppose that it is not that common that people change the buffer size of an already running Jack server but I suppose it can happen and it would be nice if overwitch could handle the situation gracefully.

Here is the specific callback that I am talking about: https://jackaudio.org/api/group__ClientCallbacks.html#ga030cc371acb19abe52861492acb960ad

Hi!

The code to handle this it's already present in the print_init_error branch. I'll merge it into the master in the following days. There's one caveat though: Overwitch is restarted completely so it will clear the ring buffers and will perform the startup tuning again so you'll lose audio for a few seconds.

I've tested it but I'd be nice if you could test it too.

Let me know your thoughts on the solution. Is it practical enough for you? If you want to disable the startup try to change this line to a higher status.

overbridge_set_status (ob, OB_STATUS_INIT);

I will give it a try!

One does not simply change the buffer size during recording. I think a few seconds of silence is fine.

I get a seg-fault with PipeWire as the Jack server right from the start.

It seems to work with regular Jack but I noticed that the audio speed goes up and down for a few seconds when I change buffer sizes.

Here is a WAV file where I recorded the glitch. It is not a ZIP atchive. I had to add .zip at the end, otherwise GitHub would not let me upload it. Just remove .ZIP at the end.
buffer_size_glitch_session.wav.zip

There are a couple of issues here: the buffer changes, which totally work for me without any glitch; and the PipeWire issue.

At the moment, I can not install PipeWire yet and, in fact, I want to release version 0.2 without any more features that are already open and since it's still kind of experimental, makes more sense to me to open an specific issue for PipeWire. For this purpose, I've just open #21.

Regarding the glitch, I'm using Ardour and JACK in Debian stable. What is your configuration on which you're getting the glitch? Let's consider that this might be something unrelated to Overwitch.

I was not using PipeWire when I experienced the glitch. I was using regular Jack 2. I used Ardour 6.9 for recording on a Manjaro 21.2.0 system.

The MAIN L/R ports of Overwitch were linked to the playback ports of my sound card. I used Ardour's audio setup window to change the buffer size of Jack.

Well, that's just exactly the same configuration that I have. The Ardour version number differs but the JACK version will probably too.

$ apt list --installed | grep jack
jack-capture/stable,now 0.9.73-3 amd64 [installed]
jackd2-firewire/stable,now 1.9.17~dfsg-1 amd64 [installed,automatic]
jackd2/stable,now 1.9.17~dfsg-1 amd64 [installed]
jackd/stable,now 5+nmu1 all [installed,automatic]
libjack-jackd2-0/stable,now 1.9.17~dfsg-1 amd64 [installed,automatic]
libjack-jackd2-dev/stable,now 1.9.17~dfsg-1 amd64 [installed]
qjackctl/stable,now 0.9.1-1 amd64 [installed,automatic]

$ ardour --version
Ardour6.5.0~ds0 (built using 6.5.0~ds0-1 and GCC version 10.2.1 20210110)

Indeed, the version of Jack installed on my system is 1.9.19.

One more thing. The segfault doesn't happen if I compile the latest PipeWire master and run overwitch against it. The audio glitch doesn't happen either but the silence is much longer.

It takes about 18 seconds when going from 1024 to 64 samples and about 40 when going from 64 to 1024 samples.

The silence time is variable and it depends on many things. This silence is used to simulate everything without sending data which might end up filling the ring buffers with more data than needed due to the initial errors in the ratios, what would lead to higher latencies.

Perhaps it's possible to reduce the time, I'll think about it.

Let me explain a bit how what I call calibration works.

Overwitch implements a DLL based on the work of Fons Adriaensen and basically is resampling the audio continuosly based on the different rates of the input samples and the output samples. The DLL is calculated only for the Overbridge to JACK side and the reverse path just uses the inverse ratio.

Before audio (an MIDI) is actually flowing thru Overwitch we need to have a ratio value that is stable enough because otherwise we'll be resampling with the wrong ratio and filling the internal buffers with an inaccurate number of samples. If the amount of samples is less than the expected there is no problem, otherwise we'll be increasing the latency. This way, audio does not pass thru until the ratio is stable enough.

Considering this, the huge audio silence is due to the initial low accuracy of the accumulated samples and this will never be avoidable specially when changing the buffer sizes because he higher the sample difference the higher the error and the higher oscillations during the stabilization process and, hence, the longer time to stabilize.

Another factor to consider is the amounts of blocks used in the Overbridge size because the lower the blocks the higher the difference and thus the higher initial oscillations.

Long story short, this can not be avoided. However, I've just pushed the branch startup_time_fix because I think that perhaps this could be mitigated in some cases. But the worst case scenario remains the same.

Let me know if this improves anything for you.

Keep in mind that another policy could have been implemented and I decided to do this because it was the simplest way.

Is the calibration process deterministic?

If yes, would it be feasible to have pre-calculated values for certain popular configurations and use the calibration algorithm for more exotic configurations only?

I'm thinking that running with a buffer size of 64 at 44.1kHz and two periods would be a pretty common scenario.

If the calibration process is deterministic then the output of the process could be stored together with a device descriptor and Overwitch could use those pre-calculated values instead of recalibrating.

Edit: changed tuning to calibration.

It is deterministic, of course, but the time it takes to be usable depends a lot on the initial conditions.

If yes, would it be feasible to have pre-calculated values for certain popular configurations and use the calibration algorithm for more exotic configurations only?

This is what I tried with the commit I mentioned. What I tried was to only fully calibrate the first time and partially the rest of occasions as I was not resetting the DDL and just scalating the ratio. But the problem stays the same in some circumstances.

Imagine that at instant 0 both ends are reported to use the same amount of samples, which would give a 1.0 ratio. Now, imagine that one of the sides provides this value just slightly later. In these two cases the ratios differ and the parameters are the same. As all this depends on the JACK callback wake-up time and on the USB response time it's not possible to improve this IMO.

Despite all this, if it's not the worst case scenario I measured the stabilization times and were generally better. That's why I asked you to confirm if this improvement was more of an anomaly.

I see. Thanks for clearing that up. I wasn't aware of all the variables.

I will give it a try in a few hours.

I saw that startup_time_fix is the continuation of print_init_error so I compared the two.

startup_time_fix performed slightly better with 1-5s difference.

My method was not the most precise but I suppose it is good enoug for the task. I also used PipeWire as the Jack server and not regular Jack.

I was monitoring Main L and R via my sound card.

I changed the buffer size and at the same time started a stopwatch on my phone. I stopped the stopwatch when I heard sound again.

I'd say all measurements are accurate within half a second.

I did three round of goung from 1024 samples to 64 samples and back.

startup_time_fix

1024 samples to 64

Attempt Duration of silence
1 11s
2 17s
3 9s

~12s on average

64 samples to 1024

Attempt Duration of silence
1 19s
2 13s
3 17s

~16s on average

print_init_error

1024 samples to 64

Attempt Duration of silence
1 17s
2 17s
3 17s

17s on average

64 samples to 1024

Attempt Duration of silence
1 13s
2 23s
3 15s

17s on average

Thanks for taking the time to test this. Very accurate post. 💯

Your measurements are very similar to my findings. Best case scenario behaves slightly better and worse case is somehow similar.

I'll merge this whenever the rest of issues are closed as it looks like reduces the silence time under some conditions. For now, I'm keeping this open.

No worries!

Merged into master.

Awesome! This should work with PipeWire 0.3.41 and newer.