How to record sound in buffer using ALSA - c

I'm begining to learn linux and ALSA and I was wondering if there is a way to store the sound I record from a microphone a directly to the buffer. I read here http://www.linuxjournal.com/article/6735?page=0,2 how to make my recording program. But what I need is a little more complex. I need to record sound untill I hit a key. The reason I need this is because I'm messing with a RaspberryPI(debian on it) and to see if I could turn it into a sound monitoring/detecting device.
My main problem is now that when I try to use it to record (./Rec >name.raw ) it does nothing. It just ouputs an empty .raw file.
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <termios.h>
#include <alsa/asoundlib.h>
struct termios stdin_orig; // Structure to save parameters
void term_reset() {
tcsetattr(STDIN_FILENO,TCSANOW,&stdin_orig);
tcsetattr(STDIN_FILENO,TCSAFLUSH,&stdin_orig);
}
void term_nonblocking() {
struct termios newt;
tcgetattr(STDIN_FILENO, &stdin_orig);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking
newt = stdin_orig;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
atexit(term_reset);
}
int main() {
int key=0;
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
/* One channel (mono) */
snd_pcm_hw_params_set_channels(handle, params, 1);
/* 16000 bits/second sampling rate */
val = 16000;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
/* Set period size to 2048 frames. */
frames = 2048;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 2; /* 2 bytes/sample, 1 channels */
buffer = (char *) malloc(size);
while (key == 0)
{
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
}
else if (rc < 0)
{
fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
}
else if (rc != (int)frames)
{
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr, "short write: wrote %d bytes\n", rc);
key = getchar();
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}

Here is how I did that with python. Tested to work on my desktop Debian with USB Plantronics headphones. You need to install python-qt4 and python-pyaudio packages for this to work.
Also, you'll need to set your input device to microphone. In GNOME I switched both input and output devices via System Tools -> System Settings -> Sound. If you have Raspbian, not Debian on your Raspberry, as I do, it's gonna be tougher, cause there's LXDE instead of GNOME. You can use alsamixer and F6 button there to set audio cards, but the problem is that ALSA is low-level interface, while most Linuxes use some sound server on top of it, such as PulseAudio or JACK. You'll need some luck/spent time to make sure you switched input/output device to your mic/headphones.
If you use Jack microphone, plugged in through Jack input of your Raspberry Pi, note that Raspberry's Jack is input only, so you won't be able to play back your recordings and need some USB headphones to listen to your wav.
Personally, I feel that ALSA is very poorly documented (I suppose it's intentional job security) and I don't like to deal with it.
import pyaudio
import wave
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# This is Qt part: we create a window, which has a "stop" flag.
# Stop flag defaults to False, but is set to True, when you press a key.
# Value of that flag is checked in main loop and loop exits when flag is True.
app = QApplication(sys.argv)
class MyWindow(QWidget):
def __init__(self):
super(QWidget, self).__init__()
self.stop = False
def keyPressEvent(self, event):
print "keyPressedEvent caught!"
self.stop = True
window = MyWindow()
window.show()
# This is sound processing part: we create an input stream to read from microphone.
p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(2),
channels = 2,
rate=44100,
input=True,
output=False,
frames_per_buffer=1024)
# This is main loop: we iteratively poll audio and gui: audio data are stored in output_buffer,
# whereas gui is checked for stop flag value (if keyPressedEvent happened, flag will be set
# to True and break our main loop).
output_buffer = ""
while True:
app.processEvents()
data = stream.read(1024)
output_buffer += data
if window.stop: break
stream.stop_stream()
stream.close()
# Here we output contents of output_buffer as .wav file
output_wav = wave.open("output.wav", 'w')
output_wav.setparams((2, 2, 44100, len(output_buffer),"NONE","not compressed"))
output_wav.writeframesraw(output_buffer)
p.terminate()

