How to set the period size in ALSA, revisited - alsa

This appears to answer my problem: How to set periods and buffer size in ALSA? but I have an example which doesn't work.
frames = 1024;
int dir;
snd_pcm_hw_params_set_period_size_near(pcm_handle, params, &frames, &dir);
snd_pcm_hw_params(pcm_handle, params);
snd_pcm_hw_params_get_period_size(params, &frames, 0);
printf("Frames: %zd\n", frames);
Regardless of frames being a high or a low number, when I fetch what it actually was set to with snd_pcm_hw_params_get_period_size(), it always shows me 512 frames.
I understand that the exact number I'm trying to set might not be available. However, shouldn't it set it to the nearest value of what I'm requesting?
I'm expecting to see it at least get increased when I request a higher number, or get lowered when I request a lower number, not remain exactly the same.
hw_params.c output for the "hw" device:
Device: hw (type: HW)
Access types: MMAP_INTERLEAVED RW_INTERLEAVED
Formats: S16_LE S32_LE
Channels: 2 4 6 8
Sample rates: 44100 48000 96000 192000
Interrupt interval: 20-5944309 us
Buffer size: 41-11888617 us
hw_params.c output for the "default" device:
Device: default (type: IOPLUG)
Access types: RW_INTERLEAVED
Formats: U8 S16_LE S16_BE S24_LE S24_BE S32_LE S32_BE FLOAT_LE FLOAT_BE MU_LAW A_LAW S24_3LE S24_3BE
Channels: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Sample rates: 1-192000
Interrupt interval: 5-4294967295 us
Buffer size: 15-4294967295 us
Minimal reproducible example where I attempt to set both the period of the buffer size:
/**
* Attempting to set some parameters.
*
* Using the template from: http://equalarea.com/paul/alsa-audio.html
*
**/
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#define PCM_DEVICE "default"
int main(int argc, char **argv)
{
unsigned int pcm;
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
/* Open the PCM device in playback mode */
if(pcm = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
printf("ERROR: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(pcm));
return 1;
}
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm_handle, params);
/* Set parameters */
if(pcm = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
printf("ERROR: Can't set interleaved mode. %s\n", snd_strerror(pcm));
return 1;
}
if(pcm = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_FLOAT) < 0) {
printf("ERROR: Can't set format. %s\n", snd_strerror(pcm));
return 1;
}
int channels = 2;
if(pcm = snd_pcm_hw_params_set_channels(pcm_handle, params, channels) < 0) {
printf("ERROR: Can't set channels number. %s\n", snd_strerror(pcm));
return 1;
}
int rate = 44100;
if(pcm = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0) < 0) {
printf("ERROR: Can't set rate. %s\n", snd_strerror(pcm));
return 1;
}
/* Write parameters */
if(pcm = snd_pcm_hw_params(pcm_handle, params) < 0) {
printf("ERROR: Can't set harware parameters. %s\n", snd_strerror(pcm));
return 1;
}
printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
int ch;
snd_pcm_hw_params_get_channels(params, &ch);
if(ch > 1) {
printf("Channels: %i, stereo\n", ch);
}
else if(ch == 1) {
printf("Channels: %i, mono\n", ch);
}
snd_pcm_hw_params_get_rate(params, &ch, 0);
printf("Rate: %d bps\n", ch);
int dir;
snd_pcm_uframes_t frames = 1024;
printf("Attempting to set frames to %d\n", frames);
snd_pcm_hw_params_set_period_size_near(pcm_handle, params, &frames, &dir);
snd_pcm_hw_params(pcm_handle, params);
snd_pcm_hw_params_get_period_size(params, &frames, 0);
printf("Frames is now: %zd\n", frames);
snd_pcm_hw_params_get_period_time(params, &ch, NULL);
int buffer_size = 52430;
printf("Attempting to set the buffer size to: %d\n", buffer_size);
snd_pcm_hw_params_set_buffer_size(pcm_handle, params, buffer_size);
snd_pcm_hw_params(pcm_handle, params);
snd_pcm_uframes_t temp;
snd_pcm_hw_params_get_buffer_size(params, &temp);
printf("Buffer size is now: %d\n", temp);
return 0;
}
Compile with: gcc set_params_fail.c -lasound
Output:
PCM name: 'default'
PCM state: PREPARED
Channels: 2, stereo
Rate: 44100 bps
Attempting to set frames to 1024
Frames is now: 512
Attempting to set the buffer size to: 52430
Buffer size is now: 524288

