因此,我有一个 C++ 回调函数,可以为我提供一个浮点数数组的数组 - 音频信号。
目前,我的 C++ 库正在直接将数据录制到 wav 格式的文件中,并在录制结束时通知我的 C# 应用程序。
但是,我希望在 UI 界面上获得更多的交互性,例如“无限”进度条、已记录的数据量、取消按钮等等,而且由于最坏情况下只有一分钟左右,也许最好将其保留在内存中。我对 .NET 和 C# 的内存管理知之甚少,所以不知道如何有效地实现它。
在 C# 中是否有快速可调整大小的容器,可以仅将数据放入其中,稍后像数组一样访问它?
我还想根据它构建波形图像。我已经在 C++ 中完成了这些事情,但是某种程度上,我不喜欢编写太多的消息传递、传输对象等等。
把事情放在一起:
我有一个 C++ 未管理的回调函数,执行某些操作,从中调用 C# 方法一旦处理完数据,C 原型将是:
void process(float **signal, int n); (通常为 [2][n] - 用于立体声)
相应的 C# 是什么,如何从 C++ 回调中调用它?
最好的类来连续写入流(例如 mem.put(float[][] data, int size)),然后使用其他简单方法(例如从中保存 wav 文件或制作波形位图)将其读取为数组。
如果在 C# 中执行此操作,是否会有显着的性能损失?(托管的 C++ 包装器调用 C# 函数等等...以及可能的一些 DSP 物品)还是我只是多虑了? :)
干杯
pablox
我的解决方案
好的,我这样解决了:
在我的 C++ 头文件中,我有一个传输结构:
public ref struct CVAudio {
public:
float *left;
float *right;
int length;
};
然后在托管 C++ 类中,我声明了:
delegate void GetAudioData([In, Out] CVAudio^ audio);
然后我可以将它作为参数传递给初始化音频的方法:
void initializeSoundSystem(void *HWnd, GetAudioData ^audio);
那个代表也有一个C的原型。
typedef void (CALLBACK *GETAUDIODATA)(CVAudio ^a);
这在内部的 C++ 类中用作:
void initializeSoundSystem(HWND HWnd, GETAUDIODATA audio);
第一个方法的主体是:
void VDAudio::initializeSoundSystem(void *HWnd, GetAudioData ^audio)
{
HWND h = (HWND) HWnd;
acb = audio;
pin_ptr<GetAudioData ^> tmp = &audio;
IntPtr ip = Marshal::GetFunctionPointerForDelegate(audio);
GETAUDIODATA cb = static_cast<GETAUDIODATA>(ip.ToPointer());
audioObserver->initializeSoundSystem(h, cb);
}
audioObserver的主体仅将回调存储在对象中并执行一些与音频相关的操作。
然后,在处理方法中调用回调,像这样:
VDAudio^ a = gcnew VDAudio();
a->left = VHOST->Master->getSample()[0]; //returns left channel float*
a->right = VHOST->Master->getSample()[1];
a->length = length;
(*callback)(a);
而 C# 委托的主体:
public void GetSamples(CVAudio audio)
{
unsafe
{
float* l = (float*)audio.left;
float* r = (float*)audio.right;
if (l != null)
{
SamplePack sample = new SamplePack();
sample.left = new float[audio.length];
sample.right = new float[audio.length];
IntPtr lptr = new IntPtr((void*)l);
IntPtr rptr = new IntPtr((void*)r);
Marshal.Copy(lptr, sample.left, 0, audio.length);
Marshal.Copy(rptr, sample.right, 0, audio.length);
this.Dispatcher.Invoke(new Action(delegate()
{
GetSamples(sample);
}));
}
}
}
所以可能这不是最优秀的代码 - 我不确定。只能说它能够工作,似乎也没有泄漏等问题。:)