【问题标题】:Capture default audio stream with ALSA in C++在 C++ 中使用 ALSA 捕获默认音频流
【发布时间】:2017-03-18 23:20:31
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你没有找到任何例子吗?
  • 仅适用于 python。但我想用 C/C++ 编写它,这就是我问的原因,因为我在 C/C++ 上找到的示例无法正常工作,因为它们太旧了。
  • gist.github.com/albanpeignier/104902 。实际上你可以使用 C 本身。我已经在我的系统和它的工作中尝试过。

标签: c++ audio alsa audio-analysis


【解决方案1】:

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

第 1 部分

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

所以处理步骤是:

  1. 捕获音频缓冲区
  2. 获取音频缓冲区每一列的 RMS(每一列都是一个音频通道)。
  3. 对每列的 RMS 值取对数。
  4. 找出如何将每个通道的 log(RMS) 值映射到 LED 上。一个想法是使用音频数据的 RMS 的对数基数 2 (log2),因为这将为您提供 32 位数据,您可以将其除以(旋转 8 :log2(RMS)

例如在伪代码中:

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;

然后您可以将音频流式传输到矩阵(矩阵列是音频通道)。但是,首先您要在 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    • 2013-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多