Re: Open source mixer AU proposal
Re: Open source mixer AU proposal
- Subject: Re: Open source mixer AU proposal
- From: James Chandler Jr <email@hidden>
- Date: Fri, 8 Aug 2003 14:07:25 -0700
On Friday, August 8, 2003, at 08:13 AM, Robert Grant wrote:
What I'm looking for is a mixer that is somewhat akin to real-world
mixers. I want:
Stereo/mono inputs
per input:
input gain fader
input balance/pan (balance for stereo, pan for mono)
send levels
pre/post fader switches for the sends (not essential but nice to
have)
Some basic EQ (lo/mid/hi) would also be nice but not essential
multiple stereo effect send busses (say 4)
Effect Return busses if it's technically feasible (see below)
Stereo master out.
As I've demonstrated here many times I'm not talented enough to build
this myself or even have much idea about how to get started. So I'm
interested in working on a SourceForge type project with a BSD-type
license (because I want to build commercial apps with it) with a few
others - I'd probably be able to fill in some of the blanks :-). It
wouldn't need a GUI I think because hosts would happily provide their
own (especially if it is often coupled with the Stereo mixer).
Hi Robert
I'm very ignorant on CoreAudio, so far have only learned a bit about
CoreMIDI. My suggestions might be entirely the wrong way on CoreAudio.
The way I do a Mixer on PC--
The lowest level is an assortment of asm tight loops for various mixing
functions. Since PC (at least in our code) frequently uses interleaved
stereo files, there are dedicated asm functions for MixMonoToMono,
MixMonoToStereo (for mono tracks which must be panned into a stereo
buss), MixStereoToStereo, etc. There are also special variants for
various built-in format conversions, so 16 bit integer buffers can for
instance be mixed to a float output buffer without the higher-level
code having to make sure all the audio is in float format before
entering the mixer.
Perhaps format conversions would be unnecessary in a CoreAudio
implementation where all streams are assumed to be float... Similarly,
perhaps interleaved stereo variants would be unnecessary if stereo is
always handled in CoreAudio with a pair of Mono streams. Hey, already
said I'm ignorant of CoreAudio!
One might write a single tight-loop asm buffer-mixing function that
would handle all the possible format differences. Might be the
desirable way to do it. My coworker who writes the audio sequencing
code and the mixer outer loop, wanted separate lean-n-mean functions,
so he could optimize at a higher level when feeding the mixer.
Sometimes it isn't wise to put unnecessary conditionals in tight loops.
The low-level mix functions take pointers to input and output buffers,
and left/right gain multipliers.
Our implementation uses two aux stereo busses and a stereo main mix
buss, but one could fairly easily make a mixer object with arbitrary
number of aux send/return and master outputs.
We have an object which maintains a graph of up to 4 audio plugins. The
mixer object instantiates a four-filter graph object for each track,
though if a graph doesn't contain any plugins it just passes the buffer
from input to output without doing anything. EQ or any other plugin can
be inserted in the graph slots. Each filtergraph object has provisions
for mute/bypass, so individual plugins in each graph can be bypassed by
the user without having to remove the plugin from the graph.
Aux returns and the Master output are treated like tracks, each with
its own insert filtergraph. The Aux returns are mixed into the main
output just like Tracks, except the input to the Aux insert
filtergraphs comes from the aux busses. There is also an insert
filtergraph on the master output buss, for global plugins like EQ or
PeakLimit.
When we add softsynth plugin capability, we hope to mix them just like
any other track, except the softsynth will just be the first plugin in
a Track's insert filtergraph.
The mixer loop gets called to render each audio output buffer, after
input track buffers have been fetched--
Here is possible simple pseudocode assuming stereo interleaved Tracks
and an arbitrary number of Aux Busses. It would require added code to
support solo/mute or whatever.
NumTrks = NumberOfInputTracks + NumberOfAuxReturns + 1;
//every slot in the mixer is a track, including Aux returns and
Master out
MasterIndex = NumTrks - 1;
//array index of the master buss
//The mixer output is retrieved from TrkBuffer[MasterIndex]
Aux1Index = MasterIndex - NumberOfAuxReturns
//array index of the first Aux Return
Array of Track input audio buffers-- TrkBuffer[NumTrks]
Array of LeftGain[NumTrks] and RightGain[NumTrks]
//multiplier factors for track left/right gain
//Pan knobs are pre-calculated into LeftGain and RightGain values
in the Mixer UI code
Array of AuxSendGain[NumberOfAuxReturns]
//Aux Send multiplier factors
Array of PostFaderBool[NumberOfInputTracks]
//True if Aux Send is PostFader, False if Aux Send is PreFader
Array of FilterGraphs-- FilterGraphArray[NumTrks]
for (Trk = Aux1Index; Trk <= MasterIndex; ++Trk)
{
ZeroTheTrack(TrkBuffer[Trk]);
//Fill mix destination buffers with zero
}
for (Trk = 0; Trk < NumTrks; ++Trk)
{
CallFilterGraph(FilterGraphArray[Trk], TrkBuffer[Trk],
TrkBuffer[Trk])
//Call plugin insert chain, placing the filtergraph output back
into TrkBuffer
MixStereoToStereo(TrkBuffer[Trk], TrkBuffer[MasterIndex],
LeftGain[Trk], RightGain[Trk]);
//Mix the Track or Aux buffer into the master output
//if Trk == MasterIndex, it applies the final master gain
slider to the output buss in-place
if (Trk >= Aux1Index) //Don't mix Aux back into Aux, or Master back
into Master
continue;
for (i = Aux1Index; i < MasterIndex; ++i) //mix tracks to Aux Sends
{
if PostFaderBool[Trk] //PreFader patching
MixStereoToStereo(TrkBuffer[Trk], TrkBuffer[i],
LeftGain[Trk] * AuxSendGain[i], RightGain[Trk] * AuxSendGain[i]);
else //PostFader patching
MixStereoToStereo(TrkBuffer[Trk], TrkBuffer[i],
AuxSendGain[i], AuxSendGain[i]);
}
}
Conveniently ignoring the probable numerous logic mistakes, this will
mix all the tracks to the master and aux busses.
The last few iterations apply insert effects to the aux busses, mix aux
returns to the master, and finally the last iteration will apply master
insert effects and then apply the master gain.
It seems like a lot of rigamarole to go thru. Perhaps there are simpler
more efficient strategies. However, its amazing how well the code runs
on a modestly-fast computer.
James Chandler Jr.
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.