简体   繁体   中英

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.

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.

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. This is the first time I work with Audio and ALSA. I am trying to avoid using python for now as I want to learn a bit more.

If you believe that it is not worth writing this on C++ I will do it in 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. The second part discusses how to use C++ to read audio data from the ALSA sound card.

Part 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". 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).

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).
  3. Take the logarithm of the RMS value for each column.
  4. Work out how to map each channel's log(RMS) value onto the LEDs. 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. Then work out how to map these 24 bits onto LEDs to achieve your aim.

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

You can use gtkiostream to implement C++ classes for handling audio with ALSA.

For example this ALSA::Capture class allows you to capture audio for processing.

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 :

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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