我正在包装一个c ++ dll,它在c#中进行高质量的采样率转换,我不确定我应该使用什么类型的 op0 参数。 C ++包装器会像这样调用它:
int _cdecl process(double* const ip0, int l, double*& op0)
文档说明了参数:
“@ param [out] op0此变量接收指向重采样数据的指针。 该指针可以指向“ip0”输入缓冲区内的地址,或者指向 *此对象的内部缓冲区。建议在实时应用程序中使用 将此指针传递给下一个输出音频块并使用任何数据 在调用之前先从前一个输出音频块离开 process()函数再次出现。返回时“op0”指向的缓冲区可能 由重新采样器拥有,因此不应被调用者释放。“
我想做的是以下内容:
[DllImport("r8bsrc.dll", EntryPoint="process", CallingConvention = CallingConvention.Cdecl)]
public static extern int Process([in] double[] ip0,
int length,
[out] double[] op0);
但我很确定这不起作用,因为编组人员无法知道 op1 背后的内存有多大,或者我错了?
所以我想我必须自己将op1背后的值复制回托管数组。也许:
[DllImport("r8bsrc.dll", EntryPoint="process", CallingConvention = CallingConvention.Cdecl)]
public static extern int Process([in] double[] ip0,
int length,
out IntPtr op0); //or do i need out double* ?
然后用:
再次换行 private IntPtr FOutBufferPtr; //reuse it as recommeded
public int Process(double[] input, out double[] output)
{
var outSamples = R8BrainDLLWrapper.Process(input, input.Length, out FOutBufferPtr);
output = new double[outSamples];
Marshal.Copy(FOutBufferPtr, output, 0, outSamples);
}
涉及最少份数的最佳方式是什么?
EDIT2:
这是当前的代码,它完美运行:
public int Process(double[] input, ref double[] output)
{
//pin the input during process
var pinnedHandle = GCHandle.Alloc(input, GCHandleType.Pinned);
//resample
var outSamples = R8BrainDLLWrapper.Process(FUnmanagedInstance, pinnedHandle.AddrOfPinnedObject(), input.Length, out FOutBufferPtr);
//copy to output array
if(output.Length < outSamples)
output = new double[outSamples];
Marshal.Copy(FOutBufferPtr, output, 0, outSamples);
//free pin
pinnedHandle.Free();
return outSamples;
}
签名现在是:
[DllImport("r8bsrc.dll", EntryPoint="r8b_process", CallingConvention = CallingConvention.Cdecl)]
public static extern int Process(IntPtr instance,
IntPtr ip0,
int length,
out IntPtr op0);
答案 0 :(得分:2)
@param [out] op0
此变量接收指向重采样数据的指针。该指针可以指向“ip0”输入缓冲区内的地址,或指向*此对象的内部缓冲区。在实时应用程序中,建议将此指针传递给下一个输出音频块,并在再次调用process()函数之前首先使用先前输出音频块留下的任何数据。返回时“op0”指向的缓冲区可能由重新采样器拥有,因此调用者不应释放它。
这会立即对ip0
提出约束。您必须安排ip0
指向的缓冲区在函数调用结束后保持稳定。这意味着你必须在调用函数之前将其固定。这反过来暗示必须将其声明为IntPtr
。
对于op0
,这指向重采样器拥有的内存或ip0
输入缓冲区内的位置。因此,您将不得不使用IntPtr
,这次是out
参数。
因此,声明必须是:
[DllImport("r8bsrc.dll", EntryPoint="process",
CallingConvention = CallingConvention.Cdecl)]
public static extern int Process(IntPtr ip0, int length, out IntPtr op0);
如上所述,您在ip0
中传递的指针必须使用GCHandle
类获取,以便您可以固定数组。