我需要找到录制音频流的最佳方式。我已经用 C++ 构建了低级代码,并将其中的一部分与 C# 接口。
所以我有一个 C++ 回调,它给了我一个浮点数组 - 音频信号。目前,我的 C++ lib 正在以 wav 格式将数据直接记录到文件中,并且它只会在记录结束时通知我的 C# 应用程序。
但是,我希望在 UI 方面有更多的交互性,比如“无限”进度条、记录的数据量、取消按钮等,因为最坏的情况是一分钟,也许最好把它保存在内存中。我对 .NET 和 C# 内存管理知之甚少,所以我不知道如何有效地进行。
C# 中是否有任何可快速调整大小的容器,我可以将数据放入其中,然后像数组一样访问它?
我也想建立一个波形图像。我已经用 C++ 完成了这些事情,但不知何故我不喜欢编写太多消息传递、传输对象等的想法。
所以把事情放在一起:
我有 C++ 非托管回调,它可以做一些事情,一旦它处理了数据,我想从内部调用 C# 方法,C 原型将是:
无效进程(浮点**信号,int n);(通常 [2][n] - 用于立体声)
什么是 C# 等价物,我如何从 C++ 回调中调用它?
将连续流写入(例如 mem.put(float[][] data, int size) )然后将其作为数组或其他简单方法读取(例如从中保存 wav 文件或制作波形位图)
如果我在 C# 中这样做,会不会有重大的性能损失?(托管 c++ 包装器调用 c# 函数等......可能还有一些 DSP 的东西)或者我只是偏执狂?:)
干杯,
巴布罗克斯
我的解决方案
好的,我这样解决了:
在我的 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);
}));
}
}
}
所以可能这不是最好的代码 - 我不知道。只能说它有效,似乎没有泄漏等:)