Re: Any system calls OK to use in audio thread?
Re: Any system calls OK to use in audio thread?
- Subject: Re: Any system calls OK to use in audio thread?
- From: Brian Willoughby <email@hidden>
- Date: Mon, 26 Feb 2018 20:07:52 -0800
I never understood why “rewriting” samples was ever considered a good design
choice. As I recall, DirectSound employs this technique.
The big problem here is that you’re assuming you have enough CPU to write the
same sample slots more than once. Most modern users expect to be able to
dedicate nearly 100% of the available CPU to meaningful audio calculations. If
there were ever enough CPU cycles to afford going back to invalidate and
rewrite samples on the fly, then those users would simply crank up the number
of plugins and/or the complexity of the synthesis until no spare cycles are
left. In other words, you can’t rely on being given an opportunity for a “do
over” when it comes to audio.
Basically, the best design choice that meets customer expectations is to assume
in your code that you only have one chance to write a given sample slot.
Reducing latency between parameter updates and audible results simply requires
smaller buffers at the hardware level.
In response to your earlier question, I was going to say that shifting audio
processing to another thread and then feeding the results to the audio thread
via a ringbuffer doesn’t actually give you any more time. There is still a hard
limit for real time audio. Whatever time duration is represented by the audio
buffer (given the sample rate and buffer size), that’s all the time you have
for audio processing. Non-audio threads can’t run any faster than the audio
thread. The only exception is, as Paul points out, those cases where audio is
coming from non-real-time sources like disk I/O or perhaps network streaming.
In the latter cases, having a non-audio-thread buffering scheme is a good idea
(and necessary, since disk I/O cannot occur on the audio thread).
There are probably some special cases like convolution reverb where you can
benefit from processing some of the algorithm on a separate thread that feeds
the audio thread. But there will still be a requirement that low-latency
processing be handling in the audio thread itself, without forgetting that
low-latency processing must be bounded by the amount of CPU processing
available in each audio time slot.
I suppose we should also consider the cases where multi-threaded processing
could potentially run faster than the audio thread, in which case feeding the
audio thread via a ringbuffer could allow a lot more processing. Note that
latency is nearly always increased in these situations.
In contrast, if you have an audio application with basically no real-time
requirements, e.g., iTunes playback, then you could easily process all audio in
a separate thread and feed the finished results to the audio thread with a ring
buffer. I believe that iTunes computes the crossfades between tracks in advance
- it’s rather entertaining to listen to the audio glitches that occur when
seemingly innocuous edits to the playlist trigger iTunes’ heuristics to
recalculate that crossfade. iTunes used to be a glitch-free playback system,
but there have been so many features tacked on that it has become unreliable.
Brian
On Feb 26, 2018, at 7:46 PM, Brian Armstrong <email@hidden>
wrote:
> Thanks, that makes sense.
>
> Even in the example you suggested, couldn't the producer invalidate/rewrite
> the samples in the ring on parameter change? If the consumer reads front to
> back, and producer writes back to front, then the change will occur at some
> indeterminate point in the stream but will be applied consistently after
> that. Assuming correct memory fences anyway, I think.
>
> Brian
>
> On Mon, Feb 26, 2018 at 7:36 PM Paul Davis <email@hidden> wrote:
>> On Mon, Feb 26, 2018 at 9:16 PM, Brian Armstrong
>> <email@hidden> wrote:
>>> As a related question, is there any reason not to just feed the audio
>>> thread with a ringbuffer filled on a different thread? You could manage
>>> pointers either with try-lock or atomics.
>>
>> that's exactly what you're supposed to do. and what just about every
>> correctly implemented audio application does.
>>
>> except that processing needs to happen in the audio thread to minimize
>> latency. imagine the user tweaks the parameter of a plugin. they expect to
>> hear the result ASAP. if you pre-process the audio before it hits the audio
>> thread, you can't ensure that. so, you disk i/o and other
>> non-latency-dependent processing outside the audio thread, write to the
>> buffer; audio thread reads from it, runs plugins and the rest, delivers to
>> the "hardware" (you don't have access to the hardware with coreaudio, but
>> the concept is the same).
>>
>> you don't need locks on a single-reader/single-writer circular buffer. you
>> do need to ensure correct memory ordering.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden