2

I have modified the code provided by Tim Boldstad http://timbolstad.com/2010/03/16/core-audio-getting-started-pt2/ (may God bless him), and added a small slider to be able to change the output tone frequency form 40hz to 200000 hz. I now want to be able to use a LPF on the tone generated.

First of all, does any1 have a detailed guide which explains how to do this. I've tried simply adding a node in between, but it doesn't work, apparently, I need to convert 16 bit integer samples to the floating 8.24 format, before giving audio sample inputs to the filter, and then i have to convert it back to 16 bit integer. Is this the problem? or have i connected the node wrongly? Where am i supposed to set the filters cutoff frequency and other parameters?

Can anyone explain what AudioUnitGetProperty does? Apple documentation on these topics are EXTREMELY fragmented and utterly worthless :(

-(void) initializeAUGraph
{

OSStatus result= noErr;

    result = NewAUGraph(&mGraph);

    AUNode outputNode;
    AUNode mixerNode;
    AUNode effectsNode;

    AudioComponentDescription effects_desc;
    effects_desc.componentType = kAudioUnitType_Effect;
    effects_desc.componentSubType = kAudioUnitSubType_LowPassFilter;
    effects_desc.componentFlags = 0;
    effects_desc.componentFlagsMask = 0;
    effects_desc.componentManufacturer = kAudioUnitManufacturer_Apple;

    AudioComponentDescription mixer_desc;
    mixer_desc.componentType=kAudioUnitType_Mixer;
    mixer_desc.componentSubType=kAudioUnitSubType_MultiChannelMixer;
    mixer_desc.componentFlags=0;
    mixer_desc.componentFlagsMask=0;
    mixer_desc.componentManufacturer=kAudioUnitManufacturer_Apple;

    AudioComponentDescription output_desc;
    output_desc.componentType = kAudioUnitType_Output;
    output_desc.componentSubType = kAudioUnitSubType_RemoteIO;
    output_desc.componentFlags = 0;
    output_desc.componentFlagsMask = 0;
    output_desc.componentManufacturer = kAudioUnitManufacturer_Apple;

   result= AUGraphAddNode(mGraph, &output_desc, &outputNode);
   result= AUGraphAddNode(mGraph, &mixer_desc, &mixerNode);
    result=AUGraphAddNode(mGraph, &effects_desc, &effectsNode);

    result=AUGraphConnectNodeInput(mGraph, mixerNode, 0, effectsNode, 0);
    result=AUGraphConnectNodeInput(mGraph, effectsNode, 0, outputNode, 0);

    result=AUGraphOpen(mGraph);

    //getting mixxer

    result = AUGraphNodeInfo(mGraph, mixerNode, NULL, &mMixer);
    result = AUGraphNodeInfo(mGraph, effectsNode, NULL, &mEffects);

    UInt32 numbuses = 1;
    UInt32 size = sizeof(numbuses);
    result = AudioUnitSetProperty(mMixer, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &numbuses, size);


    //=====

    CAStreamBasicDescription desc;

    // Loop through and setup a callback for each source you want to send to the mixer.
    // Right now we are only doing a single bus so we could do without the loop.
    for (int i = 0; i < numbuses; ++i) 
    {

        // Setup render callback struct
        // This struct describes the function that will be called
        // to provide a buffer of audio samples for the mixer unit.
        AURenderCallbackStruct renderCallbackStruct;
        renderCallbackStruct.inputProc = &renderInput;
        renderCallbackStruct.inputProcRefCon = self;

        // Set a callback for the specified node's specified input
        result = AUGraphSetNodeInputCallback(mGraph, mixerNode, i, &renderCallbackStruct);

        // Get a CAStreamBasicDescription from the mixer bus.
        size = sizeof(desc);
        result = AudioUnitGetProperty(  mMixer,
                                      kAudioUnitProperty_StreamFormat,
                                      kAudioUnitScope_Input,
                                      i,
                                      &desc,
                                      &size);
        // Initializes the structure to 0 to ensure there are no spurious values.
        memset (&desc, 0, sizeof (desc));                               

        // Make modifications to the CAStreamBasicDescription
        // We're going to use 16 bit Signed Ints because they're easier to deal with
        // The Mixer unit will accept either 16 bit signed integers or
        // 32 bit 8.24 fixed point integers.

        desc.mSampleRate = kGraphSampleRate; // set sample rate
        desc.mFormatID = kAudioFormatLinearPCM;
        desc.mFormatFlags      = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
        desc.mBitsPerChannel = sizeof(AudioSampleType) * 8; // AudioSampleType == 16 bit signed ints
        desc.mChannelsPerFrame = 1;
        desc.mFramesPerPacket = 1;
        desc.mBytesPerFrame = ( desc.mBitsPerChannel / 8 ) * desc.mChannelsPerFrame;
        desc.mBytesPerPacket = desc.mBytesPerFrame * desc.mFramesPerPacket;

        printf("Mixer file format: "); desc.Print();
        // Apply the modified CAStreamBasicDescription to the mixer input bus
        result = AudioUnitSetProperty(  mMixer,
                                      kAudioUnitProperty_StreamFormat,
                                      kAudioUnitScope_Input,
                                      i,
                                      &desc,
                                      sizeof(desc));
    }

    // Apply the CAStreamBasicDescription to the mixer output bus
    result = AudioUnitSetProperty(   mMixer,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  0,
                                  &desc,
                                  sizeof(desc));

    //************************************************************
    //*** Setup the audio output stream ***
    //************************************************************

    // Get a CAStreamBasicDescription from the output Audio Unit
    result = AudioUnitGetProperty(  mMixer,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  0,
                                  &desc,
                                  &size);

    // Initializes the structure to 0 to ensure there are no spurious values.
    memset (&desc, 0, sizeof (desc));

    // Make modifications to the CAStreamBasicDescription
    // AUCanonical on the iPhone is the 8.24 integer format that is native to the iPhone.
    // The Mixer unit does the format shifting for you.
    desc.SetAUCanonical(1, true);
    desc.mSampleRate = kGraphSampleRate;

    // Apply the modified CAStreamBasicDescription to the output Audio Unit
    result = AudioUnitSetProperty(  mMixer,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  0,
                                  &desc,
                                  sizeof(desc));

    // Once everything is set up call initialize to validate connections
    result = AUGraphInitialize(mGraph);
}
Shawn
  • 21
  • 2

1 Answers1

0

Can anyone explain what AudioUnitGetProperty does?

Well, it gets the value of a property from an Audio Unit. A "property" is typically something you deal with as a programmer (e.g. audio stream format, connection state), whereas a "parameter" is usually something you expose to the user (e.g. low pass cutoff frequency, mixer volume). Notice that there are AudioUnitGetParameter and AudioUnitSetParameter functions to compliment the AudioUnitGetProperty and AudioUnitSetProperty functions.

You're basically expected to "just know" what an Audio Unit's properties / parameters are and what values they're expecting. The best source of documentation on this are two headers in AudioUnit.framework. Namely, AudioUnitProperties.h and AudioUnitParameters.h. The next best source is Xcode's autocomplete. For example, the AULowPass' parameters are kLowPassParam_CutoffFrequency and kLowPassParam_Resonance, so you can just type kLowPassParam and Xcode will show you what's available. The other AUs typically follow this scheme.

...but it doesn't work, apparently

I'm going to need more information. Do you mean you just can't hear the difference? The AULowPass starts with a very high cutoff frequency, so unless you set it something lower you probably won't hear any difference at all.

Try setting the cutoff frequency to something quite low, for example 500hz. You do that like this:

AudioUnitSetParameter(mEffects,
                      kLowPassParam_CutoffFrequency,
                      kAudioUnitScope_Global,
                      0,
                      500,
                      0);
admsyn
  • 1,431
  • 8
  • 19