Пытаюсь написать программку, генерирующую синусоиду (а вообще - еще и другие сигналы). На OSS все работало, но не факт, что oss будет поддерживаться в дальнейшем, поэтому пытаюсь сделать аналог на ALSA. Компилирую, запускаю - раздаются какие-то щелчки и гул. Подскажите, пожалуйста, кто программировал на ALSA, как сгенерировать нормальную синусоиду? Может быть, здесь:
s1 = c1+A1*cos((time+((double)i)*rate)*_2pi*freq1);
Сама программка:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include <alsa/asoundlib.h>
#include <sys/time.h>
#include <math.h>
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
#define METHOD SND_PCM_ACCESS_RW_INTERLEAVED
static unsigned int rate = 44100; /* stream rate */
static unsigned int channels = 2; /* count of channels */
static unsigned int period_time; /* period time in us */
double freq1 = 440; /* sinusoidal wave frequency in Hz */
double freq2 = 440; /* sinusoidal wave frequency in Hz */
short c1 = 0, c2 = 0, A1 = 32700, A2 = 32700;
int size;
static int verbose = 0; /* verbose flag */
static snd_output_t *output = NULL;
double dtime(){
struct timeval ct;
struct timezone tz;
gettimeofday(&ct, &tz);
return (ct.tv_sec + ct.tv_usec/1e6);
}
static int xrun_recovery(snd_pcm_t *handle, int err){
if (err == -EPIPE) { /* under-run */
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
return 0;
} else if (err == -ESTRPIPE) {
while ((err = snd_pcm_resume(handle)) == -EAGAIN)
usleep(1); /* wait until the suspend flag is released */
if (err < 0) {
err = snd_pcm_prepare(handle);
if (err < 0)
printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
}
return 0;
}
return err;
}
static int write_loop(snd_pcm_t *handle_o){
double time0, time, _2pi = 2.*M_PI;
unsigned char tmp;
int i, s1, s2, _ss;
snd_pcm_sframes_t err;
double rnd1, rnd2, rate;
time0 = dtime();
char *rdata = (char *) malloc(size);
_ss = size / 4;
rate = period_time / _ss;
short *data = (short*) rdata;
snd_pcm_nonblock(handle_o, 1);
while(1){
time = dtime() - time0;
for(i = 0; i < _ss; i+=2){
s1 = c1+A1*cos((time+((double)i)*rate)*_2pi*freq1);
s2 = c2+A2*cos((time+((double)i)*rate)*_2pi*freq2);
if(s1 < -32700) data[i] = -32700;
else if(s1 > 32700) data[i] = 32700;
else data[i] = s1;
if(s2 < -32700) data[i+1] = -32700;
else if(s2 > 32700) data[i+1] = 32700;
else data[i+1] = s2;
}
err = snd_pcm_writei(handle_o, rdata, size);
if (err < 0)
err = snd_pcm_recover(handle_o, err, 0);
if (err < 0){
printf("snd_pcm_writei failed\n");
break;
}
}
}
int main(int argc, char *argv[]){
snd_pcm_t *handle_o;
int err, morehelp;
snd_pcm_hw_params_t *hwparams_o;
snd_pcm_sw_params_t *swparams_o;
snd_pcm_uframes_t frames;
unsigned int chn, val;
if(argc==2) freq1 = freq2 = atof(argv[1]);
else if(argc == 3){
freq1 = atof(argv[1]);
freq2 = atof(argv[2]);
}
printf("Playback device is %s\n", device);
printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
printf("Sine wave rate is (%.4f/%.4f)Hz\n", freq1, freq2);
if ((err = snd_pcm_open(&handle_o, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
printf("Playback open error: %s\n", snd_strerror(err));
return 0;
}
snd_pcm_hw_params_alloca(&hwparams_o);
snd_pcm_hw_params_any(handle_o, hwparams_o);
snd_pcm_hw_params_set_access(handle_o, hwparams_o, METHOD);
snd_pcm_hw_params_set_format(handle_o, hwparams_o, format);
snd_pcm_hw_params_set_channels(handle_o, hwparams_o, 2);
val = 44100;
snd_pcm_hw_params_set_rate_near(handle_o, hwparams_o, &val, &err);
frames = 128;
snd_pcm_hw_params_set_period_size_near(handle_o, hwparams_o, &frames, &err);
printf("set period size = %d: %s\n", frames, snd_strerror(err));
err = snd_pcm_hw_params(handle_o, hwparams_o);
if (err < 0) {
printf("unable to set hw parameters: %s\n", snd_strerror(err));
exit(1);
}
snd_pcm_hw_params_get_period_size(hwparams_o, &frames, &err);
size = frames * 4;
snd_pcm_hw_params_get_period_time(hwparams_o, &period_time, &err);
printf("Period size: %dx4, period time: %d\n", frames, period_time);
if (verbose > 0){
snd_pcm_dump(handle_o, output);
}
snd_pcm_prepare(handle_o);
err = write_loop(handle_o);
if (err < 0)
printf("Transfer failed: %s\n", snd_strerror(err));
snd_pcm_close(handle_o);
return 0;
}