Jack-Audio process callback time period

Discussion of all things Raspberry Pi / Raspberry Pi 2 related

Moderators: khz, MattKingUSA

Post Reply
nahumb
Established Member
Posts: 9
Joined: Mon Jul 30, 2018 8:51 am

Jack-Audio process callback time period

Post by nahumb »

Hi,

I'm using Jack API in a synthesizer c++ program I'm developing running on a Raspberry Pi 4.

Sample rate is 44100 ( jackSampleRate = jack_get_sample_rate(client_out); )

Buffer size is set to 512 ( jack_set_buffer_size(client_out, _JACK_AUD_PERIOD_SIZE); ) (#define _JACK_AUD_PERIOD_SIZE 512).

Calculated process callback rate is 512/44100 = 11.6mSec.
However, actual process callback is initiated every 5.8mSec (with nframes = 512).

Any idea why the process callback rate is x2 than I expect it to be? (or my assumption is wrong? Why?)

Thanks,

Nahum

folderol
Established Member
Posts: 1159
Joined: Mon Sep 28, 2015 8:06 pm
Location: Here, of course!
Contact:

Re: Jack-Audio process callback time period

Post by folderol »

I don't think you can actually have less than two periods per buffer, so presumably one or other is being silently adjusted.

nahumb
Established Member
Posts: 9
Joined: Mon Jul 30, 2018 8:51 am

Re: Jack-Audio process callback time period

Post by nahumb »

Hi folderol.

Thanks for your prompt reply.

My apology, but not sure I understand your answer :roll:

Do you mean that I get 2 callbacks for each buffer (period) and one is ignored by the Jack-server?

What do you mean by "one or other is being silently adjusted"? (ignored?).

Thanks,

Nahum.

folderol
Established Member
Posts: 1159
Joined: Mon Sep 28, 2015 8:06 pm
Location: Here, of course!
Contact:

Re: Jack-Audio process callback time period

Post by folderol »

You and jack can't write to a period at the same time so while you are writing to one, jack is writing to the other, then jack swaps them over - or something like that! I'm a bit fuzzy on the details.

j_e_f_f_g
Established Member
Posts: 1121
Joined: Fri Aug 10, 2012 10:48 pm

Re: Jack-Audio process callback time period

Post by j_e_f_f_g »

By default, Jack assumes a period of 2. What this means is that Jack divides your buffer into 2 equal pieces (of 256 bytes each). Before you start play, Jack asks you to fill in the first 256 buffer piece with audio data, which jack then gives to your audio hardware to play. While your audio card is playing this first 256 bytes of data, jack asks you to fill in the second buffer piece with your next 256 bytes of data. The audio card signals jack when it's done playing the first piece, and jack immediately gives the audio card your second buffer piece (which you've already filled in). Now, while the audio hardware is playing your second 256 bytes, jack tells you to fill in the first buffer piece again with your next 256 bytes. When the audio card finishes playing the second buffer piece, jack immediately gives it the first buffer piece again. In effect, this constant swapping of buffer pieces allows jack to (hopefully) always have 256 bytes of data ready to play before the audio card needs it. This assures a smooth playback of audio data.

Of course, if you don't fill in a buffer piece before the audio card finishes playing your other buffer piece (maybe because you're doing some time-consuming DSP on the data), now you've got a problem. The audio card has no choice but to do one of two things:

1) Play whatever data is in the buffer piece you're working on. Depending on what you've managed to get in there, you may actually get something that sounds like nothing went wrong. Or, you may get some brief audible glitch like a faint quick pop. Or you may get something that sounds really bad, especially if you continue to take too long filling subsequent buffer pieces.

2) Stop play, in which case your audio output goes silent. You then have to reset the audio card, fill in your first buffer piece, and restart the audio card''s playback. The advantage here is that you don't get some awful noise when something goes wrong -- you get silence. Also you get to cleanly restart playback, such as to replay any audio that may have been "dropped out".

Jack forces your audio card to do #1. But if you're instead using ALSA's API, you have your choice of methods (by setting the "stop threshold". A value of 0 uses method 2.)

nahumb
Established Member
Posts: 9
Joined: Mon Jul 30, 2018 8:51 am

