我正在使用FMOD从文件到内存读取声音。加载后,我将其转换为浮动格式,这样我就可以将其可视化并进一步处理。
我也想让FMOD播放存储在内存中的声音。但是有一个问题:我将其作为float[]
存储在内存中,但FMOD.System.createSteam
要求原始数据为byte[]
。我可以使用Marshal复制整个数组,但最终会得到同一个数组的两个副本。有没有办法以原始字节(float[]
)访问byte[]
数组?
通知 - 我知道,我必须固定数组,以便GC在运行时不会在内存中移动它。
另外,如果没有必要,我想避免使用unsafe
。
答案 0 :(得分:4)
显然你可以在每个浮点数上使用BitConverter.GetBytes
将float []复制到byte []中。我很确定你可以通过对float []使用void *然后将它转换为byte *来唯一可以访问float [] AS的字节[]。我知道你不是在寻找不安全的代码,但这是我能够做到的唯一方法。作为强类型,c#故意禁止那种东西。
我知道您正在使用FMOD .NET包装器,但也许您可以为想要byte []的函数导入本机dll调用?本机调用可能会调用指针:
namespace FMOD
{
public partial class System
{
[DllImport(VERSION.dll)]
private static extern RESULT FMOD_System_CreateSound(IntPtr system, IntPtr name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref IntPtr sound);
[DllImport(VERSION.dll)]
private static extern RESULT FMOD_System_CreateStream(IntPtr system, IntPtr name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref IntPtr sound);
public RESULT createSound(IntPtr data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref Sound sound)
{
RESULT result = RESULT.OK;
IntPtr soundraw = new IntPtr();
Sound soundnew = null;
try
{
result = FMOD_System_CreateSound(systemraw, data, mode, ref exinfo, ref soundraw);
}
catch
{
result = RESULT.ERR_INVALID_PARAM;
}
if (result != RESULT.OK)
{
return result;
}
if (sound == null)
{
soundnew = new Sound();
soundnew.setRaw(soundraw);
sound = soundnew;
}
else
{
sound.setRaw(soundraw);
}
return result;
}
public RESULT createStream(IntPtr data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref Sound sound)
{
RESULT result = RESULT.OK;
IntPtr soundraw = new IntPtr();
Sound soundnew = null;
try
{
result = FMOD_System_CreateStream(systemraw, data, mode, ref exinfo, ref soundraw);
}
catch
{
result = RESULT.ERR_INVALID_PARAM;
}
if (result != RESULT.OK)
{
return result;
}
if (sound == null)
{
soundnew = new Sound();
soundnew.setRaw(soundraw);
sound = soundnew;
}
else
{
sound.setRaw(soundraw);
}
return result;
}
}
}
以下是一些实用函数,它们从字节转换为浮点数,反之亦然,以防它们最终有用。如果你没有将float []作为byte *传递,那么没有理由使用这些原样。我相信你已经知道如何进行托管转换。如果您最终走上不安全的路线,这只是为了节省您的时间。
using System.Runtime.InteropServices
private unsafe byte[] FloatsToBytes(float[] floats) {
fixed (void* pFloats = floats) {
byte* pBytes = (byte*)pFloats;
byte[] bytes = new byte[sizeof(float) * floats.Length];
Marshal.Copy((IntPtr)pBytes, bytes, 0, floats.Length * sizeof(byte));
return bytes;
}
}
private unsafe float[] BytesToFloats(byte[] bytes) {
fixed (void* pBytes = bytes) {
float* pFloats = (float*)pBytes;
float[] floats = new float[bytes.Length / sizeof(float)];
Marshal.Copy((IntPtr)pFloats, floats, 0, bytes.length / sizeof(float));
return floats;
}
}