0

Just started learning and testing with the iOS AudioUnit framework and made a multichannel mixer with a render callback function in bus 0. In the callback function I synthesize a sound like so:

OSStatus RenderTone(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const     AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList   *ioData) {
    const double amplitude = 0.5;

    iPadAudioViewController *viewController = (__bridge iPadAudioViewController *)inRefCon;

    double phase = viewController->phase;
    double phase_increment = 2.0 * M_PI * viewController->frequency / viewController->sampleRate;
    const int channel = 0;
    Float32 *buffer = (Float32 *)ioData->mBuffers[channel].mData;

    for (UInt32 frame = 0; frame < inNumberFrames; frame++) {
        buffer[frame] = sin(phase) * amplitude;

        phase += phase_increment;
        if (phase > 2.0 * M_PI) {
            phase -= 2.0 * M_PI;
        }
    }

    viewController->phase = phase;

    return noErr;
}

What if I wanted to synthesize more sounds in a variable amount of other busses of the multichannel mixer with different values for phase/frequency etc?

I haven't yet found any information on this on Google or the iOS documentation.

Hope someone can get me in the right direction

Youri
  • 38
  • 1
  • 6

1 Answers1

1

My answer is going to be in C++ since I don't have the ObjC chops to write it from scratch, but you'll get the idea.

First, you're going to need a separate copy of phase and frequency for each signal. It would make the most sense to store these in a class representing one instance of the sine generator. e.g.

class SineGen
{
private:
    double frequency;
    double phase;

public:
    void Generate(Float32* pBuffer, int numFrames)
    {
        for (UInt32 frame = 0; frame < inNumberFrames; frame++) {
            buffer[frame] = sin(phase) * amplitude;

            phase += phase_increment;
            if (phase > 2.0 * M_PI) {
                phase -= 2.0 * M_PI;
            }
        }
    }
};

In your RenderTone function, you need to run each sine generator into a temporary buffer and then sum them element wise. Finally, you need to divide it down to bring it back into range.

OSStatus RenderTone(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const     AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList   *ioData) {
    const double amplitude = 0.5;

    Float32 *buffer = (Float32 *)ioData->mBuffers[channel].mData;
    Float32 *tmp1 = new Float32[inNumberFrames];
    Float32 *tmp2 = new Float32[inNumberFrames];

    viewController->sineGen1->Generate(tmp1, inNumberFrames);
    viewController->sineGen2->Generate(tmp2, inNumberFrames);

    for (UInt32 frame = 0; frame < inNumberFrames; frame++) {
        buffer[frame] = amplitude * (tmp1[frame] + tmp2[frame]) / 2.0;

    return noErr;
}
jaket
  • 9,140
  • 2
  • 25
  • 44