将 mp3 字节数组转换为浮点数组以使用 Unity

njk*_*k23 6 c# audio mp3 unity-game-engine ros

所以我目前正在尝试从外部麦克风(在这种情况下实际上是在机器人上)获取音频并将其流式传输到 Unity 中以在场景中播放。我很确定这个音频是以 mp3 格式编码的,采样率为 16000 Hz,比特率为 192 kHz。

我可以在 Unity 中将此音频作为字节数组(似乎始终是 Little Endian)获取,并且我想转换为每个值范围从 -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;
    }
Run Code Online (Sandbox Code Playgroud)

然后我像这样调用它:

scaledAudio = ConvertByteToFloat(audioData);
AudioClip audioClip = AudioClip.Create("RobotAudio", scaledAudio.Length, 1, 16000, false);
audioClip.SetData(scaledAudio, 0);
AudioSource.PlayClipAtPoint(audioClip, robot.transform.position);
Run Code Online (Sandbox Code Playgroud)

但结果是很多静态的,在记录一些输出时,我意识到我得到了一堆 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;
        }
Run Code Online (Sandbox Code Playgroud)

[注意:结果除以 32767f,因为我读到这是可能出现的最大值,我想将其缩小到 -1.0f 和 1.0f 之间]

这个数字看起来更有希望。它们确实都在 -1.0f 和 1.0f 之间。但是当我尝试用 Unity 播放音频时,我听到的都是静态的。

问题几乎肯定是在 byte[] 到 float[] 的转换中,但我可能在为 AudioClip 或 AudioSource 设置数据或播放器时犯了一个错误。

非常感谢任何帮助/建议!

[附加资源:我进入统一的字节[]来自这里: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 脚本的解码功能,看起来我会很高兴!]

Woo*_*Dev 4

您链接的文件中,它表示在设置过程中它将数据编码为编码的 mp3 格式(左侧的行号)。

21 >> // Need to encoding or publish raw wave data
22 >> ros::param::param<std::string>("~format", _format, "mp3");
Run Code Online (Sandbox Code Playgroud)

这意味着您有两个选择。

从您的库中导出波形格式(原始 PCM)

更改 C++ 库的输出格式以导出原始波形文件格式。

21 >> // Need to encoding or publish raw wave data
22 >> ros::param::param<std::string>("~format", _format, "wave");
Run Code Online (Sandbox Code Playgroud)

通读代码,如果将第 22 行的第三个构造函数参数更改为“wave”,它将把数据导出为 .wav 格式,因此不需要在 Unity 中进行解码。如果可以的话,这将要求您重新编译 C++ 代码。请注意,音频数据(波形格式)在内存中会稍大(比 mp3)。

请参阅audio_capture.cpp文件的第98 行-> 109 行,了解它检查wave 或mp3 格式的位置。

在 Unity 中解码 MP3 音频

否则你可以尝试在 Unity 中解码 mp3 数据。这很可能涉及使用 mp3 库(我发现的第一个库是MP3Sharp)。另外,还有一个名为uAudio的 Unity 资源,它声明可以进行实时 mp3 压缩/解压缩;这可能比使用通用 mp3 解码器更简单,因为它已经是为 Unity 设计的。

我不建议您编写自己的 mp3 解码器,除非只是为了挑战或学习目的。


抛开所有想法不谈,我的第一次尝试是重新编译 C++ 库,并将参数设置为“wave”,如上所述!

我希望这有帮助 :)