Reputation: 67
I'm importing an external C++ function from a dylib into Unity C#. The function in question looks like this:
[DllImport ("librtcmix_embedded")]
unsafe private static extern int RTcmix_runAudio(void* k, void *outAudioBuffer, int nframes);
It takes in a pointer and writes the audio information to that pointer in a fixed size buffer. I have a C# function from Unity which is supposed to take this information into a buffer:
void OnAudioFilterRead(float[] data, int channels)
Ideally within the body of OnAudioFilterRead, I will be able to declare a pointer of fixed size int* (2048, the number of samples Unity's audio uses) and feed that into the outAudioBuffer parameter of RTcmix_runaudio, then copy the information from that pointer into the float array of data.
void OnAudioFilterRead(float[] data, int channels)
{
int *buffer = new int*(2048); //this line is not proper c#, how do I do this?
RTcmix_runAudio (null, buffer, 2048);
for(int i = 0; i<2048; i++){
data[i] = (float) buffer[i];
}
}
However, I have no real idea how to get a properly working pointer with a size of 2048 in C#. Any help with this? All my attempts to input arrays or use fixed structs have crashed the program.
Upvotes: 1
Views: 1903
Reputation: 134
By using Marshal.AllocHGlobal you can allocate an unmanaged buffer of 8192 bytes (2048 x 32 bit samples), pointed to by IntPtr and pass that to the DLL. You then use Marshal.Copy to copy the unmanaged buffer content into a managed int[]. I then used Linq to 'cast' the buffer into a float[]. Free the unmanaged buffer with FreeHGlobal.
I'm assuming that the buffer consists of 4 byte integers. If it actually contains float then change the type of destination to float[], and C# will call the correct Marshal.Copy.
using System;
using System.Linq;
using System.Runtime.InteropServices;
public static class DLL
{
[DllImport("librtcmix_embedded")]
public static extern int RTcmix_runAudio(IntPtr k, IntPtr outAudioBuffer, int nframes);
}
public class MyTest
{
void OnAudioFilterRead(out float[] data, int channels)
{
int[] destination = new int[channels];
IntPtr buffer = Marshal.AllocHGlobal(4*channels);
DLL.RTcmix_runAudio((IntPtr)0, buffer, channels);
Marshal.Copy(buffer, destination, 0, channels);
Marshal.FreeHGlobal(buffer);
data = destination.Select(item => (float)item).ToArray();
}
}
Upvotes: 1