Re: Jack-Audio process callback time period

Post by nahumb »

Thanks for a very comprehensive and educating reply.

Buffer size is indeed 512 samples and callbacks are generated every half-buffer time, yet, number of frames in each callback request i get is 512
and not 256.
I have also put a trap inside the callback function looking for nframs != 512 -> always 512.

What bugs me more, is that it all sounds OK, though audio buffers are generated and sent to Jack in double rate, which cut by half envelopes time,
for example, but does not change the pitch or sound timbre?!.

Attached are Jack output messages when Jack is initialized for reference:

jackdmp 1.9.12
Copyright 2001-2005 Paul Davis and others.
Copyright 2004-2016 Grame.
Copyright 2016-2017 Filipe Coelho.
jackdmp comes with ABSOLUTELY NO WARRANTY
This is free software, and you are welcome to redistribute it
under certain conditions; see the file COPYING for details
JACK server starting in realtime mode with priority 10
self-connect-mode is "Don't restrict self connect requests"
audio_reservation_init
Acquire audio card Audio3
creating alsa driver ... hw:sndrpihifiberry|hw:sndrpihifiberry|512|3|44100|0|0|nomon|swmeter|-|32bit
ALSA: Cannot open PCM device alsa_pcm for capture. Falling back to playback-only mode
configuring for 44100Hz, period = 512 frames (11.6 ms), buffer = 3 periods
ALSA: final selected sample format for playback: 32bit integer little-endian
ALSA: use 3 periods for playback

Thanks,

Nahum.

j_e_f_f_g
Established Member
Posts: 1121
Joined: Fri Aug 10, 2012 10:48 pm

Re: Jack-Audio process callback time period

Post by j_e_f_f_g »

That's due to the way that ALSA's underlying code handles buffering differently than JACK does. (ie, JACK sits on top of ALSA, and does the mixing of all JACK app buffers into the ALSA driver's buffer, in realtime). And ALSA sets up the hardware to trigger an interrupt halfway through the playback of the driver's buffer.

I'm not sure why you're interested in knowing the rate at which your callback is being called, but you definitely should not be using it to synchronize anything to audio playback. For one thing, JACK is always buffering audio before that data is actually played back. And this buffering can vary depending upon a system's jack settings for buffer size and periods. Plus, jack has a second mode called "free-wheeling" in which jack tries to get as far ahead of the audio playback as it has buffer space. In this mode, jack may invoke your callback even faster than audio data is being played.

The above JACK messages indicate that you've configured JACK on your system (probably using a tool such as QJackQtl) for a period of 3. You've told JACK to swap between 3 "buffer pieces" -- not 2. So, JACK is trying to keep ahead of the audio card by 2 of your buffer pieces, while the audio card is playing a third buffer piece. Nevertheless, JACK's callback always asks you to fill in only 1 piece at a time.

nahumb
Established Member
Posts: 9
Joined: Mon Jul 30, 2018 8:51 am

Re: Jack-Audio process callback time period

Post by nahumb »

I'm interested in knowing the rate as my code is a realtime synthesizer application (like FluidSynth), so next audio block is calculated/processed soon after the previous one is delivered to JACK and this new block is delivered to JACK at the next interval to keep delay to a minimum.

I will look into making the 2 processes asynchronous and let the JACK sets all relevant parameters.

Yes, QJackQtl indeed sets the period to 3.

Thanks.

Nahum.

j_e_f_f_g
Established Member
Posts: 1121
Joined: Fri Aug 10, 2012 10:48 pm

Re: Jack-Audio process callback time period

Post by j_e_f_f_g »

nahumb wrote:
Thu Jan 14, 2021 10:55 am
My code is a realtime synthesizer application
Does it get loaded as an (LV2) plugin, or a standalone executable? Because if it's the latter, and latency (between a note being triggered, and the actual pitch being produced) is of utmost importance to you, then your best performance will be achieved using ALSA's MMAP mode, not JACK.

I make a realtime algorithmic auto-accompaniment program (think "Band in a Box") called BackupBand, and I use ALSA's MMAP mode for the best latency. I alternatively offer JACK support for those people who either don't care about latency (ie, they care more about realtime mixing/routing audio between standalone executables), or whose ears/brains aren't very adept at recognizing delays within the sub 10 millisecond range.

If you want to see how you can use either MMAP mode, or JACK, selected by the enduser via his Preferences setting, then you may want to peruse my source code at:

https://sourceforge.net/projects/backupband/files/

The code of interest is in AudioPlay.c. I profusely comment my source, so it should answer most questions you may have about it. But if you do have questions, feel free to ask.

For a lot more technical discussion of how the jack source code and APi (such as jack_activate) actually work (and why it's deliberately misleading when folks make the claim that JACK adds no latency above ALSA's MMAP mode), see my posts:

viewtopic.php?f=44&t=11101&p=41203&hili ... ate#p41203
viewtopic.php?f=24&t=12364&p=51590&hili ... ate#p51590

nahumb
Established Member
Posts: 9
Joined: Mon Jul 30, 2018 8:51 am

Re: Jack-Audio process callback time period

Post by nahumb »

Hi Jeff,

Wow, thank you so much for sharing your project.
Most certainly it will take me days to get in and learn what and how you do it.
Thanks.

And now for the bottom line - I have resolved the issue :-)

