Reputation: 630
I'm studying alsa programming on ubuntu.
I'm trying to output a sine wave to line-out of my laptop soundcard, and then redirecting to line-in (microphone) via an audio cable.
___LINE_IN(microphone)\
/ \
| \ _____________
| |soundcard-pc |
cable /
| /
\ ___LINE_OUT(speakers)/
I'm using this code
#include<stdio.h>
#include<stdlib.h>
#include<alsa/asoundlib.h>
#include<math.h>
#define SIZEBUF 2048
int main(void)
{
int i;
int err;
double x;
double cost;
double frequency=500;
unsigned int rate=44100;
short buf[SIZEBUF];
snd_pcm_t *phandle;
snd_pcm_hw_params_t *hw_params;
snd_pcm_open(&phandle, "default", SND_PCM_STREAM_PLAYBACK, 0);
snd_pcm_hw_params_malloc(&hw_params);
snd_pcm_hw_params_any(phandle, hw_params);
if ((err = snd_pcm_hw_params_set_access(phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
printf("Cannot set access type.\n");
exit(1);
}
snd_pcm_hw_params_set_format(phandle, hw_params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_rate_near(phandle, hw_params, &rate, 0);
snd_pcm_hw_params_set_channels(phandle, hw_params, 1);
snd_pcm_hw_params(phandle, hw_params);
snd_pcm_hw_params_free(hw_params);
snd_pcm_prepare(phandle);
cost = 2.0 * M_PI * frequency / (double)rate;
printf("cost=%f.\n", cost);
for (i = 1 ; i < SIZEBUF ; i++) {
x = sin(i * cost);
buf[i] = (short)(32767 * x + 32768);
}
for (i = 0 ; i < 50 ; i++) {
snd_pcm_writei(phandle, buf, SIZEBUF);
}
snd_pcm_close(phandle);
exit(0);
}
I'm using audacity to see the wave, but it appears strange, like in this image
It seems not to have the behaviour of a sine wave. Why?
Upvotes: 3
Views: 1999
Reputation:
To convert float samples to SND_PCM_FORMAT_S16_LE do:
#include <endian.h>
#include <math.h>
#include <stdint.h>
// assume -1.0 <= x <= 1.0
int16_t float_to_s16le (float x)
{
int16_t s16 = trunc (x * 32767); // rounds toward zero
return htole16 (s16);
}
Some remarks:
htole16
or an equivalent).Upvotes: 2
Reputation: 180172
You are using samples of type short
, and have correctly declared them as S16_LE
.
However, your code then computes the values as if they were unsigned:
buf[i] = (short)(32767 * x + 32768);
You do not need an offset; with signed samples, zero actually is zero. Use this:
buf[i] = (short)(32767 * x);
Upvotes: 3