After calling snd_pcm_hw_params(), all parameters are fixed. You have to call snd_pcm_hw_params_set_period_size_near() before the first (and only) call to snd_pcm_hw_params().

Related

Why does ALSA snd_pcm_hw_params_get_buffer_size react to the size of local stack frame allocations?

Distro: Debian 9.11
Compiler: gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
ALSA version: Advanced Linux Sound Architecture Driver Version k4.9.0-11-amd64.
Please consider the following minimal reproducible example (now updated, with more error handling):
/**
* Trying to set some parameters for ALSA.
*
* Code from: http://equalarea.com/paul/alsa-audio.html
*
*/
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#define PCM_DEVICE "default"
int main(int argc, char **argv)
{
unsigned int err;
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
if((err = snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Error: Can't open \"%s\" PCM device. %s\n", PCM_DEVICE, snd_strerror(err));
return 1;
}
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(pcm_handle, params);
if((err = snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
printf("Error: Can't set interleaved mode. %s\n", snd_strerror(err));
return 1;
}
if((err = snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_FLOAT)) < 0) {
printf("Error: Can't set format. %s\n", snd_strerror(err));
return 1;
}
int channels = 2;
if((err = snd_pcm_hw_params_set_channels(pcm_handle, params, channels)) < 0) {
printf("Error: Can't set channels number. %s\n", snd_strerror(err));
return 1;
}
int rate = 44100;
if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, params, &rate, 0)) < 0) {
printf("Error: Can't set rate. %s\n", snd_strerror(err));
return 1;
}
printf("PCM name: '%s'\n", snd_pcm_name(pcm_handle));
printf("PCM state: %s\n", snd_pcm_state_name(snd_pcm_state(pcm_handle)));
int ch;
if((err = snd_pcm_hw_params_get_channels(params, &ch)) < 0) {
printf("Error: Unable to get the number of channels: %s\n", snd_strerror(err));
return 1;
}
if(ch > 1) {
printf("Channels: %i, stereo\n", ch);
}
else if(ch == 1) {
printf("Channels: %i, mono\n", ch);
}
else {
printf("Error: Unknown number of channels (%d).\n", ch);
return 1;
}
if((err = snd_pcm_hw_params_get_rate(params, &ch, 0)) < 0) {
printf("Error: Unable to get the rate: %s\n", snd_strerror(err));
return 1;
}
printf("Rate: %d bps\n", ch);
int dir;
snd_pcm_uframes_t period_size = 1024;
printf("Attempting to set the period size to %d\n", period_size);
if((err = snd_pcm_hw_params_set_period_size_near(pcm_handle, params, &period_size, &dir)) < 0) {
printf("Error: Unable to set the period size: %s\n", snd_strerror(err));
return 1;
}
printf("Attempting to get the period size.\n");
if((err = snd_pcm_hw_params_get_period_size(params, &period_size, 0)) < 0) {
printf("Error: Unable to get the period size: %s\n", snd_strerror(err));
return 1;
}
printf("Period size is now: %zd\n", period_size);
int period_time = -1;
printf("Attempting to get the period time.\n");
if((err = snd_pcm_hw_params_get_period_time(params, &period_time, NULL)) < 0) {
printf("Error: Unable to get the period time: %s\n", snd_strerror(err));
return 1;
}
printf("Period time: %d\n", period_time);
int buffer_size = 4096;
printf("Attempting to set the buffer size to: %d\n", buffer_size);
if((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, params, buffer_size)) < 0) {
printf("Error: Unable to set the buffer size: %s\n", snd_strerror(err));
return 1;
}
printf("Finalizing hw params.\n");
if((err = snd_pcm_hw_params(pcm_handle, params)) < 0) {
printf("Error: Can't set harware parameters. %s\n", snd_strerror(err));
return 1;
}
snd_pcm_uframes_t temp;
printf("Attempting to get the buffer size.\n");
if((err = snd_pcm_hw_params_get_buffer_size(params, &temp)) < 0) {
printf("Error: Unable to get the buffer size: %s\n", snd_strerror(err));
return 1;
}
printf("Buffer size is now: %d\n", temp);
if((err = snd_pcm_drain(pcm_handle)) < 0) {
printf("Error: Unable to drain the pcm handle: %s\n", snd_strerror(err));
return 1;
}
if((err = snd_pcm_close(pcm_handle)) < 0) {
printf("Error: Unable to close the pcm handle: %s\n", snd_strerror(err));
return 1;
}
return 0;
}
When char test[5] exists, I get this output:
PCM name: 'default'
PCM state: OPEN
Channels: 2, stereo
Rate: 44100 bps
Attempting to set the period size to 1024
Attempting to get the period size.
Period size is now: 1024
Attempting to get the period time.
Period time: -1
Attempting to set the buffer size to: 4096
Finalizing hw params.
Attempting to get the buffer size.
Buffer size is now: 523774
Note the "Buffer size is now: 523774". The expected output is given below:
However, if I change test[5] to test[4] or less (or remove the statement altogether), recompile, and run, I get:
PCM name: 'default'
PCM state: OPEN
Channels: 2, stereo
Rate: 44100 bps
Attempting to set frames to 1024
Frames is now: 1024
Attempting to set the buffer size to: 4096
Buffer size is now: 4096
I must be abusing the ALSA API, be doing something else weird I don't realize, or the ALSA API is broken.
Why does it react to this trivial stack allocation of 5 bytes?
Note that a higher value than 5 also produces this problem, such as a word aligned number of 32. I don't think has to do with stack alignment or something of that sort.
Compiler notes, how to reproduce:
Copy/paste the minimal example into broken_alsa.c
Then issue:
$ gcc broken_alsa.c -lasound
$ ./a.out
Remove the char temp[5] (or set it to 4), and it should work.
When calling snd_pcm_hw_params_set_period_size_near(), initialize dir to zero.

