Routing .ogg audio channels

I would like to play an .ogg file with more than 2 channels from one AudioSource and be able to manipulate each channel’s volume independently.
This could mean routing them to different channels in an AudioMixer or to access each channel through C# script.

Any suggestions / experiences?

I thought one could fill an array with all samples from the multichannel clip, and then in OnAudioFilterRead() access the channels needed and output. It seems like the following code should work, but it doesn’t? I’m posting it anyway in case someone can spot the mistake I’ve made? I don’t have time to investigate now, but will return to it later…

    float[] multiSamples;
    int sampleOffset = 0;
    int numberOfChannels = 0;

    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        numberOfChannels = audioSource.clip.channels;
        multiSamples = new float[audioSource.clip.samples * numberOfChannels];
        audioSource.clip.GetData(multiSamples, 0);
    }

    void OnAudioFilterRead(float[] data, int channels)
    {
        if (multiSamples != null)
        {
            for (int i = 0; i < data.Length; i+=2)
            {
                //write channels 1 and 2 to AudioSource output
                data[i] = multiSamples[sampleOffset + (i* numberOfChannels)];
                data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels)+1];
                //uncomment to write other channesl to outpu, mixing may be needed if you wish to output multiple channels..
                //data[i] = multiSamples[sampleOffset + (i * numberOfChannels) + 2];
                //data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels) + 3];
                //data[i] = multiSamples[sampleOffset + (i * numberOfChannels) + 4];
                //data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels) + 5];
                //data[i] = multiSamples[sampleOffset + (i * numberOfChannels) + 6];
                //data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels) + 7];
            }
            sampleOffset += data.Length;
        }
    }

Ok, I spotted one issue, I was not skipping ahead enough samples in my sampleOffset. Line 31 should read:

sampleOffset += data.Length*numberChannels;

But now the pitch is slightly messed up…

Thanks! Will definitely look into that :slight_smile:

If you figure out the pitch problem let me know. Looks like I’m skipping through the multiSamples[ ] array too quickly, but I can’t see what’s causing it. Note that you should reset offsetSamples once the multichannel file has been read, otherwise you’ll get an array index out of bounds error.

Ha, got it. :wink: I wasn’t taking into account that data[ ] represents a stereo buffer as the speaker config is set to stereo by default.

[edit] I’ve updated the code so that you can control the amplitude of the tracks with public floats. I’m using Mathf.clamp01() so that we can modify the amplitude of each channel in the Unity Editor without worrying about distortion.

    private AudioSource audioSource;
    float[] multiSamples;
    int sampleOffset = 0;
    int numberOfChannels = 0;
    public float chan1Gain, chan2Gain, chan3Gain, chan4Gain, chan5Gain, chan6Gain, chan7Gain, chan8Gain;
    float leftChannelOutput, rightChannelOutput;

    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        numberOfChannels = audioSource.clip.channels;
        multiSamples = new float[audioSource.clip.samples * numberOfChannels];
        audioSource.clip.GetData(multiSamples, 0);
    }

    void OnAudioFilterRead(float[] data, int channels)
    {
        if (multiSamples != null)
        {
            for (int i = 0, y = 0; i < data.Length; y++, i += channels)
            {
                //check we don't go outside array index
                if (sampleOffset + y * numberOfChannels + numberOfChannels > multiSamples.Length)
                    sampleOffset = 0;

                //mix signals for left channel
                leftChannelOutput = (multiSamples[sampleOffset + (y * numberOfChannels)] * Mathf.Clamp01(chan1Gain) +
                                     multiSamples[sampleOffset + (y * numberOfChannels) + 2] * Mathf.Clamp01(chan3Gain) +
                                      multiSamples[sampleOffset + (y * numberOfChannels) + 4] * Mathf.Clamp01(chan5Gain) +
                                       multiSamples[sampleOffset + (y * numberOfChannels) + 6] * Mathf.Clamp01(chan7Gain));

                //mix signals for right channel
                rightChannelOutput = (multiSamples[sampleOffset + (y * numberOfChannels) + 1] * Mathf.Clamp01(chan2Gain) +
                                     multiSamples[sampleOffset + (y * numberOfChannels) + 3] * Mathf.Clamp01(chan4Gain) +
                                      multiSamples[sampleOffset + (y * numberOfChannels) + 5] * Mathf.Clamp01(chan6Gain) +
                                       multiSamples[sampleOffset + (y * numberOfChannels) + 7] * Mathf.Clamp01(chan8Gain));

                //write left and right channels
                data[i] = leftChannelOutput;
                data[i + 1] = rightChannelOutput;
            }

            //increment sampleOffset
            sampleOffset += (data.Length / channels) * numberOfChannels;

        }
    }