c++ - 在 C++ 中使用 ALSA 捕获默认音频流

标签 c++ audio alsa audio-analysis

我正在做一个有趣的项目,根据来自默认 ALSA 设备的声音来更改飞利浦 Hue 灯泡的颜色。

我想编写一个小的 C++ 程序来捕获和分析默认音频流并将其分成 3 个低、中和高变化,然后将这些 channel 分配为红色、绿色和蓝色。

我正在尝试阅读如何创建 ALSA 设备,但我正在努力弄清楚 Google 如何使用 ALSA 捕获流。这是我第一次使用 Audio 和 ALSA。我现在试图避免使用 python,因为我想了解更多。

如果您认为在 C++ 上编写此内容不值得,我将在 python 中进行。

最佳答案

这个答案分为两部分。第一部分讨论如何获取音频数据并使用它来表示 LED“位”以用于 LED 亮度设置。第二部分讨论如何使用 C++ 从 ALSA 声卡中读取音频数据。

第 1 部分

拆分为 RGB 的想法,您可以弄清楚如何以“感知方式”将音频样本转换为 24 位表示。正如我们听到的非线性声音,您可能希望对音频数据取对数。因为音频数据既是正数也是负数,您可能希望对其绝对值执行此操作。最后,对于从 ADC 音频输入读取的每个缓冲区,您可能想要 take the RMS首先(它将为您处理绝对值)。

所以处理的步骤是:

  • 捕获音频缓冲区
  • 获取音频缓冲区每一列的 RMS(每一列都是一个音频 channel )。
  • 取每一列的 RMS 值的对数。
  • 找出如何将每个 channel 的 log(RMS) 值映射到 LED 上。一个想法是使用音频数据的 RMS 的对数基数 2 (log2),因为这将为您提供 32 位数据,您可以将其除以(旋转 8 :log2(RMS) << 8)以获得 24位表示。然后研究如何将这 24 位映射到 LED 上以实现您的目标。

  • 例如在伪代码中:
    float loudness=log2(RMS(buffer);
    if (loudness)>pow(2.,16.))
      setTheRedLED(loudness/pow(2.,16.));
    else if (loudness)>pow(2.,8.))
      setTheBlueLED(loudness/pow(2.,8.));
    else
      setTheGreenLED(loudness);
    

    第 2 部分

    您可以使用 gtkiostream 来实现 C++ 类,以便使用 ALSA 处理音频。

    例如 this ALSA::Capture类允许您捕获音频进行处理。

    要使用它,请将其包含在您的代码中:
    #include "ALSA/ALSA.H"
    using namespace ALSA;
    

    然后您可以将音频流式传输到矩阵(矩阵列是音频 channel )。但是,首先您在 C++ 代码中实例化该类:
    Capture capture("hw:0"); // to open the device hw:0 you could use "default" or another device
    // you can now reset params if you don't want to use the default, see here : https://github.com/flatmax/gtkiostream/blob/master/applications/ALSACapture.C#L82
    capture.setParams(); // set the parameters
    if (!capture.prepared()){
        cout<<"should be prepared, but isn't"<<endl;
        return -1;
    }
    
    // now define your audio buffer you want to use for signal processing
    Eigen::Array<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> buffer(latency, chCnt);
    
    // start capturing
    if ((res=capture.start())<0) // start the device capturing
        ALSADebug().evaluateError(res);
    
    cout<<"format "<<capture.getFormatName(format)<<endl;
    cout<<"channels "<<capture.getChannels()<<endl;
    cout<<"period size "<<pSize<<endl;
    
    // now do an infinite loop capturing audio and then processing it to do what you want.
    while (true){
        capture>>buffer; // capture the audio to the buffer
        // do something with the audio in the buffer to separate out for red blue and green
    }
    

    更完整的捕获示例是 available here .

    关于c++ - 在 C++ 中使用 ALSA 捕获默认音频流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40434279/

    相关文章:

    python - 无法从 linux、c++ 执行 "main(filename)"python 脚本的 "my_script"函数; pModule = PyImport_Import(pName);返回空

    c++ - 字符集 - 不清楚

    c++ - 可以将两个连续的相同类型的数组视为一个吗?

    c++ - 使用 Chromaprint 时的空白声学指纹

    javascript - Web音频增益节点未完全静音

    clock - Raspberry Pi - 添加 RTC 后音频失败

    audio - 在 Linux 上以低延迟捕获声音

    c++ - 当宏扩展为空时,临时变量会发生什么?

    silverlight - Silverlight应用程序如何从URL下载并播放mp3文件?

    audio - 在Linux中创建克隆输入音频设备