Re: [LAD] Realtime and helper threads

From: Olivier Guilyardi <ml@email-addr-hidden>
Date: Sat Aug 23 2008 - 15:56:03 EEST

Hi Dan,

why don't you answer on the mailing list?

Dan Mills wrote:
> On Fri, 2008-08-22 at 20:26 +0200, Olivier Guilyardi wrote:
>>
>> In Jackbeat I perform sample rate conversion using libsamplerate in the realtime
>> thread. I have recently realized that might be a mistake in regard to
>> performance. The SRC is used on audio samples which sample rate might differ
>> from the external (Jack) one, and also as a simple pitch shifter.
>
>
> <Snip>
>
>> In this regard, I thought about setting a (or several) non-RT helper thread(s)
>> up, where the heavy stuff would happen, and feed the converted content into the
>> RT thread through a ringbuffer. I understand that this approach would require
>> implementing a sync callback for the helper threads to get ready (fill buffers,
>> etc...) whenever the transport position changes.
>
> That is a fairly common approach, one thread per core is good. I have
> code that reads audio, sample rate converts it, time-stretches it if
> appropriate and sticks it in a ring buffer. The realtime thread does not
> pay any attention to the transport at all, it just handles the realtime
> controls (some mixing and routing in my case).

I am unsure what you mean by "core".

> One thing you do want to watch is that the disk IO threads should
> probably run at a realtime priority (just lower then the one for the
> audio thread), otherwise a make -j10 on the kernel can result in
> ringbuffer under run.

Disk IO is another problem to me. I would prefer to focus on computation load
here, that is: helper threads that performs audio conversion/transformation,
etc.... I assume that the thread priority you advise also concerns this though.

> There are a few details to making everything work right when you have
> more playbacks then available cores, and the approach does not work well
> if you need to vary things like timestretch in realtime.

Ah right, thanks, I had forgotten about this. Indeed, the good side of my
current approach (where the SRC is performed in the realtime thread) is that it
gives the user a good experience when varying the pitch: the effect is
immediate. So I'm not operating on live audio input, but I do handle live
"control" input, and in this regard the audio sample content is not exactly
known in advance anymore (since it is transformed according to realtime user
requests).

>> I'm asking this because the SRC computation load currently has an impact on the
>> output quality (ticks, xruns) with many tracks or on slower systems, and I'm
>> thinking about adding real pitch and time shifting using Rubberband in the near
>> future, which is certainly going to be a lot heavier.
>
> If you need to be able to vary the timestrtch in real time with a file
> playing, any ring buffer after the timestretcher will need to be short,
> otherwise it is fairly straightforward.

That worries me a bit. If my ringbuffer is really short, for responsive user
control, and the time stretching performed in a non-RT thread, isn't this going
to make things worse?

What about the following idea:

Say I make a Converter object, which performs time stretching. It doesn't know
anything about threading.

I also have a Reader object, with an internal ringbuffer, it reads raw audio
data, converts it using the Converter, and fills its ringbuffer with the
converted content.

The Reader objects exposes read(double time_ratio, int nframes) to the realtime
thread. When this function gets called, the Reader checks if it has data time
stretched according to this time ratio in its internal ringbuffer. If it does it
simply returns it. Otherwise, it calls the Converter on the fly, discarding the
irrelevant data in the ringbuffer, and causing a sudden small overhead.

Once the time ratio has stopped varying (the user has stopped playing with the
knob), the ringbuffer rapidly gets filled with data at the right time ratio, and
the overhead vanishes.

> Volatile is your friend as is pthread_mutex_trylock (Particularly handy
> if you have a vector of disk readers and a small handful of threads
> servicing them).

Thanks, I knew little about volatile, I've read some more about it, and already
fixed a possible bug in my code. Yes, I recently read about
pthread_mutex_trylock being acceptable in the realtime thread on the jack-devel
mailing list.

Regards,

-- 
  Olivier Guilyardi / Samalyse
_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@email-addr-hidden
http://lists.linuxaudio.org/mailman/listinfo/linux-audio-dev
Received on Sat Aug 23 16:15:05 2008

This archive was generated by hypermail 2.1.8 : Sat Aug 23 2008 - 16:15:06 EEST