Search Unity

Near/Far Audio Blend?

Discussion in 'Audio & Video' started by PhobicGunner, Dec 9, 2014.

  1. PhobicGunner

    PhobicGunner

    Joined:
    Jun 28, 2011
    Posts:
    1,813
    Hello,
    I'm trying to create a near/far audio blend script, where the near/far sounds are stored in left/right channels of an audio clip. So far, the best I've been able to come up with is a streaming audio clip and custom PcmReaderCallbacks:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public enum NearFarBlendMode
    7. {
    8.     Standard,
    9.     NearFarBlend,
    10. }
    11.  
    12. public class NearFarBlendFilter : MonoBehaviour
    13. {
    14.     public AudioClip Clip;
    15.  
    16.     public NearFarBlendMode BlendMode = NearFarBlendMode.Standard;
    17.  
    18.     public float BlendStart = 5f;
    19.     public float BlendEnd = 20f;
    20.  
    21.     private AudioClip writeClip;
    22.  
    23.     private float[] sourceBuffer;
    24.     private int readPos = 0;
    25.  
    26.     private float channelBlend = 0f;
    27.  
    28.     public void SetClip( AudioClip clip )
    29.     {
    30.         channelBlend = 0f;
    31.         readPos = 0;
    32.  
    33.         Clip = clip;
    34.  
    35.         writeClip = AudioClip.Create( "__writeClip__", Clip.samples, Clip.channels, Clip.frequency, true, true, onAudioDataRead, onSetReadPosition );
    36.  
    37.         sourceBuffer = new float[ Clip.samples * Clip.channels ];
    38.         Clip.GetData( sourceBuffer, 0 );
    39.  
    40.         audio.clip = writeClip;
    41.     }
    42.  
    43.     void Awake()
    44.     {
    45.         SetClip( Clip );
    46.         audio.Play();
    47.     }
    48.  
    49.     void onSetReadPosition( int pos )
    50.     {
    51.         readPos = pos;
    52.     }
    53.  
    54.     void onAudioDataRead( float[] data )
    55.     {
    56.         if( BlendMode == NearFarBlendMode.Standard || data == null || sourceBuffer == null ) return;
    57.  
    58.         for( int i = 0; i < data.Length && ( i + readPos ) < sourceBuffer.Length; i += 2 )
    59.         {
    60.             float mix = Mathf.Lerp(
    61.                 sourceBuffer[ i + readPos ],
    62.                 sourceBuffer[ i + readPos + 1 ],
    63.                 channelBlend );
    64.  
    65.             data[ i ] = mix;
    66.             data[ i + 1 ] = mix;
    67.         }
    68.  
    69.         readPos += data.Length;
    70.     }
    71.  
    72.     void Update()
    73.     {
    74.         if( BlendMode == NearFarBlendMode.Standard ) return;
    75.  
    76.         float distance = Vector3.Distance( transform.position, Camera.main.transform.position );
    77.         channelBlend = calculateBlend( distance );
    78.     }
    79.  
    80.     float calculateBlend( float distance )
    81.     {
    82.         distance = Mathf.Max( 0, distance - BlendStart );
    83.         return ( distance / ( BlendEnd - BlendStart ) );
    84.     }
    85. }
    86.  
    I know I'm supposed to be using OnAudioFilterRead for stuff like this, but it just doesn't work for me - in particular, if I implement a custom audio filter for this stuff it seems there's no way to make Unity handle spatialized speaker panning for me (stereo speaker pan is trivial, but 5.1 or 7.1 surround, not so much).

    Any feedback? Is there a better way to do this in Unity?