fail init ALSA for 24bit file with SND_PCM_FORMAT_S24_3LE format

I am trying to playback 24bit wav file with 3-bytes sample allignment using ALSA (libasound.so.2). And ALSA fails on setting buffer size with Invalid argument error (and ALSA do not pass anything to drivers)
Here is wav file header content:
chunkId: 46464952
chunkSize: 221417340
format: "WAVE"
subchunk1Id: "fmt "
subchunk1Size: 40
audioFormat: fffe
numChannels: 2
sampleRate: 88200
byteRate: 529200
blockAlign: 6
bitsPerSample: 24
cbSize 16
wValidBitsPerSample 18
dwChannelMask 0
SubFormat
subchunk2Id: "data"
subchunk2Size: 221417280
Unfortunately cannot provide proper test program source as it is part of cross-platform program and wount build separately. The shorten example might looks like
#include <stdio.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <semaphore.h>
#include "asoundlib.h"
int main(int argc, char *argv[])
{
int err = -1; /**< ALSA & clib function return code */
snd_pcm_t *p_handle = NULL; /**< pointer to active pcm object */
static const char *const p_device = "default"; /**< const pointer to const device id string */
unsigned int sampleRate = 0;
unsigned int rbuffertime = 0; /**< real buffer time as granted by ALSA */
err = snd_pcm_open(&p_handle, p_device, SND_PCM_STREAM_PLAYBACK, 0);
if (0 > err)
{
printf("Playback open error: %s\n", snd_strerror(err));
return err;
}
/* Get full range of possible hw params */
err = snd_pcm_hw_params_any(p_handle, p_hwparams);
if (0 > err)
{
printf("Error fetching hw param ranges: %s\n", snd_strerror(err));
return err;
}
// Specify a specific config out of configuration space and set it
err = snd_pcm_hw_params_set_rate_resample(p_handle, p_hwparams, 1);
if (0 > err)
{
printf("Unable to snd_pcm_hw_params_set_rate_resample for playback: %s\n", snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_set_access(p_handle, p_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
if (0 > err)
{
printf("Unable to snd_pcm_hw_params_set_access for playback: %s\n", snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_set_format(p_handle, p_hwparams, SND_PCM_FORMAT_S24_3LE);
if (0 > err)
{
printf("Unable to snd_pcm_hw_params_set_format for playback: %s\n", snd_strerror(err));
return err;
}
err = snd_pcm_hw_params_set_channels(p_handle, p_hwparams, 2);
if (0 > err)
{
printf("Unable to snd_pcm_hw_params_set_channels for playback: %s\n", snd_strerror(err));
return err;
}
sampleRate = 88200;
err = snd_pcm_hw_params_set_rate_near(p_handle, p_hwparams, &sampleRate, 0);
if (0 > err)
{
printf("Unable to snd_pcm_hw_params_set_rate for playback: %s\n", snd_strerror(err));
return err;
}
rbuffertime = 500000;
err = snd_pcm_hw_params_set_buffer_time_near(p_handle, p_hwparams, &rbuffertime, 0);
if (0 > err)
{
printf("Unable to snd_pcm_hw_params_set_buffer_time_near for playback: %s\n", snd_strerror(err));
}
return err;
}
ALSA fails on snd_pcm_hw_params_set_buffer_time_near() call with error
ALSA ERROR hw_params: set_near (BUFFER_TIME)
value = 500000 : Invalid argument
ACCESS: RW_INTERLEAVED
FORMAT: S24_3LE
SUBFORMAT: STD
SAMPLE_BITS: 24
FRAME_BITS: 48
CHANNELS: 2
RATE: 88200
PERIOD_TIME: (476 247688)
PERIOD_SIZE: (42 21846)
PERIOD_BYTES: [256 131072]
PERIODS: [2 1024]
BUFFER_TIME: (495351 495352)
BUFFER_SIZE: 43690
BUFFER_BYTES: [262144 262140]
TICK_TIME: ALL
(ALSA even not attempts to pass any data to drivers, just fails on set buffer)
That program works well for 16 bit audio.
I have tried different values of buffer (0.001 .. 1 second) however none of them works. Suppose I have missed any part of ALSA config required for 24 bit with 3LE, of maybe some check of previous init steps results?
Unfortunately I cannot find any example of ALSA usage for 24 bits, I would appreciate if You advice any link to example/recommendation/documentation.
EDITED
The result of aplay for this file is:
aplay -v /export/target/24bit_88.2kHz.wav
Playing WAVE '/export/target/24bit_88.2kHz.wav' : Signed 24 bit Little Endian in 3bytes, Rate 88200 Hz, Stereo
aplay: set_params:979: Sample format non available

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.

Sample frequency in ALSA in C

I have a program that records 5sec of the audio values using the ALSA lib , here is the code :
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#include <stdio.h>
int main() {
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int val;
int dir,z=0;
snd_pcm_uframes_t frames;
signed short *buffer;
FILE* inp = NULL;
FILE* inp2 =NULL;
inp = fopen("values","wb+");
inp2 = fopen("Values2","w+");
int fd = open("v",O_WRONLY);
/* 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,1);
/* Sample frequency */
val = 96000;
//val2 = val;
snd_pcm_hw_params_set_rate(handle, params,
val, &dir);
printf(" %d \n", val);
/* 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 * 1; /* 2 bytes/sample, 1 channels */
buffer = (signed short*) 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);
fwrite(buffer,sizeof(signed short),size,inp);
for(z =0; z<size;z++)
fprintf(inp2,"%lf\n",buffer[z]/1.0);
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
printf(" buffer");
free(buffer);
fclose(inp);
fclose(inp2);
close(fd);
return 0;
}
I'm using the function snd_pcm_hw_params_set_rate to set an exact value for fs but I get this warning :
warning: passing argument 4 of ‘snd_pcm_hw_params_set_rate’ makes integer from pointer without a cast [enabled by default]
val, &dir);
^
In file included from /usr/include/alsa/asoundlib.h:54:0,
from capture.c:4:
/usr/include/alsa/pcm.h:743:5: note: expected ‘int’ but argument is of type ‘int *’
int snd_pcm_hw_params_set_rate(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int val, int dir);
I've check the documentation the parameter type should be correct, but more interesting is that after the running the program, I get another warring or error :
*** Error in `./out': malloc(): memory corruption (fast): 0x0000000002462d90 ***
Aborted (core dumped)
this don't show up when I use :
size = frames * 1; to
size = frames * 2;
an the result is just wrong, I tried to use a lower sample frequency but it didn't help.
when use : snd_pcm_hw_params_set_rate_near the sample freuqency changes to 192000 and the result is than correct, I would really use the first function so I get to know what sample freuqcy I'm using.
any idea how I can do it, or why do I get those warrings ?
Regarding the warning, compiler is right, you're passing the address of dir which is of type int *.

How to improve cmuSphinx's accuracy?

I want to use pocketShpinx to do some speech-to-text word. I have install sphinxbase and pocketSphinx. And download the acoustic model/langauge model/dictionary. Then I test the example code just like follows:
#include <pocketsphinx/pocketsphinx.h>
#include <stdio.h>
#include <stdlib.h>
#include "debug.h"
int main(int argc, char *argv[])
{
ps_decoder_t *ps;
cmd_ln_t *config;
FILE *fh;
int rv;
char const *hyp, *uttid;
int32 score;
config = cmd_ln_init(NULL, ps_args(), TRUE,
"-hmm", "/home/madper/speech/hub4opensrc.cd_continuous_8gau",
"-lm", "/home/madper/speech/language_model.arpaformat.DMP",
"-dict", "/home/madper/speech/cmudict/cmudict/sphinxdict/cmudict_SPHINX_40",
NULL);
if (config == NULL)
{
DBG (("cmd_ln_init() failed.\n"));
exit(1);
}
if ((ps = ps_init (config)) == NULL) /* init decoder */
{
DBG (("ps_init() failed.\n"));
exit(1 );
}
if ((fh = fopen("test.raw", "rb")) == NULL) /* open raw file */
{
DBG (("fopen() failed.\n"));
exit (1);
}
if ((rv = ps_decode_raw (ps, fh, "test", -1)) < 0 )
{
DBG (("ps_decode_raw() error!\n"));
exit (1);
}
if ((hyp = ps_get_hyp(ps, &score, &uttid)) == NULL)
{
DBG (("ps_get_hyp() failed!\n"));
exit (1);
}
printf ("Recognized: %s\n", hyp); /* this is what you say */
fclose(fh);
ps_free(ps);
return 0;
}
DBG is just a macro to print error message if defined DEBUG.
Then I write some code to record from mic use alsa. Like follows:
#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, 1);
/* 44100 bits/second sampling rate (CD quality) */
val = 16000;
snd_pcm_hw_params_set_rate_near(handle, params,
&val, &dir);
/* Set period size to 32 frames. */
frames = 16;
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, 2 channels */
buffer = (char *) malloc(size);
/* We want to loop for 5 seconds */
snd_pcm_hw_params_get_period_time(params,
&val, &dir);
loops = 2000000 / 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;
}
So, I record a raw file. Then do speech-to-test on that file. But the accuracy is very vert poor. Just like hello or go home will give me hotel or MHM MHM and so on. So what's wrong with these code?
I have read the faqs, should I use acoustic model adaptation to improve accuracy?
PS. I change stereo to mono. And the sound is strange. I can't understand what I said. So, what's wrong with it? This is that raw file test.raw
If you look at the first Q and A in http://cmusphinx.sourceforge.net/wiki/faq you will notice that the library assumes mono data.
You record in stereo.

Resources