Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Routing .ogg audio channels

Discussion in 'Audio & Video' started by hysaic, May 31, 2016.

  1. hysaic

    hysaic

    Joined:
    May 18, 2014
    Posts:
    2
    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?
     
  2. rorywalsh

    rorywalsh

    Joined:
    Apr 10, 2015
    Posts:
    114
    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...

    Code (CSharp):
    1.    
    2.     float[] multiSamples;
    3.     int sampleOffset = 0;
    4.     int numberOfChannels = 0;
    5.  
    6.     void Start()
    7.     {
    8.         audioSource = GetComponent<AudioSource>();
    9.         numberOfChannels = audioSource.clip.channels;
    10.         multiSamples = new float[audioSource.clip.samples * numberOfChannels];
    11.         audioSource.clip.GetData(multiSamples, 0);
    12.     }
    13.  
    14.     void OnAudioFilterRead(float[] data, int channels)
    15.     {
    16.         if (multiSamples != null)
    17.         {
    18.             for (int i = 0; i < data.Length; i+=2)
    19.             {
    20.                 //write channels 1 and 2 to AudioSource output
    21.                 data[i] = multiSamples[sampleOffset + (i* numberOfChannels)];
    22.                 data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels)+1];
    23.                 //uncomment to write other channesl to outpu, mixing may be needed if you wish to output multiple channels..
    24.                 //data[i] = multiSamples[sampleOffset + (i * numberOfChannels) + 2];
    25.                 //data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels) + 3];
    26.                 //data[i] = multiSamples[sampleOffset + (i * numberOfChannels) + 4];
    27.                 //data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels) + 5];
    28.                 //data[i] = multiSamples[sampleOffset + (i * numberOfChannels) + 6];
    29.                 //data[i + 1] = multiSamples[sampleOffset + (i * numberOfChannels) + 7];
    30.             }
    31.             sampleOffset += data.Length;
    32.         }
    33.     }
     
  3. rorywalsh

    rorywalsh

    Joined:
    Apr 10, 2015
    Posts:
    114
    Ok, I spotted one issue, I was not skipping ahead enough samples in my sampleOffset. Line 31 should read:
    Code (CSharp):
    1. sampleOffset += data.Length*numberChannels;
    But now the pitch is slightly messed up...
     
  4. hysaic

    hysaic

    Joined:
    May 18, 2014
    Posts:
    2
    Thanks! Will definitely look into that :)
     
  5. rorywalsh

    rorywalsh

    Joined:
    Apr 10, 2015
    Posts:
    114
    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.
     
  6. rorywalsh

    rorywalsh

    Joined:
    Apr 10, 2015
    Posts:
    114
    Ha, got it. ;) 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.

    Code (CSharp):
    1.     private AudioSource audioSource;
    2.     float[] multiSamples;
    3.     int sampleOffset = 0;
    4.     int numberOfChannels = 0;
    5.     public float chan1Gain, chan2Gain, chan3Gain, chan4Gain, chan5Gain, chan6Gain, chan7Gain, chan8Gain;
    6.     float leftChannelOutput, rightChannelOutput;
    7.  
    8.     void Start()
    9.     {
    10.         audioSource = GetComponent<AudioSource>();
    11.         numberOfChannels = audioSource.clip.channels;
    12.         multiSamples = new float[audioSource.clip.samples * numberOfChannels];
    13.         audioSource.clip.GetData(multiSamples, 0);
    14.     }
    15.  
    16.     void OnAudioFilterRead(float[] data, int channels)
    17.     {
    18.         if (multiSamples != null)
    19.         {
    20.             for (int i = 0, y = 0; i < data.Length; y++, i += channels)
    21.             {
    22.                 //check we don't go outside array index
    23.                 if (sampleOffset + y * numberOfChannels + numberOfChannels > multiSamples.Length)
    24.                     sampleOffset = 0;
    25.  
    26.                 //mix signals for left channel
    27.                 leftChannelOutput = (multiSamples[sampleOffset + (y * numberOfChannels)] * Mathf.Clamp01(chan1Gain) +
    28.                                      multiSamples[sampleOffset + (y * numberOfChannels) + 2] * Mathf.Clamp01(chan3Gain) +
    29.                                       multiSamples[sampleOffset + (y * numberOfChannels) + 4] * Mathf.Clamp01(chan5Gain) +
    30.                                        multiSamples[sampleOffset + (y * numberOfChannels) + 6] * Mathf.Clamp01(chan7Gain));
    31.  
    32.                 //mix signals for right channel
    33.                 rightChannelOutput = (multiSamples[sampleOffset + (y * numberOfChannels) + 1] * Mathf.Clamp01(chan2Gain) +
    34.                                      multiSamples[sampleOffset + (y * numberOfChannels) + 3] * Mathf.Clamp01(chan4Gain) +
    35.                                       multiSamples[sampleOffset + (y * numberOfChannels) + 5] * Mathf.Clamp01(chan6Gain) +
    36.                                        multiSamples[sampleOffset + (y * numberOfChannels) + 7] * Mathf.Clamp01(chan8Gain));
    37.  
    38.                 //write left and right channels
    39.                 data[i] = leftChannelOutput;
    40.                 data[i + 1] = rightChannelOutput;
    41.             }
    42.  
    43.             //increment sampleOffset
    44.             sampleOffset += (data.Length / channels) * numberOfChannels;
    45.  
    46.         }
    47.     }
     
    Last edited: May 31, 2016