所以我目前正在尝试从外部麦克风(在本例中实际上是在机器人上)获取音频并将其传输到 Unity 中以在场景中播放。我相当确定该音频是以 mp3 格式编码的,采样率为 16000 Hz,比特率为 192 kHz。
我能够在 Unity 中将此音频作为字节数组(似乎始终是 Little Endian)获取,并且我想转换为 float 组,每个值的范围从 -1.0f 到 +1.0f这样我就可以使用 AudioClip.SetData 在 Unity 场景中播放它。我的问题是到目前为止我还无法做到这一点。
我的第一次尝试是基于这个 StackOverflow 答案:create AudioClip from byte[] 它使用以下函数进行转换:
private float[] ConvertByteToFloat(byte[] array) {
float[] floatArr = new float[array.Length / 4];
for (int i = 0; i < floatArr.Length; i++) {
if (BitConverter.IsLittleEndian) {
Array.Reverse(array, i * 4, 4);
}
floatArr[i] = BitConverter.ToSingle(array, i * 4) / 0x80000000;
}
return floatArr;
}
然后我像这样调用它:
scaledAudio = ConvertByteToFloat(audioData);
AudioClip audioClip = AudioClip.Create("RobotAudio", scaledAudio.Length, 1, 16000, false);
audioClip.SetData(scaledAudio, 0);
AudioSource.PlayClipAtPoint(audioClip, robot.transform.position);
但结果是很多静态,在记录一些输出时,我意识到我得到了一堆 NaN...
我在某处读到可以使用 BitConverter.ToInt16()
函数提取 mp3 音频,因此我相应地更改了 ConvertByteToFloat
函数,如下所示:
private float[] ConvertByteToFloat16(byte[] array) {
float[] floatArr = new float[array.Length / 2];
for (int i = 0; i < floatArr.Length; i++) {
if (BitConverter.IsLittleEndian) {
Array.Reverse(array, i * 2, 2);
}
floatArr[i] = (float) (BitConverter.ToInt16(array, i * 2) / 32767f);
}
return floatArr;
}
[注意:结果除以 32767f,因为我读到这是可能出现的最大值,我想将其缩小到 -1.0f 和 1.0f 之间]
这个数字看起来更有希望。它们确实都在-1.0f 和1.0f 之间。但是当我尝试使用 Unity 播放音频时,我听到的都是静态的。
问题几乎肯定是在 byte[] 到 float[] 的转换中,但我可能在为 AudioClip 或 AudioSource 设置数据或播放器时犯了错误。
非常感谢任何帮助/建议!
[额外资源:我统一的byte[]来自这里:https://github.com/ros-drivers/audio_common/blob/master/audio_capture/src/audio_capture.cpp 有一个相关的脚本,它获取此捕获程序编码的数据并播放它( https://github.com/ros-drivers/audio_common/blob/master/audio_play/src/audio_play.cpp )。这工作得很好 - 所以如果我可以在第二个链接中复制 audio_play 脚本的解码功能,看起来我就可以开始了!]
最佳答案
在 file you linked ,它表示在设置过程中它将数据编码为编码的 mp3 格式(左侧的行号)。
21 >> // Need to encoding or publish raw wave data
22 >> ros::param::param<std::string>("~format", _format, "mp3");
这意味着您有两个选择。
从库中导出波形格式(原始 PCM)
更改 C++ 库的输出格式以导出原始波形文件格式。
21 >> // Need to encoding or publish raw wave data
22 >> ros::param::param<std::string>("~format", _format, "wave");
通读代码,如果将第 22 行的第三个构造函数参数更改为“wave”,它将把数据导出为 .wav 格式,因此不需要在 Unity 中进行解码。如果可以的话,这将要求您重新编译 C++ 代码。请注意,音频数据(波形格式)在内存中会稍大(比 mp3)。
参见 audio_capture.cpp 的第 98 -> 109 行文件用于检查波形或 mp3 格式。
在 Unity 中解码 MP3 音频
否则你可以尝试在 Unity 中解码 mp3 数据。这很可能涉及使用 mp3 库(我发现的第一个库是 MP3Sharp )。否则有一个名为 uAudio 的 Unity 资源表示进行实时 mp3 压缩/解压缩;这可能比使用通用 mp3 解码器更简单,因为它已经是为 Unity 设计的。
我不建议您编写自己的 mp3 解码器,除非只是为了挑战或学习目的。
<小时/>抛开所有想法,我的第一次尝试是重新编译您的 C++ 库,并将参数设置为“wave”,如上所述!
我希望这有帮助:)
关于c# - 将 mp3 字节数组转换为 float 组以在 Unity 中播放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51051559/