Re: How to route channels from SynthUnit to a multi-channel device? <solved>
Re: How to route channels from SynthUnit to a multi-channel device? <solved>
- Subject: Re: How to route channels from SynthUnit to a multi-channel device? <solved>
- From: michael markert <email@hidden>
- Date: Thu, 22 Sep 2005 15:49:32 +0200
Hello to all,
first of all: thanks for your answers.
After struggeling for a (much too long) time with the matrixMixer, I
wanted to post my current code-snippets to this list, because there
is really not much documentation available...
I use the MatrixMixer to route my synth-output channels to different
device-channels.
The main difference to the MatrixMixerTest.xcodeproj is the fact,
that I don't use any Line-In-Audiostream (like all the examples I
could find) but rather a Synth/EffectNode.
Therefore all the render-calls in the MatrixMixer example are
unnecessarily for this case.
Synth Node
||
||
Effect Node
||
MatrixMixer
|| || ||
|| || ||
|| || ||
Output Node (CH 0/1 -OR- CH 2/3 -OR- CH 4/5)
The first thing I struggled with, was to use the Public Utilities in
CA-SDK:
I tried the MatrixMixerExample from the CoreAudioSDK, but it needs
"CAStreamBasicDescription.h" ...and whenever I add these two files
to my project, it doesn't compile anymore with a bunch of errors:
Doug Wyatt pointed me to the right direction: Changing the fileType
of my controller-source to "sourcecode.cpp.objcpp" (in the info-
panel) or renaming the controllerObject to *.mm (instead of *.m)
solved this problem.
The next thing I struggled upon were the volume-values.
I still don't really understand why I have to use an Float32 with an
integer "1". All other values (like "1.0" or "0.8" result in a
distorted audioSignal. But nevertheless, here is the code which is
behaving like expected. I am no super-programmer, so if there are
errors (and I'm sure there are plenty :) – feel free to emend!
This is really just to provide some more infos on this topic and
maybe help someone struggeling like me finding the solution a bit
faster...
@interface: {
AudioDeviceID deviceID;
UInt32 outChannels;
int outChannelPair;
AUGraph graph;
AUNode synthNode, effectNode, mixerNode,
outputNode;
ComponentDescription selectedEffect;
ComponentDescription selectedSynth;
}
const Float64 kGraphSampleRate = 44100.;
@implementation:
-(void)setupAudio {
OSStatus result = noErr;
UInt32 size = sizeof(UInt32);
NewAUGraph(&graph);
// select default synth and effect
// leaving some things out here... setup synth & effect
component...
// synth node
AUGraphNewNode(graph, [self synthComponentDescription], 0, NULL,
&synthNode);
// effect node
AUGraphNewNode(graph, [self effectComponentDescription], 0,
NULL, &effectNode);
ComponentDescription desc;
// mixer node
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentType = kAudioUnitType_Mixer;
desc.componentSubType = kAudioUnitSubType_MatrixMixer;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AUGraphNewNode(graph, &desc, 0, NULL, &mixerNode);
// output node
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AUGraphNewNode(graph, &desc, 0, NULL, &outputNode);
// open graph
AUGraphOpen(graph);
// get outputUnit
AudioUnit outputUnit;
AUGraphGetNodeInfo(graph, outputNode, NULL, NULL, NULL,
&outputUnit);
// get current output device id (deviceID)
size = sizeof(deviceID);
AudioUnitGetProperty(outputUnit,
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Output,
1, &deviceID, &size);
// get available output channels (UInt32 outChannels)
result = AudioDeviceGetPropertyInfo(deviceID, 0, false,
kAudioDevicePropertyPreferredChannelLayout,
&size, NULL);
if(result != noErr) {
outChannels = 2; // default to first two busses
} else {
AudioChannelLayout *layout = NULL;
layout = (AudioChannelLayout *)calloc(1, size);
if(layout != NULL) {
result = AudioDeviceGetProperty(deviceID, 0, false,
kAudioDevicePropertyPreferredChannelLayout,
&size, layout);
if(layout->mChannelLayoutTag ==
kAudioChannelLayoutTag_UseChannelDescriptions) {
// no channel layout tag is returned, so iterate
through chDescriptions
if(layout->mNumberChannelDescriptions == 2) {
outChannels = 2;
} else {
outChannels = 0;
UInt32 i;
for(i=0; i<layout->mNumberChannelDescriptions; i+
+) {
if(layout->mChannelDescriptions
[i].mChannelLabel != kAudioChannelLabel_Unknown) {
outChannels ++;
}
}
}
} else {
switch (layout->mChannelLayoutTag) {
case kAudioChannelLayoutTag_AudioUnit_5_0:
case kAudioChannelLayoutTag_AudioUnit_5_1:
case kAudioChannelLayoutTag_AudioUnit_6:
outChannels = 5;
break;
case kAudioChannelLayoutTag_AudioUnit_4:
outChannels = 4;
default:
outChannels = 2;
}
}
free(layout);
}
}
if(debugMode) NSLog(@"found %i channels", outChannels);
// setup MatrixMixer
AudioUnit mixerUnit;
AUGraphGetNodeInfo(graph, mixerNode, NULL, NULL, NULL, &mixerUnit);
CAStreamBasicDescription streamDesc;
// set BusCount
UInt32 inChannels = 2;
UInt32 numbusses = inChannels / 2;
result = AudioUnitSetProperty(mixerUnit,
kAudioUnitProperty_BusCount,
kAudioUnitScope_Input,
0, &numbusses, sizeof(UInt32));
numbusses = outChannels / 2;
result = AudioUnitSetProperty(mixerUnit,
kAudioUnitProperty_BusCount,
kAudioUnitScope_Output,
0, &numbusses, sizeof(UInt32));
// set input stream format
size = sizeof(streamDesc);
result = AudioUnitGetProperty(outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0, &streamDesc, &size);
streamDesc.SetCanonical(2,false);
streamDesc.mSampleRate = kGraphSampleRate;
size = sizeof(streamDesc);
result = AudioUnitSetProperty(mixerUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0, &streamDesc, sizeof(streamDesc));
streamDesc.SetCanonical(outChannels,false);
result = AudioUnitSetProperty(mixerUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
0, &streamDesc, sizeof(streamDesc));
// connect nodes
AUGraphConnectNodeInput(graph, synthNode, 0, effectNode, 0);
AUGraphConnectNodeInput(graph, effectNode, 0, mixerNode, 0);
AUGraphConnectNodeInput(graph, mixerNode, 0, outputNode, 0);
// initialize graph
AUGraphInitialize(graph);
// leaving the MIDI synth connections out for clearifying
reasons...
// map to output bus #1
[self mapOutputToChannels:0];
}
-(IBAction)outputChannelsSelected:(id)sender {
[self mapOutputToChannels:(int)[sender indexOfItem:[sender
selectedItem]]];
}
-(void)mapOutputToChannels:(int)pairIndex {
CAStreamBasicDescription desc;
OSStatus result = noErr;
UInt32 inChannels = 2;
UInt32 i,j;
AudioUnit mixerUnit;
AUGraphGetNodeInfo(graph, mixerNode, NULL, NULL, NULL, &mixerUnit);
// set volumes
UInt32 element;
Float32 mixVolume = 1;
// set input volumes
for(i=0; i<inChannels; ++i) {
element = i;
result = AudioUnitSetParameter(mixerUnit,
kMatrixMixerParam_Volume,
kAudioUnitScope_Input,
element, mixVolume, 0);
}
// set output volumes
for(i=0; i<outChannels; ++i) {
element = i;
result = AudioUnitSetParameter(mixerUnit,
kMatrixMixerParam_Volume,
kAudioUnitScope_Output,
element, mixVolume, 0);
}
// set crosspoint volume
i = 0;
j = 0;
for(j=0; j<outChannels; j=j+2) {
// we assume to have a stereo input (0/1) only
if(j == pairIndex * 2) {
mixVolume = 1;
} else {
mixVolume = 0;
}
// set left channel
element = 0 << 16 | j & 0x0000FFFF;
result = AudioUnitSetParameter(mixerUnit,
kMatrixMixerParam_Volume,
kAudioUnitScope_Global,
element, mixVolume, 0);
// set right channel
element = 1 << 16 | (j+1) & 0x0000FFFF;
result = AudioUnitSetParameter(mixerUnit,
kMatrixMixerParam_Volume,
kAudioUnitScope_Global,
element, mixVolume, 0);
}
// set master volume
result = AudioUnitSetParameter(mixerUnit,
kMatrixMixerParam_Volume,
kAudioUnitScope_Global,
0xFFFFFFFF, 1, 0);
if(debugMode) {
NSLog(@"---- channel info for AU %@ ----", [self name]);
PrintMatrixMixerVolumes(NULL,mixerUnit); // i found it
useful to change the "MatrixMixerVolumes.h" from the PublicUtility to
print it's contents to the RunLog than writing into a file
NSLog(@"-------------------------------------");
}
// select menuItem
[outputChannelsPopup selectItemAtIndex:outChannelPair];
}
_______________________________________________
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