用于在 Raspberry Pi 上读取和播放 WAV 文件的 ALSA 应用程序
ALSA application to read and play a WAV file on Raspberry Pi
尝试学习 ALSA 音频层以最终为 Raspberry Pi 平台编写 ALSA 设备驱动程序。从简单开始,我将来自 ALSA 项目站点和其他在线资源的各种示例粘合在一起来做最简单的事情:读取 WAV 文件并在默认声音设备上播放它。我无法让这个简单的 C 示例工作。
我正在使用 libsndfile 进行所有 WAV 文件 reading/header 解码。我验证了我读入缓冲区的样本是正确的(验证了程序读取的前 400K 个样本针对将样本值转储到文本文件的 sndfile-to-text 应用程序)。所以我知道我的缓冲区包含正确的数据,问题一定出在我将它传递给 ALSA APIs.
的方式上
运行时它只在右声道发出声音,distorted/muddy - 几乎无法辨认。顺便说一句,"aplay" 应用程序完美地播放相同的 WAV 文件并报告该文件是 16 位符号 LE、44100Hz、立体声,这也与我的应用程序报告的内容相匹配。在 Raspberry Pi.
上运行
我在这里将 C 程序剥离到最少以节省空间,但我验证了所有 API 调用的正确 return 代码。为什么这个简单的 ALSA 应用程序不能产生正确的声音?
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <sndfile.h>
#define PCM_DEVICE "default"
int main(int argc, char **argv) {
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
snd_pcm_uframes_t frames;
int dir, pcmrc;
char *infilename = "/home/pi/shortsample.wav";
int* buf = NULL;
int readcount;
SF_INFO sfinfo;
SNDFILE *infile = NULL;
infile = sf_open(infilename, SFM_READ, &sfinfo);
fprintf(stderr,"Channels: %d\n", sfinfo.channels);
fprintf(stderr,"Sample rate: %d\n", sfinfo.samplerate);
fprintf(stderr,"Sections: %d\n", sfinfo.sections);
fprintf(stderr,"Format: %d\n", sfinfo.format);
/* Open the PCM device in playback mode */
snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0);
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(pcm_handle, params);
/* Set parameters */
snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(pcm_handle, params, sfinfo.channels);
snd_pcm_hw_params_set_rate(pcm_handle, params, sfinfo.samplerate, 0);
/* Write parameters */
snd_pcm_hw_params(pcm_handle, params);
/* Allocate buffer to hold single period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
fprintf(stderr,"# frames in a period: %d\n", frames);
fprintf(stderr,"Starting read/write loop\n");
buf = malloc(frames * sfinfo.channels * sizeof(int));
while ((readcount = sf_readf_int(infile, buf, frames))>0) {
pcmrc = snd_pcm_writei(pcm_handle, buf, readcount);
if (pcmrc == -EPIPE) {
fprintf(stderr, "Underrun!\n");
snd_pcm_prepare(pcm_handle);
}
else if (pcmrc < 0) {
fprintf(stderr, "Error writing to PCM device: %s\n", snd_strerror(pcmrc));
}
else if (pcmrc != readcount) {
fprintf(stderr,"PCM write difffers from PCM read.\n");
}
}
fprintf(stderr,"End read/write loop\n");
snd_pcm_drain(pcm_handle);
snd_pcm_close(pcm_handle);
free(buf);
return 0;
}
您必须检查所有可能失败的snd_
函数的return值。
S16_LE
格式每个样本有两个字节,但 int
有四个。
使用 short
和 sf_readf_short
.
尝试学习 ALSA 音频层以最终为 Raspberry Pi 平台编写 ALSA 设备驱动程序。从简单开始,我将来自 ALSA 项目站点和其他在线资源的各种示例粘合在一起来做最简单的事情:读取 WAV 文件并在默认声音设备上播放它。我无法让这个简单的 C 示例工作。
我正在使用 libsndfile 进行所有 WAV 文件 reading/header 解码。我验证了我读入缓冲区的样本是正确的(验证了程序读取的前 400K 个样本针对将样本值转储到文本文件的 sndfile-to-text 应用程序)。所以我知道我的缓冲区包含正确的数据,问题一定出在我将它传递给 ALSA APIs.
的方式上运行时它只在右声道发出声音,distorted/muddy - 几乎无法辨认。顺便说一句,"aplay" 应用程序完美地播放相同的 WAV 文件并报告该文件是 16 位符号 LE、44100Hz、立体声,这也与我的应用程序报告的内容相匹配。在 Raspberry Pi.
上运行我在这里将 C 程序剥离到最少以节省空间,但我验证了所有 API 调用的正确 return 代码。为什么这个简单的 ALSA 应用程序不能产生正确的声音?
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <sndfile.h>
#define PCM_DEVICE "default"
int main(int argc, char **argv) {
snd_pcm_t *pcm_handle;
snd_pcm_hw_params_t *params;
snd_pcm_uframes_t frames;
int dir, pcmrc;
char *infilename = "/home/pi/shortsample.wav";
int* buf = NULL;
int readcount;
SF_INFO sfinfo;
SNDFILE *infile = NULL;
infile = sf_open(infilename, SFM_READ, &sfinfo);
fprintf(stderr,"Channels: %d\n", sfinfo.channels);
fprintf(stderr,"Sample rate: %d\n", sfinfo.samplerate);
fprintf(stderr,"Sections: %d\n", sfinfo.sections);
fprintf(stderr,"Format: %d\n", sfinfo.format);
/* Open the PCM device in playback mode */
snd_pcm_open(&pcm_handle, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0);
/* Allocate parameters object and fill it with default values*/
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(pcm_handle, params);
/* Set parameters */
snd_pcm_hw_params_set_access(pcm_handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(pcm_handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(pcm_handle, params, sfinfo.channels);
snd_pcm_hw_params_set_rate(pcm_handle, params, sfinfo.samplerate, 0);
/* Write parameters */
snd_pcm_hw_params(pcm_handle, params);
/* Allocate buffer to hold single period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
fprintf(stderr,"# frames in a period: %d\n", frames);
fprintf(stderr,"Starting read/write loop\n");
buf = malloc(frames * sfinfo.channels * sizeof(int));
while ((readcount = sf_readf_int(infile, buf, frames))>0) {
pcmrc = snd_pcm_writei(pcm_handle, buf, readcount);
if (pcmrc == -EPIPE) {
fprintf(stderr, "Underrun!\n");
snd_pcm_prepare(pcm_handle);
}
else if (pcmrc < 0) {
fprintf(stderr, "Error writing to PCM device: %s\n", snd_strerror(pcmrc));
}
else if (pcmrc != readcount) {
fprintf(stderr,"PCM write difffers from PCM read.\n");
}
}
fprintf(stderr,"End read/write loop\n");
snd_pcm_drain(pcm_handle);
snd_pcm_close(pcm_handle);
free(buf);
return 0;
}
您必须检查所有可能失败的snd_
函数的return值。
S16_LE
格式每个样本有两个字节,但 int
有四个。
使用 short
和 sf_readf_short
.