c# - 将 mp3 字节数组转换为 float 组以在 Unity 中播放

标签 c# unity-game-engine audio mp3 ros

所以我目前正在尝试从外部麦克风(在本例中实际上是在机器人上)获取音频并将其传输到 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/

相关文章:

audio - FFmpeg - 将 AVI 转换为 MP4(QuickTime 播放器中没有音频)

c# - 无法将 T 转换为间隔(我自己的自定义类型)

c# - LINQ 改变本地 "let"变量

c# - Windows 10 BackgroundMediaPlayer SystemTransportControls 暂停按钮不工作

unity-game-engine - AnimationCurve.Evaluate - 按值获取时间

iphone - 使用AudioFileReadPackets通过Audio Queue访问原始音频数据

c# - 使用其标识名称从 DataTemplate 中访问控件

android - 统一: Colors are Brighter on Android Device

unity-game-engine - 着色器使立方体的边缘倾斜?

actionscript-3 - 使用AS3WavSound播放WAV-无法立即停止