Search code examples
iosxamarin.ioscore-audio

Mixing audio from files with generated sound


I'm using the example found here: https://developer.xamarin.com/samples/monotouch/MultichannelMixer/

I modified the example to add a third input to the mixer that is a simple sine wave. I want to have the two audio files play alongside the sine wave. I do this by specifying a separate AudioStreamBasicDescription for the sine wave and code inside the HandleRenderDelegate of the mixer to generate it's samples.

The problem I'm facing is that this only works if I use an audio format with float samples instead of signed integers for the sine wave. If I try using integers, the result is that the sound from the audio files is heavily distorted and there is no sine wave.

here is code I'm using for the float format (which works)

                desc = new AudioStreamBasicDescription()
                {
                    BitsPerChannel = 32,
                    Format = AudioFormatType.LinearPCM,
                    FormatFlags = AudioFormatFlags.IsFloat | AudioFormatFlags.IsPacked,
                    SampleRate = 44100,
                    ChannelsPerFrame = 1,
                    FramesPerPacket = 1,
                    BytesPerFrame = 2,
                    BytesPerPacket = 2
                };

Generating the sine wave in the HandleRenderDelegate

    if (busNumber == 2) { // generate sine wave
        var outL = (float*)data[0].Data;
        var outR = (float*)data[1].Data;
        float s;


        for (int i = 0; i < numberFrames; i++) {
            s = (float)(Math.Sin((double)pitchSample / (44100 / 440) * 2 * Math.PI)) * .2f;
            pitchSample++;

            outL[i] = outR[i] = s;
        }

        return AudioUnitStatus.OK;
    }

The code above is working as expected, but now I want to use a signed-integer format for the sine wave. So I modify the format:

                desc = new AudioStreamBasicDescription()
                {
                    BitsPerChannel = 32,
                    Format = AudioFormatType.LinearPCM,
                    FormatFlags = AudioFormatFlags.IsSignedInteger | AudioFormatFlags.IsPacked,
                    SampleRate = 44100,
                    ChannelsPerFrame = 1,
                    FramesPerPacket = 1,
                    BytesPerFrame = 2,
                    BytesPerPacket = 2
                };

And the wave generator:

if (busNumber == 2) {
    var outL = (int*)data[0].Data;
    var outR = (int*)data[1].Data;
    short s;


    for (int i = 0; i < numberFrames; i++) {
        s = (short)(Math.Sin((double)pitchSample / (44100 / 440) * 2 * Math.PI) * .2 * Int16.MaxValue);
        pitchSample++;

        outL[i] = outR[i] = s;
    }

    return AudioUnitStatus.OK;
}

With the modified code I get distorted sounding audio files and no sine wave.

Why does it work with float samples but not integers?


Solution

  • I'm not sure that these are the only problems, but you have inconsistent settings:

    • BitsPerChannel set to 32 instead of 16
    • you would want to cast to (short *) instead of (int *)
    • ChannelsPerFrame set to 1, but you set stereo in the generator (I'm not sure if it's a bug)

    (I'm supposed here that you want to use 16-bit signed integer.)

    Note: in the float case BytesPerFrame and BytesPerPacked should be 4