|
今天,看了下wav文件格式,在Linux下尝试了读取wav文件数据写往声卡文件/dev/dsp,播放成功。
没想到Linux下声卡编程竟然如此简单,就是把音频数据写到/dev/dsp文件即可。
源代码如下
/* filename: wavplay.c */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <linux/soundcard.h>
#define BUFSIZE 512
struct RIFF_Header{
char RIFF_ID[4];
uint32_t RIFF_Size;
char RIFF_Format[4];
};
struct Chunk_Header{
char Chunk_ID[4];
uint32_t Chunk_Size;
};
struct Wave_Format{
uint16_t AudioFormat;
uint16_t NumChannels;
uint32_t SampleRate;
uint32_t AvgBytesPerSec;
uint16_t BlockAlign;
uint16_t BitsPerSample;
};
int main(int argc, char *argv[])
{
struct RIFF_Header riff_header;
struct Chunk_Header fmt_chunk, data_chunk;
struct Wave_Format wavfmt;
char buf[BUFSIZE];
FILE * fwave;
int sndfd;
int status;
int arg;
int readbytes;
int writebytes;
int writed;
if( argc < 2 ){
fprintf(stderr, "Usage: wavplay <filename>\n");
exit(-1);
}
fwave = fopen( argv[1], "r");
if( fwave == NULL ){
fprintf(stderr, "Can't open file %s\n", argv[1]);
exit(-1);
}
fread(&riff_header, 1, sizeof(struct RIFF_Header), fwave);
if( strncmp(riff_header.RIFF_ID, "RIFF", 4) || strncmp(riff_header.RIFF_Format, "WAVE",4)){
fprintf(stderr, "Unknown file format.\n");
exit(-1);
}
sndfd = open("/dev/dsp", O_RDWR);
if (sndfd < 0) {
perror("open of /dev/dsp failed");
exit(-1);
}
fread(&fmt_chunk, 1, sizeof(struct Chunk_Header), fwave);
if( !strncmp(fmt_chunk.Chunk_ID, "fmt ", 4) ){
/* this is a fmt chunk */
fread(&wavfmt, 1, sizeof(struct Wave_Format), fwave);
arg = wavfmt.BitsPerSample;
status = ioctl(sndfd, SOUND_PCM_WRITE_BITS, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_BITS ioctl failed");
if (arg != wavfmt.BitsPerSample)
perror("unable to set sample size");
arg = wavfmt.NumChannels;
status = ioctl(sndfd, SOUND_PCM_WRITE_CHANNELS, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
if (arg != wavfmt.NumChannels)
perror("unable to set number of channels");
arg = wavfmt.SampleRate;
status = ioctl(sndfd, SOUND_PCM_WRITE_RATE, &arg);
if (status == -1)
perror("SOUND_PCM_WRITE_WRITE ioctl failed");
/* skip extra bytes */
fseek(fwave, fmt_chunk.Chunk_Size - 16 + fmt_chunk.Chunk_Size%2, SEEK_CUR);
}else{
fprintf(stderr, "Can't find fmt chunk.\n");
exit(-1);
}
while( fread(&data_chunk, 1, sizeof(struct Chunk_Header), fwave) != 0 )
if( !strncmp(data_chunk.Chunk_ID, "data", 4) ){
printf("Begin Play\n");
/* this is a data chunk */
writed = 0;
while(writed < data_chunk.Chunk_Size){
readbytes = fread(buf, 1, BUFSIZE, fwave);
writebytes = write(sndfd, buf, readbytes);
if( writebytes != readbytes )
perror("wrote wrong number of bytes");
writed += readbytes;
}
}else{
/* skip unknown chunks */
fseek(fwave, data_chunk.Chunk_Size + fmt_chunk.Chunk_Size%2, SEEK_CUR);
}
fclose(fwave);
close(sndfd);
return 0;
}
哈哈,DIY wav播放器的路又向前进了一步。 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
|