如何创建指针数组的指针与VST音频缓冲区相同?

时间:2013-11-06 09:59:07

标签: c++ arrays pointers audio vst

在VST规范中,多声道音频数据的缓冲区传递......

MyClass::ProcessDoubleReplacing(double **inputs, double **outputs, int frames)
{
    //and accessed like this...
    outputs[channel][sample] = inputs[channel][sample]
}

我想创建一个类似的“2d指针数组”,但没有取得多大成功。我可以创建一个简单的指针并迭代它读/写值....

double* samples;
samples[0] = aValue;

....但是我正在尝试实施一些让我能够实现的崩溃节......

samples[0][0] = aValue;

实现这个的正确方法是什么?

3 个答案:

答案 0 :(得分:2)

double* samples;
samples[0] = aValue;

这真的很糟糕。 :(请不要这样做!“示例”只是指向你记忆中某处的指针。 它指向的内存根本没有分配,但是你正在写这个内存......

您可以从堆中或从堆栈中分配内存块。但是,堆栈具有大小限制(在编译器设置中配置) - 因此对于较大的块(如音频数据),通常会从堆中分配它。但是你必须注意,你不会从堆中泄漏内存 - 堆栈内存由变量的范围自动管理,因此更容易开始。 在C / C ++中,您可以像这样从堆栈中分配内存:

double samples[512];

然后你可以做类似的事情:

samples[0] = aValue; // change value of 1st sample in sample buffer with 512 elements

double* pointerToSample = samples[255]; // point to 256ths sample in the sample buffer
pointerToSample[127] = aValue;          // change value of 384ths sample (256+128) in our sample buffer with 512 elements

依旧...... 但如果你这样做,

double* pointerToSample;
pointerToSample[127] = aValue;

你正在写作未分配的内存!你的指针指向某处,但它背后没有分配的内存。 小心这个!如果samples变量已经超出范围,也永远不会访问pointerToSample:否则不会再分配内存指针ToTample指向的位置。

要在C ++中从堆中分配内存,需要动态关键字new(分配内存)和删除(以后释放内存)。

double *samples = new double[512];

将为您的样本数据分配一块内存。但使用它之后,你必须手动删除它 - 否则你会泄漏内存。所以就这样做:

delete[] samples;

完成后。

最后但并非最不重要的是回答你的问题如何创建一个二维数组来调用方法ProcessDoubleReplacing()

int main(int argc, char ** argv){
  /* create 2 dimensional array */
  int** samplesIn = new int*[44100];
  int** samplesOut = new int*[44100];
  for(int i = 0; i < 44100; ++i){   // 1s @ 44.1Khz
    samplesIn[i] = new int[2];      // stereo
    samplesOut[i] = new int[2];      // stereo
  }
  /* TODO: fill your input buffer with audio samples from somewhere i.e. file */
  ProcessDoubleReplacing(samplesIn, samplesOut, 44100);

  /* cleanup */
  for(int i = 0; i < 44100; ++i) {
    delete [] samplesIn[i];
    delete [] samplesOut[i];
  }
  delete [] samplesIn;
  delete [] samplesOut;

  return 0;
}

答案 1 :(得分:1)

@Constantin的答案几乎已经确定了,但我只是想在你的实现中添加它,你应该在你的process()回调中分配缓冲区。这样做可能会导致插件花费太多时间,因此系统会丢弃音频缓冲区,从而导致播放故障。

相反,这些缓冲区应该是主处理类的字段(即AEffect),您应该在构造函数中分配它们的大小。 从不new方法中使用deleteprocess(),否则您会遇到麻烦!

Here's a great guide关于实时音频节目的注意事项。

答案 2 :(得分:0)

如果你想用C ++写一些东西来提供类似你所展示的类似的界面,我会用std::vector来管理内存,如下所示:

vector<vector<double>> buffers (2,vector<double>(500));

这只存储数据。对于指针数组,您需要一个指针数组。 :)

vector<double*> pointers;
pointers.push_back(buffers[0].data());
pointers.push_back(buffers[1].data());

这是有效的,因为std::vector保证所有元素都存储在内存中并且线性存储。所以,你也可以这样做:

double** p = pointers.data();
p[0][123] = 17;
p[1][222] = 29;

重要的是要注意,如果你调整其中一些向量,指针可能会变得无效,在这种情况下你应该继续并获得新的指针。

请记住,data成员函数是C ++ 11的一项功能。如果您不想使用它,可以编写

&some_vector[0] // instead of some_vector.data()

(除非矢量为空)

不是将double **传递给某个函数,而是可能对通过引用直接传递缓冲区向量感兴趣,但是,如果您希望您的接口与C兼容,这显然不起作用。只是说。

修改:关于我选择std::vector超过new[]malloc的原因的说明:因为在现代C ++中这是正确的做法!在这种情况下搞乱的可能性较低。由于向量负责管理内存,因此不会有任何内存泄漏。这在C ++中尤为重要,因为您可能会有异常,因此在函数结束时使用delete[]之前可能会提前退出函数。