This code shows you how to capture from ALSA in C++ in a while loop :
https://github.com/flatmax/gtkiostream/blob/master/test/ALSACaptureTest.C#L95
You can alter the loop there to record forever, replace :
while (N>0){
with
while (1){
Now you'll need some extra code. Firstly to read a character non-blocking add this to the top of the file :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define ngetc(c) (read (0, (c), 1))
ngetc is a non-blocking read from stdin. It returns -1 when nothing is read. It returns > 1 when you press the enter key.
So finally putting this all together, change :
while (N>0){
with
while (1){
int enter=ngetc(&ch);
if (enter>0)
break;

Related

How to send raw binary data over serial in C without non-native libraries in linux

I'm currently trying to send raw binary data in the format of decimal to an external device over serial. I currently have the data in a buffer array but would like it in a structure like this:
struct packetData{
uint8_t sync1;
uint8_t sync2;
uint16_t messageId;
uint16_t dataWordCount;
uint16_t flags;
uint16_t checksum;
};
I'm also using 9600 baud, and have all the termios settings set using cfmakeraw and I'm currently writing using:
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int flags = O_RDWR | O_NOCTTY | O_NDELAY;
fd = open(device, flags);
uint16_t buf_tx[BUFFER_SIZE] = {255,129,191,0,2057,0};
if(fd == -1){
printf("\n Failed to open port! ");
return -1;
}
tcgetattr(fd, &tty); //Get the current attributes of the Serial port
cfmakeraw(&tty);
cfsetispeed(&tty, B9600); //Set read speed as 9600 baud
cfsetospeed(&tty, B9600); //Set write speed as 9600 baud
if((tcsetattr(fd, TCSANOW, &tty)) != 0){
printf("Error! Can't set attributes.\n");
return -1;
}
else{
printf("Connection successful! \n");
}
while(x < 1000){
memset(buf_tx, 0, sizeof(buf_tx));
tcflush(fd, TCOFLUSH);
if(y < 5){
if(write(fd, buf_tx, 5) == -1){
printf("\n");
printf("Error>>: %s\n",strerror(errno));
y++;
}
}
tcflush(fd, TCIOFLUSH);
usleep(1000);
x++;
}
This code isnt the full code, just the setup/write parts so no need to worry about its syntax. if possible it would be nice not to have that buffer array and just use the struct directly, but I'll take what I can get.
It seems you have the serial port opening more or less in hand. I prefer to set the termios member components explicitly myself, but cfmakeraw() is perfectly fine too.
What you should consider, is having a separate function to send one or more of those structures at a time. For example,
int write_all(const int fd, const void *buf, const size_t len)
{
const char *data = buf;
size_t written = 0;
ssize_t n;
while (written < len) {
n = write(fd, data + written, len - written);
if (n > 0) {
written += n;
} else
if (n != -1) {
/* C library bug, should never occur */
errno = EIO;
return -1;
} else {
/* Error; n == -1, so errno is already set. */
return -1;
}
}
/* Success. */
return 0;
}
The function will return 0 if all data was successfully written, and -1 with errno set if an error occurs.
To send a struct packetData pkt; just use write_all(fd, &pkt, sizeof pkt).
To send a full array struct packetData pkts[5]; use write_all(fd, pkts, sizeof pkts).
To send n packets starting at pkts[i], use write_all(fd, pkts + i, n * sizeof pkts[0]).
However, you do not want to use tcflush(). It does not do what you think it does; it actually just discards data.
Instead, to ensure that the data you have written has been transmitted, you need to use tcdrain(fd).
I recommend against adding tcdrain(fd) at the end of write_all() function, because it blocks, pauses the program, until the data has been transmitted. This means that you should only use tcdrain() before you do something that requires the other end has received the transmission; for example before trying to read the response.
However, if this is a query-response interface, and you do intend to also read from the serial device, you should set tty.c_cc[VMIN] and tty.c_cc[VTIME] to reflect how you intend to use the interface. I prefer asynchronous full-duplex operation, but that requires select()/poll() handling. For half-duplex, with these exact structures only, you can use tty.c_cc[VMIN] = sizeof (struct packetData) with say tty.c_cc[VTIME] = 30, which causes read() to try and wait until a full structure is available, but at most 30 deciseconds (3.0 seconds). Something like tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 1; is more common; that causes read() to return a short count (even 0!) if there is no additional data received within a decisecond (0.1 seconds). Then, the receive function could be along the following lines:
int read_all(const int fd, void *buf, const size_t len)
{
char *const ptr = buf;
size_t have = 0;
ssize_t n;
/* This function is to be used with half-duplex query-response protocol,
so make sure we have transmitted everything before trying to
receive a response. Also assumes c_cc[VTIME] is properly set for
both the first byte of the response, and interbyte response interval
in deciseconds. */
tcdrain(fd);
while (have < len) {
n = read(fd, ptr + have, len - have);
if (n > 0) {
have += n;
} else
if (n == 0) {
/* Timeout or disconnect */
errno = ETIMEDOUT;
return -1;
} else
if (n != -1) {
/* C library bug, should never occur */
errno = EIO;
return -1;
} else {
/* Read error; errno set by read(). */
return -1;
}
}
/* Success; no errors. */
return 0;
}
If this returns -1 with errno == ETIMEDOUT, the other side took too long to answer. There may be remainder of the late response in the buffer, which you can discard with tcflush(TCIFLUSH) (or with tcflush(TCIOFLUSH), which also discards any written data not yet transmitted). Synchronization in this case is a bit difficult, because the above read_all() function doesn't return how many bytes it received (and therefore how many bytes to discard of a partial structure).
Sometimes the interface used always returns the number of bytes, but also sets errno (to 0 if no error occurred, and a nonzero error constant otherwise). That would be better for a query-response interface read and write functions, but many programmers find this use case "odd", even though it is perfectly okay by POSIX.1 standard (which is the relevant standard here).

play multiple wav files simultaneously using alsa c api

I want to implement a specific functionality to my project which includes continuously playing a sample-default.wav in the background and play a sample-specific.wav file when some specific condition matches. What I really want is that, when sample-specific.wav file is running, volume of sample-default.wav file becomes 0 (or simply, I want to mute sample-default.wav file when sample-specific.wav is running).
I am trying to implement this functionality using alsa-library for c. I have tried almost every approach to achieve this but nothing seems to works for me.
My current approach
I am trying to add two virtual sound devices using dmix plugin of alsa leaving default for system sounds. I searched google and find that I need to edit /etc/asound.conf file for creating different sound devices.
I added two sound devices, named notification and sample-sound. My current /etc/asound.conf file looks something like the one below:-
pcm.notification {
type dmix
ipc_key 1024
slave {
pcm "hw:1,0"
}
}
ctl.notification {
type hw
card 2
}
pcm.sample-sound {
type dmix
ipc_key 1025
slave {
pcm "hw:1,0"
}
}
ctl.sample-sound {
type hw
card 3
}
This works perfectly fine with aplay i.e. when I am playing sample-default.wav file using aplay by the following command:-
aplay -D plug:notification sample-default.wav
It works, but when i am trying to run the following code to play sample-default.wav using alsa library on my notification device:-
#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <pthread.h>
void default_sound (char * str) {
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
snd_pcm_uframes_t frames;
/* Open PCM device for playback */
int status = snd_pcm_open(&handle, "notification", SND_PCM_STREAM_PLAYBACK, 0);
if (status < 0) {
printf("Unable to open pcm deveice%s\n", snd_strerror(status));
return;
}
/* Allocate a hardware parameter obejct */
snd_pcm_hw_params_alloca(&params);
/* Fill it with default values */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
/* Single Channel (mono) */
snd_pcm_hw_params_set_channels(handle, params, 1);
/* sampling rate */
unsigned int sample_rate = 16000;
int dir;
snd_pcm_hw_params_set_rate_near(handle, params, &sample_rate, &dir);
/* set period size to 32 frames */
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
status = snd_pcm_hw_params(handle, params);
if(status < 0) {
printf("Unable to set hw params: %s\n", snd_strerror(status));
return;
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
int size = frames * 2;
char *buffer = (char *)malloc(size);
int readfd = open("sample-call.wav", O_RDONLY);
if(readfd < 0) {
printf("Error in opening wav file\n");
exit(1);
}
int readval;
while(readval = read(readfd, buffer, size) > 0) {
status = snd_pcm_writei(handle, buffer, frames);
if(status == -EPIPE) {
printf("underrun occured\n");
snd_pcm_prepare(handle);
}
else if(status < 0) {
printf("Error from writei: %s\n", snd_strerror(status));
}
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
}
int main() {
pthread_t pthread_id;
int status = pthread_create(&pthread_id, NULL, default_sound, "running");
if (status != 0) {
printf("Error in creating thread\n");
}
pthread_join(pthread_id, NULL);
return 0;
}
It compiles successfully but throws run-time error :-
8211 segmentation fault (core dumped) ./play-multiple-sound
I don't know what's going wrong with the above code.
If the above code works fine then I will play two sound files on two devices (notification and sample-sound) and control the volume of these devices using the alsa-mixer library which I have already implemented.
I am trying to achieve this from the past few weeks and none of the solution seems to work for me, so please help me out with this and if you know a better approach then please suggest.

Sound Recording & Play on Raspberry Pi Using ALSA in C

I am trying to record sound and play it in a C program.
just like using those terminal lines:
arecord -D plughw:0 -r 16000 sample.wav
for record, and later on
aplay sample.wav
to play the sound.
I used this code:
/*
This example reads from the default PCM device
and writes to standard output for 5 seconds of data.
*/
/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
int main() {
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default",
SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr,
"unable to open pcm device: %s\n",
snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params,
SND_PCM_FORMAT_S16_LE);
/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, 2);
/* 44100 bits/second sampling rate (CD quality) */
val = 44100;
snd_pcm_hw_params_set_rate_near(handle, params,
&val, &dir);
/* Set period size to 32 frames. */
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle,
params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr,
"unable to set hw parameters: %s\n",
snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params,
&frames, &dir);
size = frames * 4; /* 2 bytes/sample, 2 channels */
buffer = (char *) malloc(size);
/* We want to loop for 5 seconds */
snd_pcm_hw_params_get_period_time(params,
&val, &dir);
loops = 5000000 / val;
while (loops > 0) {
loops--;
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE) {
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
} else if (rc < 0) {
fprintf(stderr,
"error from read: %s\n",
snd_strerror(rc));
} else if (rc != (int)frames) {
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr,
"short write: wrote %d bytes\n", rc);
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
I compile this file this way:
gcc -o recorder -lasound recorder.c
and run it:
./recorder < sample.wav
if I try to play this with "aplay sample.wav" it's making a terrible noisy sound.
but if I use "aplay -t raw -f S16_LE -c2 -r44100 sample.wav"
it works good.
what I do wrong and if there is an easy way to capture audio and play it on Raspberry Pi?
Thank You for Your time.
Its just a basic thing, when you are trying aplay sample.wav" "aplay" will look for wave header and its not there in your file. So its playing with some other format (Sampling frequency,Channels, etc ..). That why your audio become noisy.
But in aplay -t raw -f S16_LE -c2 -r44100 sample.wav you are providing all information needed and its working fine.

How to record sound in buffer using ALSA [duplicate]

I'm begining to learn linux and ALSA and I was wondering if there is a way to store the sound I record from a microphone a directly to the buffer. I read here http://www.linuxjournal.com/article/6735?page=0,2 how to make my recording program. But what I need is a little more complex. I need to record sound untill I hit a key. The reason I need this is because I'm messing with a RaspberryPI(debian on it) and to see if I could turn it into a sound monitoring/detecting device.
My main problem is now that when I try to use it to record (./Rec >name.raw ) it does nothing. It just ouputs an empty .raw file.
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <termios.h>
#include <alsa/asoundlib.h>
struct termios stdin_orig; // Structure to save parameters
void term_reset() {
tcsetattr(STDIN_FILENO,TCSANOW,&stdin_orig);
tcsetattr(STDIN_FILENO,TCSAFLUSH,&stdin_orig);
}
void term_nonblocking() {
struct termios newt;
tcgetattr(STDIN_FILENO, &stdin_orig);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // non-blocking
newt = stdin_orig;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
atexit(term_reset);
}
int main() {
int key=0;
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0) {
fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
/* One channel (mono) */
snd_pcm_hw_params_set_channels(handle, params, 1);
/* 16000 bits/second sampling rate */
val = 16000;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
/* Set period size to 2048 frames. */
frames = 2048;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0) {
fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 2; /* 2 bytes/sample, 1 channels */
buffer = (char *) malloc(size);
while (key == 0)
{
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "overrun occurred\n");
snd_pcm_prepare(handle);
}
else if (rc < 0)
{
fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
}
else if (rc != (int)frames)
{
fprintf(stderr, "short read, read %d frames\n", rc);
}
rc = write(1, buffer, size);
if (rc != size)
fprintf(stderr, "short write: wrote %d bytes\n", rc);
key = getchar();
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
Here is how I did that with python. Tested to work on my desktop Debian with USB Plantronics headphones. You need to install python-qt4 and python-pyaudio packages for this to work.
Also, you'll need to set your input device to microphone. In GNOME I switched both input and output devices via System Tools -> System Settings -> Sound. If you have Raspbian, not Debian on your Raspberry, as I do, it's gonna be tougher, cause there's LXDE instead of GNOME. You can use alsamixer and F6 button there to set audio cards, but the problem is that ALSA is low-level interface, while most Linuxes use some sound server on top of it, such as PulseAudio or JACK. You'll need some luck/spent time to make sure you switched input/output device to your mic/headphones.
If you use Jack microphone, plugged in through Jack input of your Raspberry Pi, note that Raspberry's Jack is input only, so you won't be able to play back your recordings and need some USB headphones to listen to your wav.
Personally, I feel that ALSA is very poorly documented (I suppose it's intentional job security) and I don't like to deal with it.
import pyaudio
import wave
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
# This is Qt part: we create a window, which has a "stop" flag.
# Stop flag defaults to False, but is set to True, when you press a key.
# Value of that flag is checked in main loop and loop exits when flag is True.
app = QApplication(sys.argv)
class MyWindow(QWidget):
def __init__(self):
super(QWidget, self).__init__()
self.stop = False
def keyPressEvent(self, event):
print "keyPressedEvent caught!"
self.stop = True
window = MyWindow()
window.show()
# This is sound processing part: we create an input stream to read from microphone.
p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(2),
channels = 2,
rate=44100,
input=True,
output=False,
frames_per_buffer=1024)
# This is main loop: we iteratively poll audio and gui: audio data are stored in output_buffer,
# whereas gui is checked for stop flag value (if keyPressedEvent happened, flag will be set
# to True and break our main loop).
output_buffer = ""
while True:
app.processEvents()
data = stream.read(1024)
output_buffer += data
if window.stop: break
stream.stop_stream()
stream.close()
# Here we output contents of output_buffer as .wav file
output_wav = wave.open("output.wav", 'w')
output_wav.setparams((2, 2, 44100, len(output_buffer),"NONE","not compressed"))
output_wav.writeframesraw(output_buffer)
p.terminate()
This code shows you how to capture from ALSA in C++ in a while loop :
https://github.com/flatmax/gtkiostream/blob/master/test/ALSACaptureTest.C#L95
You can alter the loop there to record forever, replace :
while (N>0){
with
while (1){
Now you'll need some extra code. Firstly to read a character non-blocking add this to the top of the file :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define ngetc(c) (read (0, (c), 1))
ngetc is a non-blocking read from stdin. It returns -1 when nothing is read. It returns > 1 when you press the enter key.
So finally putting this all together, change :
while (N>0){
with
while (1){
int enter=ngetc(&ch);
if (enter>0)
break;

Cannot open /dev/dsp

I am trying to learn audio recording, so I compiled The following code that I found online , but for some reason I cannot open /dev/dsp. I tried killing pulseaudio, but it re-opens as soon as I killall it. I really don't know what I am doing; I've been struggling for the latter part of the week. Please help.
I also tried chmod o+rw /dev/dsp
/*
* parrot.c
* Program to illustrate /dev/dsp device
* Records several seconds of sound, then echoes it back.
* Runs until Control-C is pressed.
*/
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <linux/soundcard.h>
#define LENGTH 3 /* how many seconds of speech to store */
#define RATE 8000 /* the sampling rate */
#define SIZE 8 /* sample size: 8 or 16 bits */
#define CHANNELS 1 /* 1 = mono 2 = stereo */
/* this buffer holds the digitized audio */
unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];
int main()
{
int fd; /* sound device file descriptor */
int arg; /* argument for ioctl calls */
int status; /* return status of system calls */
/* open sound device */
fd = open("/dev/dsp", O_RDWR);
if (fd < 0) {
perror("open of /dev/dsp failed");
exit(1);
}
/* set sampling parameters */
arg = SIZE; /* sample size */
status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_BITS ioctl failed");
if (arg != SIZE)
perror("unable to set sample size");
arg = CHANNELS; /* mono or stereo */
status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
if (arg != CHANNELS)
perror("unable to set number of channels");
arg = RATE; /* sampling rate */
status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_WRITE ioctl failed");
while (1) { /* loop until Control-C */
printf("Say something:\n");
status = read(fd, buf, sizeof(buf)); /* record some sound */
if (status != sizeof(buf))
perror("read wrong number of bytes");
printf("You said:\n");
status = write(fd, buf, sizeof(buf)); /* play it back */
if (status != sizeof(buf))
perror("wrote wrong number of bytes");
/* wait for playback to complete before recording again */
status = ioctl(fd, SOUND_PCM_SYNC, 0);
if (status == -1)
perror("SOUND_PCM_SYNC ioctl failed");
}
}
See, /dev/dsp was used on older versions of ubuntu linux. It's no longer available in newer versions of ubuntu. I think it was gone with 10.04. Things changed from 10.10.
From one of the websites:
10.10 Maverick finally disabled the very old OSS drivers (which provided /dev/dsp, so the padsp wrapper is the easiest way to handle if it you can't select ALSA or PulseAudio directly.
See this http://manpages.ubuntu.com/manpages/hardy/man1/padsp.1.html

Resources