今天,看了下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; } |