• 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: Steps to Display A Microphone's Input Level
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Steps to Display A Microphone's Input Level


  • Subject: Re: Steps to Display A Microphone's Input Level
  • From: Simon Wolf <email@hidden>
  • Date: Tue, 25 Jan 2011 16:47:06 +0000

As a follow-up to my own message, I decided to use an AUGraph containing two AudioUnits, a HAL output and a multi channel mixer. I think that I have it all set up properly but I only ever get -120.0 returned as the decibel value of the kMultiChannelMixerParam_PreAveragePower parameter of the mixer.

When I call CAShow for my AUGraph once I've configured it I get:

AudioUnitGraph 0x11169000:
  Member Nodes:
	node 1: 'auou' 'ahal' 'appl', instance 0x810000 O I
	node 2: 'aumx' 'mcmx' 'appl', instance 0x810001 O I
  Connections:
	node   1 bus   1 => node   2 bus   0  [1 ch, 44100 Hz]
  CurrentState:
	mLastUpdateError=0, eventsToProcess=F, isRunning=F

Here's how I'm setting up the AUGraph:

In the header file I have:

  AUGraph mGraph;
  AudioUnit mAUHAL;
  AudioUnit mMixer;
  AudioStreamBasicDescription	mSourceDeviceFormat;
  AudioStreamBasicDescription	mCustomisedDeviceFormat;

In the implementation file I use this method to set the graph up:

