slowrx/pcm.c

144 wiersze
4.0 KiB
C
Czysty Zwykły widok Historia

2011-08-07 17:46:35 +00:00
#include <stdio.h>
#include <stdlib.h>
2011-08-20 11:49:29 +00:00
#include <stdbool.h>
2011-08-16 21:29:38 +00:00
#include <string.h>
2011-08-07 17:46:35 +00:00
#include <gtk/gtk.h>
#include <alsa/asoundlib.h>
2011-08-16 21:29:38 +00:00
#include <fftw3.h>
2011-08-07 17:46:35 +00:00
#include "common.h"
2011-08-16 21:29:38 +00:00
/*
* Stuff related to sound card capture
*
*/
2011-08-07 17:46:35 +00:00
2011-08-20 05:51:27 +00:00
// Capture fresh PCM data to buffer
2011-08-16 21:29:38 +00:00
void readPcm(gint numsamples) {
int samplesread, i;
2012-04-02 08:59:52 +00:00
gint32 tmp[BUFLEN]; // Holds one or two 16-bit channels, will be ANDed to single channel
2011-08-16 21:29:38 +00:00
samplesread = snd_pcm_readi(pcm_handle, tmp, (PcmPointer == 0 ? BUFLEN : numsamples));
if (samplesread < numsamples) {
if (samplesread == -EPIPE) printf("ALSA: buffer overrun\n");
else if (samplesread == -EBADFD) printf("ALSA: PCM is not in the right state\n");
else if (samplesread == -ESTRPIPE) printf("ALSA: a suspend event occurred\n");
else if (samplesread < 0) printf("ALSA error %d\n", samplesread);
else printf("Can't read %d samples\n", numsamples);
exit(EXIT_FAILURE);
}
if (PcmPointer == 0) {
// Fill buffer on first run
for (i=0; i<BUFLEN; i++)
PcmBuffer[i] = tmp[i] & 0xffff;
2011-08-16 21:29:38 +00:00
PcmPointer = BUFLEN/2;
} else {
for (i=0; i<BUFLEN-numsamples; i++) PcmBuffer[i] = PcmBuffer[i+numsamples];
2011-08-20 05:51:27 +00:00
for (i=0; i<numsamples; i++) {
PcmBuffer[BUFLEN-numsamples+i] = tmp[i] & 0xffff;
2011-08-20 05:51:27 +00:00
// Keep track of max power for VU meter
if (abs(PcmBuffer[i]) > MaxPcm) MaxPcm = abs(PcmBuffer[i]);
2011-08-20 05:51:27 +00:00
}
2011-08-16 21:29:38 +00:00
PcmPointer -= numsamples;
}
}
// Initialize sound card
2011-08-07 17:46:35 +00:00
void initPcmDevice() {
2011-08-08 21:36:47 +00:00
int card;
char *cardname;
int cardnum, numcards;
snd_pcm_stream_t PcmInStream = SND_PCM_STREAM_CAPTURE;
snd_pcm_hw_params_t *hwparams;
char pcm_name[30];
unsigned int exact_rate = 44100;
2011-08-07 17:46:35 +00:00
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cardcombo), "default");
numcards = 0;
card = -1;
do {
snd_card_next(&card);
if (card != -1) {
snd_card_get_name(card,&cardname);
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cardcombo), cardname);
numcards++;
}
} while (card != -1);
2011-08-08 21:36:47 +00:00
// Select sound card
2011-08-07 17:46:35 +00:00
if (numcards == 0) {
printf("No sound cards found!\n");
exit(EXIT_SUCCESS);
} else {
cardnum = 2;
2011-08-07 17:46:35 +00:00
}
2011-08-09 13:17:55 +00:00
gtk_combo_box_set_active(GTK_COMBO_BOX(cardcombo), 0);
2011-08-07 17:46:35 +00:00
snd_pcm_hw_params_alloca(&hwparams);
while (true) {
if (cardnum == 0) {
sprintf(pcm_name,"default");
} else {
sprintf(pcm_name,"hw:%d",cardnum-1);
}
if (snd_pcm_open(&pcm_handle, pcm_name, PcmInStream, 0) < 0) {
fprintf(stderr, "ALSA: Error opening PCM device %s\n", pcm_name);
if (cardnum == 0) {
exit(EXIT_FAILURE);
} else {
cardnum--;
}
} else {
break;
}
2011-08-07 17:46:35 +00:00
}
/* Init hwparams with full configuration space */
if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
fprintf(stderr, "ALSA: Can not configure this PCM device.\n");
exit(EXIT_FAILURE);
}
if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
fprintf(stderr, "ALSA: Error setting interleaved access.\n");
exit(EXIT_FAILURE);
}
if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
fprintf(stderr, "ALSA: Error setting format S16_LE.\n");
exit(EXIT_FAILURE);
}
if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0) < 0) {
fprintf(stderr, "ALSA: Error setting sample rate.\n");
exit(EXIT_FAILURE);
}
if (exact_rate != 44100) fprintf(stderr, "ALSA: Using %d Hz instead of 44100.\n", exact_rate);
2012-04-02 08:59:52 +00:00
// Try stereo first
if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) {
// Fall back to mono
if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 1) < 0) {
fprintf(stderr, "ALSA: Error setting channels.\n");
exit(EXIT_FAILURE);
}
2011-08-07 17:46:35 +00:00
}
if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) {
fprintf(stderr, "ALSA: Error setting HW params.\n");
exit(EXIT_FAILURE);
}
2011-08-16 21:29:38 +00:00
PcmBuffer = calloc( BUFLEN, sizeof(gint16));
2011-08-07 17:46:35 +00:00
}