unity 录音功能主要通过,Microphone这个类来完成。使用这个类自然可以跨平台,不用调用平台本地代码处理。
private static AudioClip clip;
private static int maxRecordTime = 10;
private static int samplingRate = 12000;
public static bool TryStartRecording()
{
try
{
Microphone.End(null);
clip = Microphone.Start(null, false, maxRecordTime, samplingRate);
}
catch(Exception e)
{
return false;
}
return true;
}
Start开始录音,name默认不写就是寻找默认设备。samplingRate是采样率长度,越长音质越好,录音文件越大。Start之前调用End是为了结束可能正在进行的录音。
public static void EndRecording(out int length, out AudioClip outClip)
{
int lastPos = Microphone.GetPosition(null);
if (Microphone.IsRecording(null))
{
length = lastPos / samplingRate;
}
else
{
length = maxRecordTime;
}
Microphone.End(null);
if (length < 1.0f)
{
outClip = null;
return;
}
outClip = clip;
}
结束的时候,计算音频数据的长度,返回长度和clip对象,做进一步处理。拿到,clip文件就可以利用AudioSource播放了。如果,我们需要保存和读取这个音频文件我们就需要使用clip的SetData和GetData文件。
public static byte[] GetData(this AudioClip clip)
{
var data = new float[clip.samples * clip.channels];
clip.GetData(data, 0);
byte[] bytes = new byte[data.Length * 4];
Buffer.BlockCopy(data, 0, bytes, 0, bytes.Length);
return SVZip.ConvertBytesZlib(bytes, Ionic.Zlib.CompressionMode.Compress);
}
public static void SetData(this AudioClip clip, byte[] bytes)
{
bytes = SVZip.ConvertBytesZlib(bytes, Ionic.Zlib.CompressionMode.Decompress);
float[] data = new float[bytes.Length / 4];
Buffer.BlockCopy(bytes, 0, data, 0, data.Length);
clip.SetData(data, 0);
}
public static byte[] ConvertBytesZlib(byte[] data, CompressionMode compressionMode)
{
CompressionMode mode = compressionMode;
if (mode != CompressionMode.Compress)
{
if (mode != CompressionMode.Decompress)
{
throw new NotImplementedException();
}
return ZlibStream.UncompressBuffer(data);
}
return ZlibStream.CompressBuffer(data);
}
GetData会获得一个float数组,里面是采样音频数据。我们需要把它转换byte数据保存文件,利用BlockCopy内存拷贝,并且使用了Zlib压缩算法对最终的byte数据压缩。GetData的时候,先解压在逆向把byte数据转换为flaot数据,返回给clip,就拿到了可以播放的clip对象了。
使用SetData的clip需要我们调用AudioClip.Create方法创建出来,所以录音的时候,我们需要拿到原始clip的frequency和LengthSamples属性,传入给create方法。
当clip的数据可以转换成byte数据的时候,我们就可以使用读写文件的方法保存和读取了。另外,既然我们有了音频数据,我们可以做一些操作修改音调添加魔音处理等这样的功能。
==================================================================================
还有一个功能需求,就是在录音的过程中。如何显示录的声音的大小,同时显示一个音量大小的动画呢。其,核心的思路是,音频数据是float的0-1范围内的数据。就是音量大小的比例。我们可以把0-1的范围,分为若干个区间,来表示音量的大小。那么,我们有两个方案,来录音的时候实时获取这个sample数据。
第一,就是使用协程,不断的检测Microphone.IsRecording是否在录音中,然后利用Microphone.GetPosition获得当前的进度,往前计算一段sample数据,找出一个平均值来代表这段时间的音量大小。
第二,就是使用clip的回调接口PCMReaderCallback,在录到数据的时候会回调这个函数,参数中可以拿到当前的一段的sample数据。同样的找出一个平均值来代表当前的音量。