First of all, I’m totally green to audio programming, so I’d be thankful for any advice and learning resources. I used (Linux Journal – Introduction to Sound Programming with ALSA) and googling as reference points.
What I need is to play all samples from previously read .wav
file.
What I currently do is to open connection to default audio playback device, set parameters according to format of audio file, set period to contain all of samples at once and then call snd_pcm_writei
once, to play them. After that, I call snd_pcm_drain
and snd_pcm_close
to exit.
This currently works, but I don’t know if you are supposed to do that. I tried to make period smaller, and play samples consecutively in a loop, but the output was not synchronized, was deformed, or produced loud noise after playing correctly for some time.
This is how I currently handle this problem:
int audio_play(unsigned int frequency, int bits_per_sample, int channels_count, char *samples, long samples_count) {
snd_pcm_t *handle;
snd_pcm_uframes_t frames;
int dir;
int write_result;
snd_pcm_hw_params_t *params;
if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {printf("naudio_play failed: snd_pcm_open failed.n"); return 2;}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (bits_per_sample == 8)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
else if (bits_per_sample == 16)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16);
else if (bits_per_sample == 24)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24);
else if (bits_per_sample == 32)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S32);
if (channels_count == 1)
snd_pcm_hw_params_set_channels(handle, params, 1);
else if (channels_count == 2)
snd_pcm_hw_params_set_channels(handle, params, 2);
snd_pcm_hw_params_set_rate(handle, params, frequency, 0);
frames = samples_count;
snd_pcm_hw_params_set_period_size(handle, params, frames, 0);
if (snd_pcm_hw_params(handle, params) < 0) {printf("naudio_play: snd_pcm_hw_params_failed.n"); return 1;}
snd_pcm_writei(handle, samples, frames);
snd_pcm_drain(handle);
snd_pcm_close(handle);
return 0;
}
And this is how I tried to do it, but result was horrible:
int audio_play(unsigned int frequency, int bits_per_sample, int channels_count, char *samples, long samples_count) {
snd_pcm_t *handle;
snd_pcm_uframes_t frames;
int dir;
int write_result;
snd_pcm_hw_params_t *params;
if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) {printf("naudio_play failed: snd_pcm_open failed.n"); return 2;}
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
if (bits_per_sample == 8)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
else if (bits_per_sample == 16)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16);
else if (bits_per_sample == 24)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24);
else if (bits_per_sample == 32)
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S32);
if (channels_count == 1)
snd_pcm_hw_params_set_channels(handle, params, 1);
else if (channels_count == 2)
snd_pcm_hw_params_set_channels(handle, params, 2);
snd_pcm_hw_params_set_rate(handle, params, frequency, 0);
frames = samples_count / (bits_per_sample / 8 * channels_count);
snd_pcm_hw_params_set_period_size(handle, params, frames, 0);
if (snd_pcm_hw_params(handle, params) < 0) {printf("naudio_play: snd_pcm_hw_params_failed.n"); return 1;}
while (samples_count > 0) {
snd_pcm_writei(handle, samples, frames);
samples_count -= frames;
samples += frames;
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
return 0;
}
Code was tested using audio files with these parameters:
file type: RIFF
file format: WAVE
block format: fmt
data block id: data
channels count: 2
frequency: 44100
bytes per sec: 176400
bytes per block: 4
bits per sample: 16
samples count: 262094
and
file type: RIFF
file format: WAVE
block format: fmt
data block id: data
channels count: 1
frequency: 22257
bytes per sec: 22257
bytes per block: 1
bits per sample: 8
samples count: 91240
What I want to know is if there is any problem with making period size huge, and if so, to get any tips or examples how to make it sound correctly.
Dominik is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
2