0

我没有音频编程经验,而且 C++ 是相当低级的语言,所以我对它有一点问题。我使用从http://www.steinberg.net/en/company/developers.html下载的 ASIO SDK 2.3 。

我正在根据 SDK 中的示例编写自己的主机。

现在我已经设法完成了整个样本,看起来它正在工作。我有外部声卡连接到我的电脑。我已经成功地为这个设备加载了驱动程序,配置了它,处理了回调,将数据从模拟转换为数字等常见的东西。

我现在卡住的部分:当我通过我的设备播放一些曲目时,我可以看到混音器(设备的软件)中的条形移动。所以设备以正确的方式连接。在我的代码中,我选择了带有在混音器中移动的条形名称的输入和输出。我还使用 ASIOCreateBuffers() 为每个输入/输出创建缓冲区。

  1. 如果我错了,现在纠正我:当调用 ASIOStart() 并且驱动程序处于运行状态时,当我将声音信号输入到外部设备时,我相信缓冲区已充满数据,对吗?

  2. 我正在阅读文档,但我有点迷茫 - 如何访问设备发送到应用程序、存储在 INPUT 缓冲区中的数据?还是信号?我需要它来进行信号分析或将来记录。

编辑:如果我让它变得复杂,那么简而言之,我的问题是:如何从代码访问输入流数据?我在文档中看不到任何让我这样做的对象/回调。

4

3 回答 3

1

ASIO SDK 中的主机示例非常接近您的需要。在bufferSwitchTimeInfo回调中有一些这样的代码:

for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
    int ch = asioDriverInfo.bufferInfos[i].channelNum;
    if (asioDriverInfo.bufferInfos[i].isInput == ASIOTrue)
    {
        char* buf = asioDriver.bufferInfos[i].buffers[index];
        ....

其中 if 块asioDriver.bufferInfos[i].buffers[index]是指向原始音频数据的指针(index是方法的参数)。

缓冲区的格式取决于驱动程序,可以通过测试发现asioDriverInfo.channelInfos[i].type。格式的类型将是 32bit int LSB first,32bit int MSB first,依此类推。您可以在ASIOSampleType枚举中找到值列表asio.h。此时,您需要将样本转换为下游信号处理代码的一些通用格式。如果您正在进行信号处理,您可能需要转换为double. 该文件host\asioconvertsample.cpp将使您了解转换中涉及的内容。您将遇到的最常见格式可能是 INT32 MSB。这是您将其转换为双倍的方法。

for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
{
    int ch = asioDriverInfo.bufferInfos[i].channelNum;
    if (asioDriverInfo.bufferInfos[i].isInput == ASIOTrue)
    {
        switch (asioDriverInfo.channelInfos[i].type)
        {
            case ASIOInt32LSB:
            {
                double* pDoubleBuf = new double[_bufferSize];
                for (int i = 0 ; i < _bufferSize ; ++i)
                {
                    pDoubleBuf[i] = *(int*)asioDriverInfo.bufferInfos.buffers[index] / (double)0x7fffffff;
                }
                // now pDoubleBuf contains one channels worth of samples in the range of -1.0 to 1.0.
                break;
            }
            // and so on...
于 2015-01-09T06:34:38.530 回答
0

非常感谢。您的回答很有帮助,但由于我对 C++ 有点缺乏经验:PI 发现它有点问题。

一般来说,我已经基于 hostsample 编写了自己的主机。我暂时没有实现 asioDriverInfo 结构并使用公共变量。

  1. 我的第一个问题是:。

    char* buf = asioDriver.bufferInfos[i].buffers[index];
    

    因为我得到了我不能将 (void*) 转换为 char* 的错误,但这可能解决了问题:

    char* buf = static_cast<char*>(bufferInfos[i].buffers[doubleBufferIndex]);
    
  2. 我的第二个问题是数据转换。我检查了你推荐给我的文件,但我觉得它有点黑魔法。现在,我正在尝试按照您的示例进行操作,并且:

    for (int i = 0; i < inputBuffers + outputBuffers; i++)
    {
        if (bufferInfos[i].isInput) 
        {
            switch (channelInfos[i].type)
            {
                case ASIOSTInt32LSB:
                {
                    double* pDoubleBuf = new double[buffSize];
                    for (int j = 0 ; j < buffSize ; ++j)
                    {
                        pDoubleBuf[j] = bufferInfos[i].buffers[doubleBufferIndex] / (double)0x7fffffff; 
                    }
                    break;
                }
            }
        } 
    

    我在那里得到错误:

    pDoubleBuf[j] = bufferInfos[i].buffers[doubleBufferIndex] / (double)0x7fffffff; 
    

    这是:

    error C2296: '/' : illegal, left operand has type 'void *'
    

我没有得到的是,在您的示例中,那里没有表: asioDriverInfo.bufferInfos.buffers[index] 在 bufferInfos 之后,即使我修复它......我应该将它转换为哪种类型以使其工作。磷

PS。我确信 ASIOSTInt32LSB 数据类型适用于我的 PC。

于 2015-01-09T07:57:44.587 回答
0

可以使用 void 指针访问 ASIO 输入和输出缓冲区,但是使用 memcpy 或 memmove 访问 I/O 缓冲区将创建一个内存副本,如果您正在进行实时处理,则应避免这种情况。我建议将指针类型转换为 int* 以便您可以直接访问它们。

当大多数 CPU 都支持 AVX2 时,当您拥有 100 多个音频通道时,将类型 1 逐 1 转换为实时处理也非常慢。_mm256_loadu_si256() 和 _mm256_cvtepi32_ps() 会更快地完成转换。

于 2020-01-16T10:35:12.127 回答