// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Generic;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Audio
{
///
/// An audio effect that limits the frequency range of a sound to simulate being played
/// over various telephony or radio sources.
///
///
/// For the best results, also attach an to the sound
/// source. This will ensure that the proper frequencies will be restored
/// when audio influencers are used in the scene.
///
[RequireComponent(typeof(AudioSource))]
[RequireComponent(typeof(AudioLowPassFilter))]
[RequireComponent(typeof(AudioHighPassFilter))]
[DisallowMultipleComponent]
[AddComponentMenu("Scripts/MRTK/SDK/AudioLoFiEffect")]
public class AudioLoFiEffect : MonoBehaviour
{
[Tooltip("The quality level of the simulated audio source.")]
[SerializeField]
private AudioLoFiSourceQuality sourceQuality;
///
/// The quality level of the simulated audio source (ex: AM radio).
///
public AudioLoFiSourceQuality SourceQuality
{
get { return sourceQuality; }
set { sourceQuality = value; }
}
///
/// The audio influencer controller that will be updated when filter settings are changed.
///
[SerializeField]
[HideInInspector] // The inspector will already have a reference to the object, this avoids duplication.
private AudioInfluencerController influencerController = null;
///
/// The audio filter settings that match the selected source quality.
///
private AudioLoFiFilterSettings filterSettings;
///
/// The filters used to simulate the source quality.
///
private AudioLowPassFilter lowPassFilter;
private AudioHighPassFilter highPassFilter;
///
/// Collection used to look up the filter settings that match the selected
/// source quality.
///
private Dictionary sourceQualityFilterSettings =
new Dictionary();
private void Awake()
{
influencerController = gameObject.GetComponent();
LoadQualityFilterSettings();
filterSettings = sourceQualityFilterSettings[SourceQuality];
lowPassFilter = gameObject.GetComponent();
lowPassFilter.cutoffFrequency = filterSettings.LowPassCutoff;
highPassFilter = gameObject.GetComponent();
highPassFilter.cutoffFrequency = filterSettings.HighPassCutoff;
}
private void Update()
{
AudioLoFiFilterSettings newSettings = sourceQualityFilterSettings[SourceQuality];
if (newSettings != filterSettings)
{
// If we have an attached AudioInfluencerController, we must let it know
// about our filter settings change, otherwise other effects may not behave
// as expected.
if (influencerController != null)
{
influencerController.NativeLowPassCutoffFrequency = newSettings.LowPassCutoff;
influencerController.NativeHighPassCutoffFrequency = newSettings.HighPassCutoff;
}
filterSettings = newSettings;
lowPassFilter.cutoffFrequency = filterSettings.LowPassCutoff;
highPassFilter.cutoffFrequency = filterSettings.HighPassCutoff;
}
}
///
/// Populates the source quality filter settings collection.
///
private void LoadQualityFilterSettings()
{
if (sourceQualityFilterSettings.Keys.Count > 0) { return; }
sourceQualityFilterSettings.Add(
AudioLoFiSourceQuality.FullRange,
new AudioLoFiFilterSettings(10, 22000)); // Frequency range: 10 Hz - 22 kHz
sourceQualityFilterSettings.Add(
AudioLoFiSourceQuality.NarrowBandTelephony,
new AudioLoFiFilterSettings(300, 3400)); // Frequency range: 300 Hz - 3.4 kHz
sourceQualityFilterSettings.Add(
AudioLoFiSourceQuality.WideBandTelephony,
new AudioLoFiFilterSettings(50, 7000)); // Frequency range: 50 Hz - 7 kHz
sourceQualityFilterSettings.Add(
AudioLoFiSourceQuality.AmRadio,
new AudioLoFiFilterSettings(40, 5000)); // Frequency range: 40 Hz - 5 kHz
sourceQualityFilterSettings.Add(
AudioLoFiSourceQuality.FmRadio,
new AudioLoFiFilterSettings(30, 15000)); // Frequency range: 30 Hz - 15 kHz
}
///
/// Settings for the filters used to simulate a low fidelity sound source.
///
///
/// This struct is solely for the private use of the AudioLoFiEffect class.
///
private struct AudioLoFiFilterSettings
{
///
/// The frequency below which sound will be heard.
///
public float LowPassCutoff { get; }
///
/// The frequency above which sound will be heard.
///
public float HighPassCutoff { get; }
///
/// FilterSettings constructor.
///
/// High pass filter cutoff frequency.
/// Low pass filter cutoff frequency.
public AudioLoFiFilterSettings(float highPassCutoff, float lowPassCutoff) : this()
{
HighPassCutoff = highPassCutoff;
LowPassCutoff = lowPassCutoff;
}
///
/// Checks to see if two FilterSettings objects are equivalent.
///
/// True if equivalent, false otherwise.
public static bool operator ==(AudioLoFiFilterSettings a, AudioLoFiFilterSettings b)
{
return a.Equals(b);
}
///
/// Checks to see if two FilterSettings objects are not equivalent.
///
/// False if equivalent, true otherwise.
public static bool operator !=(AudioLoFiFilterSettings a, AudioLoFiFilterSettings b)
{
return !(a.Equals(b));
}
///
/// Checks to see if a object is equivalent to this AudioLoFiFilterSettings.
///
/// True if equivalent, false otherwise.
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is AudioLoFiFilterSettings))
{
return false;
}
AudioLoFiFilterSettings other = (AudioLoFiFilterSettings)obj;
return Equals(other);
}
///
/// Checks to see if a object is equivalent to this AudioLoFiFilterSettings.
///
/// True if equivalent, false otherwise.
public bool Equals(AudioLoFiFilterSettings other)
{
if ((!other.LowPassCutoff.Equals(LowPassCutoff)) ||
(!other.HighPassCutoff.Equals(HighPassCutoff)))
{
return false;
}
return true;
}
///
/// Generates a hash code representing this FilterSettings.
///
public override int GetHashCode()
{
string s = $"[{GetType().ToString()}] Low: {LowPassCutoff}, High: {HighPassCutoff}";
return s.GetHashCode();
}
}
}
}