So I'm using alsa to capture audio from a microphone and eventually I want to process samples from each channel. This type of low level programming is quite new to me.
However I'm a little confused, most of the examples using alsa store the samples for audio captured in format PCM_FORMAT_S16_LE in a char buffer. I understand it's not really a char buffer but a byte buffer. The device I'm using has four channels so from what I understand I have a 16 bit number stored in two bytes in the char buffer. Where 2 bytes/sample, and then 4 channels are interleaved.
Here's my code for capturing, I've omitted the hw setup as it's not important to my question.
char *buffer;
further down the program...
snd_pcm_params_get_period_size(params, &frames, &dir);
size = frames *8; /* 2 bytes/sample, 4 channels */
buffer = (char *) malloc(size);
snd_pcm_hw_params_get_period_time(params, &val, &dir);
loops = 5000000 / val;
while (loops > 0)
{
loops--;
capture = send_pcm_readi(handle, buffer, frames);
if (capture == -EPIPE)
{
fprintf(stderr, "overrun occured");
snd_pcm_prepare(handle);
}
else if (capture <0)
{
fprintf(stderr, "error from read: %s\n", snd_strerror(capture));
}
else if(capture != (int)frames)
{
fprintf(stderr, "short read, read %d frames\n", capture);
}
/*
Process values
*/
}
What I would like to do is be able to convert each sample to a voltage or a dB value in order to do some further processing. I know the data is correct as I can write the samples into a text file and for example audacity can interpret the raw data to be a four channel audio file.
However, I'm confused as to how I get this information directly from the char buffer?
When you have signed 16-bit samples, you should use a signed 16-bit data type for your buffer:
typedef short int s16;
s16 *buffer = malloc(size_in_bytes);
(You should use SND_PCM_FORMAT_S16
to get the endianness correct.)
In the buffer, every four values are one frame.
for (i = 0; i < capture; i++) {
ch1 = buffer[i * 4 + 0];
ch2 = buffer[i * 4 + 1];
ch3 = buffer[i * 4 + 2];
ch4 = buffer[i * 4 + 3];
// or use a loop over 0..3
...
}
Alternatively, if you want to access all the samples of one specific channel, go over the buffer in steps of four:
// for the first channel
for (i = 0; i < capture; i++) {
sample = buffer[i * 4 + 0];
...
}