Clarification of Question by
ignorant-ga
on
15 Jan 2005 12:18 PST
As you will see in the code below, there are a mess of calls in pre_record() of
the form snd_pcm_... Honestly, I have little clue about why; they seem to be
needed to make recording work. If anyone can give an in depth explanation of
what is going on with them, the money is yours --- and i'm increasing it to $20
Following is a reasonably "minimal" program that records (I promised to post):
#define _GNU_SOURCE
#include <stdlib.h>
#include <alsa/asoundlib.h>
#include "formats.h"
static struct
{
snd_pcm_format_t format;
unsigned int channels;
unsigned int rate;
} Hwparams = {SND_PCM_FORMAT_S16_LE, 2, 44100};
static snd_pcm_uframes_t Frames;
static size_t Bytes_per_frame;
static snd_pcm_t *Handle;
void pcm_read_frames(u_char *d)
{
long r, s = Frames;
while (s > 0) {
if ((r = snd_pcm_readi(Handle,d,s)) > 0) {
s -= r;
d += r * Bytes_per_frame;
} else if (r == -EAGAIN || ((r < s) && !(r < 0)))
snd_pcm_wait(Handle,1000);
}
}
#define Sz(x) sizeof(x)
void pre_record(int fd, long bytes)
{
long buffer_time = 500000, period_time = buffer_time/4;
snd_pcm_uframes_t buffer_frames, buffer_size, period_frames, xfer_align;
WaveChunkHeader wch, ch = {WAV_FMT,16};
WaveHeader h;
WaveFmtBody f;
snd_pcm_hw_params_t *params;
snd_pcm_sw_params_t *swparams;
snd_pcm_open(&Handle,"default",SND_PCM_STREAM_CAPTURE,0);
wch.type = WAV_DATA;
wch.length = bytes & 0x7fffffff;
h.magic = WAV_RIFF;
h.length = bytes+Sz(WaveHeader)+Sz(WaveChunkHeader)+Sz(WaveFmtBody)+Sz(WaveChunkHeader)-8;
h.type = WAV_WAVE;
f.format = WAV_PCM_CODE;
f.modus = Hwparams.channels;
f.sample_fq = Hwparams.rate;
f.byte_p_spl = Hwparams.channels*snd_pcm_format_physical_width(Hwparams.format)/8;
f.byte_p_sec = f.byte_p_spl*Hwparams.rate;
f.bit_p_spl = 16;
write(fd, &h , Sz(WaveHeader) );
write(fd, &ch, Sz(WaveChunkHeader));
write(fd, &f , Sz(WaveFmtBody) );
write(fd, &wch, Sz(WaveChunkHeader));
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_sw_params_alloca(&swparams);
snd_pcm_hw_params_any(Handle,params);
snd_pcm_hw_params_set_access(Handle,params,SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(Handle,params,Hwparams.format);
snd_pcm_hw_params_set_channels(Handle,params,Hwparams.channels);
snd_pcm_hw_params_set_rate_near(Handle,params,&Hwparams.rate, 0);
snd_pcm_hw_params_set_period_time_near(Handle,params,(unsigned *)&period_time,0);
snd_pcm_hw_params_set_buffer_time_near(Handle,params,(unsigned *)&buffer_time,0);
snd_pcm_hw_params(Handle,params);
snd_pcm_hw_params_get_period_size(params,&Frames,0);
snd_pcm_hw_params_get_buffer_size(params,&buffer_size);
snd_pcm_sw_params_current(Handle,swparams);
snd_pcm_sw_params_get_xfer_align(swparams,&xfer_align);
snd_pcm_sw_params_set_sleep_min(Handle,swparams,0);
snd_pcm_sw_params_set_avail_min(Handle,swparams,Frames);
snd_pcm_sw_params_set_start_threshold(Handle,swparams,1);
snd_pcm_sw_params_set_stop_threshold(Handle,swparams,buffer_size);
snd_pcm_sw_params_set_xfer_align(Handle,swparams,xfer_align);
snd_pcm_sw_params(Handle,swparams);
}
void post_record(int fd, long bytes)
{
WaveChunkHeader cd = {WAV_DATA, bytes & 0x7fffffff};
off64_t seek = Sz(WaveHeader) + Sz(WaveChunkHeader) +
Sz(WaveFmtBody);
u_int wave_size = bytes + 2*Sz(WaveChunkHeader) +
Sz(WaveFmtBody) + 4;
lseek64(fd,4 ,SEEK_SET); write(fd, &wave_size, 4 );
lseek64(fd,seek,SEEK_SET); write(fd, &cd , Sz(WaveChunkHeader));
close(fd);
snd_pcm_close(Handle);
snd_config_update_free_global();
}
main(int argc, char *argv[])
{
char *audiobuf; long bytes, c, fd, time; sscanf(argv[2],"%d",&time);
fd = open64(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644);
bytes = time*snd_pcm_format_size(Hwparams.format,
Hwparams.rate*Hwparams.channels);
pre_record(fd,bytes); // side effect : sets Frames
Bytes_per_frame = Hwparams.channels*snd_pcm_format_physical_width(Hwparams.format)/8;
audiobuf = malloc(Frames*Bytes_per_frame);
c = bytes;
do
pcm_read_frames(audiobuf);
while (0 < (c -= write(fd,audiobuf,Frames*Bytes_per_frame)));
post_record(fd,bytes);
free(audiobuf);
return 0;
}
// gcc -gdwarf-2 -g3 -o m m.c -I/usr/local/include -lm -lasound