Re: Ducking
Re: Ducking
- Subject: Re: Ducking
- From: Brian Willoughby <email@hidden>
- Date: Mon, 20 Oct 2008 03:17:51 -0700
On Oct 20, 2008, at 02:19, John Clayton wrote:
On 20/10/2008, at 10:06 AM, Brian Willoughby wrote:
What you've described differs from the above because it would
combine more than one control signal (i.e. every signal that you
have marked as 'isAutoDucking'); the amount of ducking would be a
proportion of the primary signal but not the control signal(s);
and there would be a random delay in the effect depending upon the
buffer boundaries.
I was thinking of 'mixing' all the data coming from the non-ducked
tracks into a singleton class instance (although it feels hackish
to me in this form - because that ties my components very tightly
together - not something I necessarily love - and that is certainly
the value of an AUGraph based approach).
We haven't really been discussing any class hierarchy, so I won't
comment on whether you should use a singleton class or some other
arrangement. However, in some respects you are designing an
application with global behavior, so using a singleton class would
not necessarily be a bad idea or in any way contrary to enforcing a
desired global behavior. If you are using Cocoa, then the
application object or its delegate would suffice - and those are
effectively singletons.
A mixer AU in an AUGraph would not even require new code, though, so
you wouldn't have to write a new class.
I'd imagine that I would collect a one-frame union of all non-
ducked audio - a bit like one really large union of all of the
signals. Any zeroes within this 'union' would represent silence,
anything else represents noise/audio - and I could drive ducking
from that union in the pre-render #2 call.
That seems a bit awkward - perhaps too simple - depending upon how
you end up using the data later.
By the way, I presume a 'bus' and a 'side chain' are in effect the
same thing, correct?
Not precisely. In the world of mixers, a 'bus' implies any number of
audio channels mixed together, although the bus might group things
into mono, stereo, or surround. A 'side chain' is a term from the
external effects processor world, and refers to an input that is not
generally heard as part of the output, but it still used for some
purpose. Effects generally require patch cables, and would have
distinct input(s) for the side chain.
In the case of an AudioUnit, there is more of a connection between
'bus' and 'side chain' than in the above contexts from the physical
world. AudioUnits arrange inputs and outputs so that the channels
are grouped into busses. There might be any number of mono, stereo,
surround, or other multichannel busses, while input and output may
match in bus/channel counts or they may be dissimilar. To (properly)
implement a ducking effect in the AudioUnit world, you would have a
minimum of two input busses and one output bus. The primary input
bus would probably be stereo, and the control signal input bus might
be mono or stereo. The output bus would be stereo, or would match
the primary input bus. The control signal in this arrangement is
usually called a 'side chain' and for an AudioUnit this would also
correspond to a bus (higher number bus than the first, primary bus).
In my first email, I meant 'bus' in the mixing terminology, referring
to the fact that you would want to mix all of the control signals
together before sending them to the 'side chain' input. In the mixer
world, a bus implies the ability to mix lots of channels already, but
in the CoreAudio world you would have to use a mixer AU to combine
several signals before you could send them to the 'side chain' input
bus of a ducking AU. In other words, you don't get mixing for free
in AUGraph just by assigning things to the same bus - in fact you
cannot assign multiple signals to the same place unless you use and
AU mixer to combine them first. I hope this is making some sense - I
apologize for mixing music industry terms with CoreAudio and
AudioUnit terminology.
I think you could improve your design by using AUGraph to create a
bus. You would then mix all of the control signals
('isAutoDucking') onto this bus. From then on, you could use a
normal ducking plugin (*) which has a side-chain input for the
control signal. Processing on the audio would then be continuous,
not broken into buffer chunks or otherwise delayed. If you still
prefer the amount of ducking to be a percentage of the primary
(which would effectively be a constant dB drop), then you could
implement more of a gate dynamic with a threshold. Otherwise, you
could implement a standard ducker where the amount of ducking is
proportional to the control signal (instead of the primary signal).
Agreed - I believe its also a more elegant approach, and its use
eliminates the need to have a specific pre-render notification in
place to process the control signals.
In my estimation, your problem will not be pre-render notification
#1, but pre-render notification #2. You have to find a way to alter
the gain based on the analysis. I see that you're using
AUDynamicsProcessor, but how do you plan on getting it to do what you
want? Are you going to manually set the gain with parameter change
messages? That would certainly introduce granularity in the
results. And, if you're using parameter changes, then you really
don't need anything as fancy as AUDynamicsProcessor. Any AU with at
least one gain parameter would suffice.
But whether I use an Audio Unit (my own, ref: your *) or pre-render
notifications (ref: my design, pre-render #1) - the data flow is
the same, no? The ducker would be processing buffers of audio and
generating a series of signals (one buffer wide), and isn't it
irrelevant whether this is a 'pre-render notification #1' or an
Audio Unit? Either way, the consumer of that signal would still be
likely to get the signal after at least one data frame of delay.
Since your first message, I have assumed that you would be
controlling the AUDynamicsProcessor by sending parameter change
messages. That's the only way I can think of that your design would
work. And, you're right, in that case there would be some
granularity, and it would happen on buffer boundaries if that's where
you do your parameter updates.
However, the data flow is not the same in your design versus mine.
In my design, the AU which implements ducking has the option of
processing gain differently for every individual sample. A ducking
AU would have synchronous buffers from both the primary audio input
bus and the control signal / side-chain bus, and thus could match up
individual samples between the two. The caveat is that we're talking
about dynamics, and the volume or intensity of a signal, and that
necessarily involves a moving average value of a signal over a time
frame much longer than one sample. But there are ways to implement
such averaging code so that it is not constrained to the buffer sizes
or jumping along buffer boundaries.
In other words, with a proper CoreAudio design involving AUGraph and
AudioUnits, there would not be a data frame of delay between control
signals and the primary signals being ducked. There would be a
slight delay due to the time averaging of the control signals, but
that is equally present in analog processing which is not buffer-based.
The connectivity of Audio Units either directly or via an AUGraph
is probably my weakest point in terms of experience - so I'm more
than happy to have criticism here.
If you understand AUGraph, then it's always going to be less code to
connect AudioUnits with it. That's provided you already have all the
AudioUnits you need. If you need new audio processing that is not
part of an existing AU, then there might be some cases where you can
directly connect other AudioUnits to your audio processing code, but
I say it would still be helpful to become familiar with all that
AUGraph can do. You have the choice of putting new code into a new
custom AU, or to just weave it in the graph. I have a hunch, though,
that implementing ducking code would be a lot more trouble with
direct callbacks than with a real AU.
It might take some tricky AUGraph design to get this to work,
since you'd be mixing a bunch of control signals together before
you could process any of the ducked signals (which I am calling
primary signals, for lack of another word).
And its this exact point where I start to ask myself the question:
how can I ensure that :
a) the control signals don't go further - I suppose if I wrote my
own AU then I can simply take the input on the bus, process it and
then throw it away
A ducking AU with 2 inputs busses and 1 output bus would consume the
2nd input bus without allowing it to go any further. You pretty much
need a ducking AU no matter what design you choose.
b) timing - can I ensure that the control signals get processed
before the ducked signals
The AUGraph should handle this. All of CoreAudio is a pull model.
The AUHALOutput will pull from your mixer that combines all audio,
one source of which will be the ducking AU. The ducking AU will then
pull from all of the control signals. But all of this only works if
you make the AUGraph connections correctly. That's the key.
Then you would mix all of the control signals and primary signals
into the final audio output (**). In other words, such a graph
would involve some amount of carefully directed feedback, so I'm
not sure what sorts of problems you might run into with AUGraph if
you make any mistakes with the feedback routing.
Oh wait - perhaps I'm thinking too procedurally here. (sound of
pin dropping?) You're suggesting that the control signals are in
fact the 'non-ducked' audio? That they are not some extra logical
control that a process/loop uses to manipulate the audio data -
they *are* the manipulated audio data.
Yes. The control signals are the non-ducked audio. You mix them all
together (into a mono or stereo sum), then feed it to the ducking
AU. The ducking AU is written to take an audio signal and derive
dynamic gain control. So you'd be using a standard mixer to combine
multiple non-ducked audio signals into one control signal bus. But
you still need a custom AU for ducking.
Again, I'm assuming that AUDynamicProcessing does not have a side-
chain input or any kind of ducking features, but I have not
investigated this.
Brian Willoughby
Sound Consulting
_______________________________________________
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
References: | |
| >Ducking (From: John Clayton <email@hidden>) |
| >Re: Ducking (From: Brian Willoughby <email@hidden>) |
| >Re: Ducking (From: John Clayton <email@hidden>) |