以字节[]的形式访问C#float []

时间:2013-12-15 00:35:28

标签: c# arrays marshalling

我正在使用FMOD从文件到内存读取声音。加载后,我将其转换为浮动格式,这样我就可以将其可视化并进一步处理。

我也想让FMOD播放存储在内存中的声音。但是有一个问题:我将其作为float[]存储在内存中,但FMOD.System.createSteam要求原始数据为byte[]。我可以使用Marshal复制整个数组,但最终会得到同一个数组的两个副本。有没有办法以原始字节(float[])访问byte[]数组?

通知 - 我知道,我必须固定数组,以便GC在运行时不会在内存中移动它。

另外,如果没有必要,我想避免使用unsafe

1 个答案:

答案 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;
        }
    }