• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Ducking
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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>)

  • Prev by Date: Re: Ducking
  • Next by Date: Apple's AudioUnits and their busses
  • Previous by thread: Re: Ducking
  • Next by thread: Apple's AudioUnits and their busses
  • Index(es):
    • Date
    • Thread