#include #include #include #include #include #include #include #include #include #define RIFF 0x46464952 #define WAVE 0x45564157 #define FMT 0x20746D66 #define DATA 0x61746164 #define PCM_CODE 1 #define WAVE_MONO 1 #define WAVE_STEREO 2 typedef struct { int riff_tag; int riff_length; int wave_tag; int fmt_tag; int fmt_length; unsigned short format; unsigned short channels; int samp_rate; int avg_samp_rate; unsigned short align; unsigned short bits_per_sample; int data_tag; int data_length; } WAVHDR; #ifdef BIGENDIAN /* convert the bytes of a 16-bit integer to little endian */ #define BSWAP16(c) (((c & 0xff) << 8) | ((c >> 8) & 0xff)) /* convert the bytes of a 32-bit integer to little endian */ #define BSWAP32(c) ((c>>24)&0xff)|((c>>8)&0xff00)|((c<<8)&0xff0000)|(c<<24) #else #define BSWAP16(c) c #define BSWAP32(c) c #endif WAVHDR* read_wavhdr(int fd) { static WAVHDR *wavhdr = NULL; if (! wavhdr) wavhdr = (WAVHDR*)malloc(sizeof(WAVHDR)); if (read(fd, wavhdr, sizeof(WAVHDR)) == -1) return NULL; wavhdr->riff_tag = BSWAP32(wavhdr->riff_tag); wavhdr->riff_length = BSWAP32(wavhdr->riff_length); wavhdr->wave_tag = BSWAP32(wavhdr->wave_tag); wavhdr->fmt_tag = BSWAP32(wavhdr->fmt_tag); wavhdr->fmt_length = BSWAP32(wavhdr->fmt_length); wavhdr->format = BSWAP16(wavhdr->format); wavhdr->channels = BSWAP16(wavhdr->channels); wavhdr->samp_rate = BSWAP32(wavhdr->samp_rate); wavhdr->avg_samp_rate = BSWAP32(wavhdr->avg_samp_rate); wavhdr->align = BSWAP16(wavhdr->align); wavhdr->bits_per_sample = BSWAP16(wavhdr->bits_per_sample); wavhdr->data_tag = BSWAP32(wavhdr->data_tag); wavhdr->data_length = BSWAP32(wavhdr->data_length); return wavhdr; } void play_wav(char *name) { WAVHDR *wavhdr; char *audiobuf = NULL; int fd = 0, audio = 0, bufsize, samplesize, stereo, speed, toread, n; if (! strlen(name)) return; if ((audio = open("/dev/dsp", O_WRONLY)) == -1) { perror("DSP open"); goto end; } if ((fd = open(name, O_RDONLY)) == -1) { perror("open"); goto end; } if (! (wavhdr = read_wavhdr(fd))) goto end; if ((wavhdr->riff_tag != RIFF) || (wavhdr->wave_tag != WAVE) || (wavhdr->fmt_tag != FMT) || (wavhdr->data_tag != DATA)) { fprintf(stderr, "Invalid WAV format\n"); goto end; } if (wavhdr->format != PCM_CODE) { fprintf(stderr, "Can't play not PCM-coded WAV files\n"); goto end; } if (wavhdr->channels > 2) { fprintf(stderr, "Can't play WAV files with %d channels\n", wavhdr->channels); goto end; } if (ioctl(audio, SNDCTL_DSP_GETBLKSIZE, &bufsize) == -1) { perror("SNDCTL_DSP_GETBLKSIZE"); goto end; } audiobuf = (char*)malloc(bufsize); samplesize = (int)wavhdr->bits_per_sample; stereo = (wavhdr->channels == 2) ? 1 : 0; speed = (int)wavhdr->samp_rate; if (ioctl(audio, SNDCTL_DSP_SAMPLESIZE, &samplesize) == -1) { perror("SNDCTL_DSP_SAMPLESIZE"); goto end; } if (ioctl(audio, SNDCTL_DSP_STEREO, &stereo) == -1) { perror("SNDCTL_DSP_STEREO"); goto end; } if (ioctl(audio, SNDCTL_DSP_SPEED, &speed) == -1) { perror("SNDCTL_DSP_SPEED"); goto end; } printf("Playing '%s' at %d bits, %d Hz ", name, samplesize, speed); if (stereo) printf("stereo\n"); else printf("mono\n"); toread = wavhdr->data_length; while (toread) { n = (toread > bufsize) ? bufsize : toread; if (read(fd, audiobuf, n) == -1) { perror("read"); break; } if (write(audio, audiobuf, n) == -1) { perror("DSP write"); break; } toread -= n; } end: if (audio > 0) close(audio); if (fd > 0) close(fd); if (audiobuf) free(audiobuf); } int main(int argc, char **argv) { int i; if (argc < 2) { fprintf(stderr, "usage: wplay \n"); exit(0); } for (i = 1; i < argc; i++) play_wav(argv[i]); return 0; } .