使用C ++中的ALSA捕获默认音频流

时间:2016-11-05 02:51:35

标签: c++ audio alsa audio-analysis

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

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

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

如果你认为不值得在C ++上写这个,我会用python来做。

1 个答案:

答案 0 :(得分:0)

此答案分为两部分。第一部分讨论如何获取音频数据并使用它来表示用于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)<< 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;

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