The fact that I get the JACK callback in a double rate was an issue I could not understand.
I have also noticed that when I start the Transport Rolling the QJackQtl play time display runs in a double speed.
I then played a YouTube video - double speed....

So I figure out it must be something with the audio card - and it was.
To make a long story short - wrong driver (I have several audio hats....).
Once the right driver was set, I get the callback every ~11msec and it all sounds perfect...
And for my novice musician ears, delay sounds OK with JACK.

Thank you for your support.

Nahum.

j_e_f_f_g
Established Member
Posts: 1121
Joined: Fri Aug 10, 2012 10:48 pm

Re: Jack-Audio process callback time period

Post by j_e_f_f_g »

Just for clarification, it's best not to change the buffer size, nor sample rate, that the enduser sets JACK to use. If you can instead use the "default" JACK settings, do that instead. (ie, Try to design your app so that it can work at the 4 sample rates of 44, 48, 88, and 96 Khz, and any buffer size).

Otherwise, if two (or more) apps have different rates/buffer sizes, then that will force JACK to do sample rate conversion, and/or extra buffer copying, on-the-fly. JACK is more efficient when all its running apps use the same settings.

Plus, there is some hardware that works much better at certain sample rates. For example, some Creative Labs cards have DACs that support only 48KHz rate. So that hardware has built-in circuitry to, for example, convert 44KHz to 48KHz on the fly -- and it doesn't sound as good. An enduser may want to always have his JACK apps use 48KHz. But if your app forces 44KHz, you've taken that option away from him.

Also, he may have set a particular group of JACK apps to always run on his system, and used QJackCtl to set a buffer size that is just large enough to avoid any underruns. If your app sets a different size, that could cause some extra copying of data when JACK tries to "resize" your "chunks" of data to flow down the app "graph".

tramp
Established Member
Posts: 1758
Joined: Mon Jul 01, 2013 8:13 am

Re: Jack-Audio process callback time period

Post by tramp »

j_e_f_f_g wrote:
Sun Jan 17, 2021 1:51 am
Otherwise, if two (or more) apps have different rates/buffer sizes, then that will force JACK to do sample rate conversion, and/or extra buffer copying, on-the-fly. JACK is more efficient when all its running apps use the same settings.
JACK don't do any sample rate conversation at all. If your app can't handle the given sample rate, you must implement a sample rate converter yourself.
On the road again.

nahumb
Established Member
Posts: 9
Joined: Mon Jul 30, 2018 8:51 am

Re: Jack-Audio process callback time period

Post by nahumb »

One more great input Jeff. Thank you.

I will modify it as follows (some of it is already implemented)

1. Sample-rate and buffer-size will be variables (not constants).
2. Default values will be initiated as default hardcoded values or per user last manual settings (see hereafter).
3. User will be able to select:
a. Manual settings: select values; application will set JACK.
b. Auto: application will get values from JACK.

Thanks,

Nahum

Post Reply