- (BOOL)initializeAUGraph
{
  AUNode inputNode;
  AUNode mixerNode;

  OSStatus result = noErr;
  UInt32 size;

  // create a new AUGraph
  result = NewAUGraph(&mGraph);
  if (result) { printf("NewAUGraph result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // input unit
  AudioComponentDescription inputDesc;
  inputDesc.componentType = kAudioUnitType_Output;
  inputDesc.componentSubType = kAudioUnitSubType_HALOutput;
  inputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
  inputDesc.componentFlags = 0;
  inputDesc.componentFlagsMask = 0;

  // multichannel mixer unit
  AudioComponentDescription mixerDesc;
  mixerDesc.componentType = kAudioUnitType_Mixer;
  mixerDesc.componentSubType = kAudioUnitSubType_MultiChannelMixer;
  mixerDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
  mixerDesc.componentFlags = 0;
  mixerDesc.componentFlagsMask = 0;

  // create a node in the graph that is an AudioUnit, using the supplied component description to find and open that unit
  result = AUGraphAddNode(mGraph, &inputDesc, &inputNode);
  if (result) { printf("AUGraphAddNode AUHAL result %lu %4.4s\n", (unsigned long)result, (char *)&result); return NO; }
  result = AUGraphAddNode(mGraph, &mixerDesc, &mixerNode);
  if (result) { printf("AUGraphAddNode mixer result %lu %4.4s\n", (unsigned long)result, (char*)&result); return NO; }

  // open the graph -- AudioUnits are open but not initialized (no resource allocation occurs here)
  result = AUGraphOpen(mGraph);
  if (result) { printf("AUGraphOpen result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // grab audio unit instances from the nodes
  result = AUGraphNodeInfo(mGraph, inputNode, NULL, &mAUHAL);
  if (result) { printf("AUGraphNodeInfo AUHAL result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
  result = AUGraphNodeInfo(mGraph, mixerNode, NULL, &mMixer);
  if (result) { printf("AUGraphNodeInfo mixer result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // enable input, diable output
  UInt32 enableIO = 1;
  result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
  enableIO = 0;
  result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // get the current device
  AudioDeviceID inputDevice;
  size = sizeof(inputDevice);
  AudioObjectPropertyAddress theAddress;
  theAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice;
  theAddress.mScope = kAudioObjectPropertyScopeGlobal;
  theAddress.mElement = kAudioObjectPropertyElementMaster;
  result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, &size, &inputDevice);
  if (result) { printf("AudioObjectGetPropertyData DefaultInputDevice result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // set the current device as the AUHAL device
  result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Input, 1, &inputDevice, sizeof(inputDevice));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // set mixer's input bus count
 UInt32 numbuses = 1;
  result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &numbuses, sizeof(numbuses));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // enable metering
  UInt32 onValue = 1;
  printf("enable metering for input bus 0\n");
  result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Input, 0, &onValue, sizeof(onValue));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // retrieve the ASBD of the input
  size = sizeof(AudioStreamBasicDescription);
  //AudioStreamBasicDescription sourceStreamFormat;
  result = AudioUnitGetProperty(mAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &mSourceDeviceFormat, &size);
  if (result) { printf("AudioUnitGetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // set the stream format
  UInt32 audioChannels;
  audioChannels = MAX(mSourceDeviceFormat.mChannelsPerFrame, 2);

  int bytesPerSample = sizeof(AudioUnitSampleType);
  //AudioStreamBasicDescription	actualOutputFormat = {0};
  mCustomisedDeviceFormat.mChannelsPerFrame = 1;
  mCustomisedDeviceFormat.mSampleRate = mSourceDeviceFormat.mSampleRate;
  mCustomisedDeviceFormat.mFormatID = kAudioFormatLinearPCM;
  mCustomisedDeviceFormat.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
  mCustomisedDeviceFormat.mBitsPerChannel = 8 * bytesPerSample;
  mCustomisedDeviceFormat.mBytesPerFrame = bytesPerSample;
  mCustomisedDeviceFormat.mFramesPerPacket = 1;
  mCustomisedDeviceFormat.mBytesPerPacket = bytesPerSample;

  // Set the AudioOutputUnit output data format
  result = AudioUnitSetProperty(mAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &mCustomisedDeviceFormat, sizeof(AudioStreamBasicDescription));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
//  result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &actualOutputFormat, sizeof(AudioStreamBasicDescription));
//  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }
  result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &mSourceDeviceFormat.mSampleRate, sizeof(mSourceDeviceFormat.mSampleRate));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // connect the outputs to the inputs
  result = AUGraphConnectNodeInput(mGraph, inputNode, 1, mixerNode, 0);
  if (result) { printf("AUGraphConnectNodeInput AUHAL result %lu %4.4s\n", (unsigned long)result, (char*)&result); return NO; }
//  result = AUGraphConnectNodeInput(mGraph, mixerNode, 0, inputNode, 0);
//  if (result) { printf("AUGraphConnectNodeInput mixer result %lu %4.4s\n", (unsigned long)result, (char*)&result); return NO; }

  // now that we've set everything up we can initialize the graph, this will also validate the connections
  result = AUGraphInitialize(mGraph);
  if (result) { printf("AUGraphInitialize result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // get the number of frames in the IO buffer(s)
  size = sizeof(UInt32);
  result = AudioUnitGetProperty(mAUHAL, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, &mAudioSamples, &size);
  if (result) { printf("AudioUnitGetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  // allocate the audio buffers
  mAudioBuffer = [self allocateAudioBufferListWithNumChannels:mCustomisedDeviceFormat.mChannelsPerFrame size:mAudioSamples * mCustomisedDeviceFormat.mBytesPerFrame];
  if (mAudioBuffer == NULL) {
    printf("AudioBufferAllocationFailed.\n");
    return NO;
  }

  // set up the callback
  AURenderCallbackStruct rcbs;
  rcbs.inputProc = renderMixerOutput;
  rcbs.inputProcRefCon = self;
  result = AudioUnitSetProperty(mAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Output, 0, &rcbs, sizeof(AURenderCallbackStruct));
  if (result) { printf("AudioUnitSetProperty result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); return NO; }

  CAShow(mGraph);

  return YES;
}

I try to retrieve the mixer level via a method invoked by a timer:

- (CGFloat)getMeterLevel
{
  OSStatus result = noErr;

  Float32 value = 0.0;
  result = AudioUnitGetParameter(mMixer, kMultiChannelMixerParam_PreAveragePower, kAudioUnitScope_Input, 0, &value);
  if (result) { printf("AudioUnitGetParameter kMultiChannelMixerParam_PostAveragePower Input result %ld X %4.4s\n", (long)result, (unsigned int)result, (char*)&result); }

  return value;
}

Possible things to note:

1. I have a callback defined for the AUHAL's AudioUnit which I will use to write the audio out to a file.
2. I have both explicitly set the output stream format of the AUHAL AudioUnit and also just tried setting the sample rate. At the moment the latter is the version used in the above code.
3. I have tried connecting the mixer node's output back into the AUHAL node's output but this is currently commented out in the code.

I'm not getting any errors or warnings so I'm now very confused. I'm wondering if it is something to do with having my AUHAL's output disabled (I've done this because I don't want to feed the input from a microphone back out through the speakers and also because most microphones are not duplex devices.

Any pointers or suggestions someone can give would be really, really appreciated because I've now been struggling with this for a few days,

Many thanks,

Simon



On 17 Jan 2011, at 13:07, Simon Wolf wrote:

> Hi. I'm a complete newcomer to Core Audio and as such I'm learning a lot and scratching my head in equal measures. I've created a test application which records audio from an input source (and allows the source to be selected) using AUHAL. What I'd like to do next is display the input level of the input device but I'm at a loss as to the best way of doing this so I'm hoping that someone can give me a pointer in the right direction, essentially a rough outline of what I need to set up.
>
> I have a feeling that I may have set off at too low a level and would be better off using an audio queue to do the recording but before I start over I wanted to see if anyone could give me some advice on where I should be focusing my investigations.
>
> This is all being done on OS X 10.6.
>
> Many thanks.
>
> Simon Wolf
>
> Website: http://www.ottersoftware.com
> Twitter: http://www.twitter.com/sgaw
> iChat: email@hidden _______________________________________________
> 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

 _______________________________________________
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: 
 >Steps to Display A Microphone's Input Level (From: Simon Wolf <email@hidden>)

  • Prev by Date: Re: SimpleSDK Location?
  • Next by Date: latency on sidechain bus
  • Previous by thread: Steps to Display A Microphone's Input Level
  • Next by thread: Re: Steps to Display A Microphone's Input Level
  • Index(es):
    • Date
    • Thread