简体   繁体   English

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

[英]Capture default audio stream with ALSA in C++

I am doing a fun project to change Philips Hue bulb lights color based on the sound that is coming from the default ALSA device.我正在做一个有趣的项目,根据来自默认 ALSA 设备的声音来改变飞利浦 Hue 灯泡的颜色。

I want to write small C++ program that captures and analyzes default audio stream and split it into 3 changes low, mid, and high, then assing those channels to red, green, and blue.我想编写一个小的 C++ 程序来捕获和分析默认的音频流,并将其分成低、中和高 3 个变化,然后将这些通道分配为红色、绿色和蓝色。

I am trying to read how to create ALSA devices but I am struggling to figure out and Google how to capture streams with ALSA.我正在尝试阅读如何创建 ALSA 设备,但我正在努力弄清楚和谷歌如何使用 ALSA 捕获流。 This is the first time I work with Audio and ALSA.这是我第一次使用 Audio 和 ALSA。 I am trying to avoid using python for now as I want to learn a bit more.我现在尽量避免使用 python,因为我想了解更多。

If you believe that it is not worth writing this on C++ I will do it in python.如果你认为用 C++ 写这个不值得,我会用 python 来做。

This answer is broken into two parts.这个答案分为两部分。 The first part discusses how to take the audio data and use it to represent LED "bits" for use in LED brightness setting.第一部分讨论如何获取音频数据并使用它来表示 LED 的“位”以用于 LED 亮度设置。 The second part discusses how to use C++ to read audio data from the ALSA sound card.第二部分讨论如何使用C++从ALSA声卡中读取音频数据。

Part 1第 1 部分

An idea for splitting into RGB, you could work out how to convert the audio samples into 24 bit representation in a "perceptual manner".拆分为 RGB 的想法,您可以弄清楚如何以“感知方式”将音频样本转换为 24 位表示。 As we hear nonlinearly, you probably want to take the logarithm of the audio data.当我们听到非线性时,您可能想要取音频数据的对数。 Because the audio data is both positive and negative, you probably want to do this on its absolute value.由于音频数据有正有负,您可能希望根据其绝对值来执行此操作。 Finally for each buffer read from the ADC audio input, you probably want to take the RMS first (which will handle doing the absolute value for you).最后,对于从 ADC 音频输入读取的每个缓冲区,您可能希望首先获取 RMS (它将为您处理绝对值)。

So the steps in processing would be :所以处理步骤是:

  1. Capture the audio buffer捕获音频缓冲区
  2. Take the RMS for each column of the audio buffer (each column is an audio channel).获取音频缓冲区每一列的 RMS(每一列是一个音频通道)。
  3. Take the logarithm of the RMS value for each column.取每列的 RMS 值的对数。
  4. Work out how to map each channel's log(RMS) value onto the LEDs.找出如何将每个通道的 log(RMS) 值映射到 LED 上。 One idea is to use log base 2 (log2) of the RMS of the audio data as that will give you 32 bits of data, which you can divide down (rotate by 8 : log2(RMS) << 8) to get a 24 bit representation.一种想法是使用音频数据的 RMS 的对数基数 2 (log2),因为这将为您提供 32 位数据,您可以将其除以(旋转 8 : log2(RMS) << 8)以获得 24位表示。 Then work out how to map these 24 bits onto LEDs to achieve your aim.然后找出如何将这 24 位映射到 LED 上以实现您的目标。

For example in pseudo code :例如在伪代码中:

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);

Part 2第 2 部分

You can use gtkiostream to implement C++ classes for handling audio with ALSA.您可以使用 gtkiostream 来实现 C++ 类,以便使用 ALSA 处理音频。

For example this ALSA::Capture class allows you to capture audio for processing.例如, 这个 ALSA::Capture类允许您捕获音频以进行处理。

To use it you include it into your code :要使用它,请将其包含在代码中:

#include "ALSA/ALSA.H"
using namespace ALSA;

Then you can stream in audio to a matrix (matrix columns are audio channels).然后您可以将音频流式传输到矩阵(矩阵列是音频通道)。 First however you instantiate the class in your C++ code :但是,首先在 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
}

A more complete capture example is available here . 此处提供了更完整的捕获示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM