
下面通过直接编辑Unity的AudioClip数据来学习声音数据的结构。
采样和量化简介
在本文中,将通过直接编辑Unity的Audio Clip数据、改变音量、编辑特定秒数的数据来学习声音数据的结构。
但在此之前,需要先简单总结一下本节关于声音数据的最低限度前提知识。
现在,考虑以下波形所代表的声音,现实世界中的声音可以用这样的连续波来表示。

接下来,考虑将其转换为数字数据,由于数字数据只是数值的集合,因此以规则的时间间隔将波分开并转换为每个时间间隔的数据,这称为抽样。

另外,一秒内采样多少次称为频率,以赫兹(Hz)为单位表示。44100 Hz,常用于声音数据,表示数据每秒采样 44100 次。
在以这种方式划分成固定时间间隔之后,信号电平被转换为每个时间间隔的数字数据。由于数字数据也是离散数,因此结果是具有如下层次的数据集合,这称为量化。

用于表示一段采样数据的比特数称为量化比特数。
综上所述,可以说如果增加频率和量化位数,就可以更准确地再现实际声音(数据量自然会增加)。
控制音量
现在了解了基础知识,来实际编辑音频剪辑。
可以通过调用AudioClip.GetData()获取所有样本的值,该值是一个浮点数数组,每个浮点值代表一个采样数据(如前一节所述,以固定间隔分隔的数据)。
采样数据由-1到1之间的值表示,因此,如果可以像下图那样写0.5,信号电平减半,也就是音量减半。
using UnityEngine;
public class AudioExample : MonoBehaviour
{
[SerializeField] private AudioSource _source;
private void Start()
{
var clip = _source.clip;
ChangeAudioClipVolume(clip, 0.5f, true);
}
private static void ChangeAudioClipVolume(AudioClip clip, float magnification)
{
// number of samples = value of clip.samples x number of channels (1 for mono, 2 for stereo)
var samples = new float[clip.samples * clip.channels];
clip.GetData(samples, 0);
for (var i = 0; i < samples.Length; i++)
{
// Multiply the values of all samples by the value of the argument
samples[i] *= magnification;
}
clip.SetData(samples, 0);
}
}
需要在加载时解压
如上获取数据时需要注意的一点AudioClip.GetData()是,AudioClip的Load Type必须是Decompress On Load。

其他任何东西都会为所有样本返回零值。
只调整一个频道
现在,只播放一个频道,假设音频文件是立体声的。

在立体声的情况下,如前一节获取的样本数据格式为第一个样本左,第一个样本右,第二个样本左,第二个样本右,依此类推。

因此,如果像下图这样只处理能被2整除的索引,则只能处理左边,反之,则只能处理右边。
using UnityEngine;
public class AudioExample : MonoBehaviour
{
[SerializeField] private AudioSource _source;
private void Start()
{
var clip = _source.clip;
ChangeAudioClipVolume(clip, 0.5f, true);
}
private static void ChangeAudioClipVolume(AudioClip clip, float magnification, bool left)
{
var samples = new float[clip.samples * clip.channels];
clip.GetData(samples, 0);
for (var i = 0; i < samples.Length; i++)
{
if (left && i % 2 != 0)
{
continue;
}
if (!left && i % 2 != 1)
{
continue;
}
samples[i] *= magnification;
}
clip.SetData(samples, 0);
}
}
当播放这个时,应该能够确认只有左耳的声音被减弱了。
处理特定的时间
最后,编辑特定秒数的数据。
为此,AudioClip.frequency请从每秒样本数可以表示为频率*通道数,因此可以只处理特定秒数的数据,如下所示。
using UnityEngine;
public class AudioExample : MonoBehaviour
{
[SerializeField] private AudioSource _source;
private void Start()
{
var clip = _source.clip;
ChangeAudioClipVolume(clip, 0.1f, 5.0f);
}
private static void ChangeAudioClipVolume(AudioClip clip, float magnification, float durationSec)
{
var samples = new float[clip.samples * clip.channels];
clip.GetData(samples, 0);
// Samples per second = sampling frequency * number of channels
var samplesPerSec = clip.frequency * clip.channels;
var limit = samplesPerSec * durationSec;
for (var i = 0; i < limit; i++)
{
samples[i] *= magnification;
}
clip.SetData(samples, 0);
}
}
如果播放这个,会发现只有前5秒声音比较小。
…
以上是关于通过直接编辑Unity的AudioClip数据来学习声音数据的结构的全部内容,如果你有任何反馈,请随时在本页面下方留言。