数据 | 一个包含音频数据的浮点数数组 。 |
通道 | 一个整数 ,用于存储传递给此委托的音频数据通道数量。 |
如果实现了 OnAudioFilterRead,Unity 将在音频 DSP 链中插入自定义滤波器。
滤波器将按照 Inspector 中显示的 MonoBehaviour 脚本的顺序插入。
每次将一组音频数据发送到滤波器时,都会调用 OnAudioFilterRead(这会频繁发生,每隔约 20 毫秒,具体取决于采样率和平台)。音频数据是一个范围在 [-1.0f;1.0f] 之间的浮点数数组,包含来自链中前一个滤波器或 音频剪辑 的音频 音频源。如果这是链中的第一个滤波器,并且没有将剪辑附加到音频源,则将此滤波器作为音频源播放。这样一来,您可以将滤波器用作音频剪辑,以过程方式生成音频。
如果有多个通道,则通道数据是交错的。这意味着数组中的每个连续数据样本都来自不同的通道,直到您用完所有通道并循环回到第一个通道为止。 data.Length
报告数据的总大小,因此要找到每个通道的样本数量,请将 data.Length
除以 channels
。
如果实现了 OnAudioFilterRead,则 Inspector 中会显示一个 VU 表,显示输出样本电平。滤波器的处理时间也会被测量,并将花费的毫秒数显示在 VU 表旁边。如果滤波器占用时间过长,则该数字将变为红色,这意味着混音器将缺乏音频数据。
另外,请注意 OnAudioFilterRead 是在与主线程不同的线程(即音频线程)上调用的,因此不允许从此函数调用许多 Unity 函数(如果尝试,则会在运行时显示警告)。
其他资源:音频滤波器。
using UnityEngine;
// The code example shows how to implement a metronome that procedurally // generates the click sounds via the OnAudioFilterRead callback. // While the game is paused or suspended, this time will not be updated and sounds // playing will be paused. Therefore developers of music scheduling routines do not have // to do any rescheduling after the app is unpaused
[RequireComponent(typeof(AudioSource))] public class AudioTest : MonoBehaviour { public double bpm = 140.0F; public float gain = 0.5F; public int signatureHi = 4; public int signatureLo = 4;
private double nextTick = 0.0F; private float amp = 0.0F; private float phase = 0.0F; private double sampleRate = 0.0F; private int accent; private bool running = false;
void Start() { accent = signatureHi; double startTick = AudioSettings.dspTime; sampleRate = AudioSettings.outputSampleRate; nextTick = startTick * sampleRate; running = true; }
void OnAudioFilterRead(float[] data, int channels) { if (!running) return;
double samplesPerTick = sampleRate * 60.0F / bpm * 4.0F / signatureLo; double sample = AudioSettings.dspTime * sampleRate; int dataLen = data.Length / channels;
int n = 0; while (n < dataLen) { float x = gain * amp * Mathf.Sin(phase); int i = 0; while (i < channels) { data[n * channels + i] += x; i++; } while (sample + n >= nextTick) { nextTick += samplesPerTick; amp = 1.0F; if (++accent > signatureHi) { accent = 1; amp *= 2.0F; } Debug.Log("Tick: " + accent + "/" + signatureHi); } phase += amp * 0.3F; amp *= 0.993F; n++; } } }