【问题标题】:C++ ASIO, accessing buffersC++ ASIO,访问缓冲区
【发布时间】:2015-01-09 00:51:18
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

  • 我相信boost-asio标签不适用于这个问题,你问的是音频相关的SDK,而不是异步io模块。
  • 你说得对,我已经编辑过了,谢谢。

标签: c++ audio asio steinberg-asio


【解决方案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,依此类推。您可以在asio.h 的ASIOSampleType 枚举中找到值列表。此时,您需要将样本转换为下游信号处理代码的一些通用格式。如果您正在进行信号处理,您可能希望转换为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...

【讨论】:

  • 谢谢伙计。那真的奏效了。虽然我在我的设备和程序中播放音乐我只得到 0.0,但我仍然访问了内存块并获得了价值。
  • 其实 :D 像这样:*((int*)asioDriverInfo.bufferInfos.buffers[index]+i) and double* pDoubleBuf = new double[_bufferSize];不应该在回调或循环中,因为它是内存泄漏
【解决方案2】:

非常感谢。您的回答很有帮助,但由于我对 C++ 有点缺乏经验:P 我觉得这有点问题。

一般来说,我已经基于 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 *'
    

我没有得到的是,在您的示例中没有表:在 bufferInfos 之后的 asioDriverInfo.bufferInfos.buffers[index] 即使我修复它......我应该将它转换为哪种类型这行得通。 P

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

【讨论】:

  • 我刚刚更新了我的答案以处理错误。您需要从 void* 转换为您需要的任何数据类型。对于只属于 int 的 32 位类型。对于 24 位类型,您需要转换为字节,然后将其转换为 int,依此类推。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 2017-10-13
    • 2021-08-29
    相关资源
    最近更新 更多