/* * Copyright (c) 1998-2001 Yoshihide SONODA * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #if defined (__FreeBSD__) && __FreeBSD__ < 4 #include #else #include #endif #include "wavefmt.h" #ifndef DEFAULT_DSP #define DEFAULT_DSP "/dev/dsp" #endif #ifndef DEFAULT_BUFFERSIZE #define DEFAULT_BUFFERSIZE 2048 #endif /* 関数プロトタイプ */ int readWaveFile(int fd, PWAVEFORMAT pwavefmt, u_int *datasize); int openDSP(const char* devname, PWAVEFORMAT pwf); int closeDSP(int fd); int playWave(int data_fd, int dsp_fd, u_int datasize); int playRaw(int data_fd, int dsp_fd); int play(const char* filename); /* グローバル変数 */ static int vflag = 1; static int cflag = 0; static int rflag = 0; static int sampling_rate = 44100; static int channels = 2; static int bits_per_sample = 16; static size_t bsize = DEFAULT_BUFFERSIZE; static char *dsp_fname = DEFAULT_DSP; static char *sbuf = NULL; int main(int argc, char* argv[]) { int ch; int rc = 0; while ((ch = getopt(argc, argv, "csrhb:f:B:C:S:")) != -1) { switch(ch) { case 'b': bsize = (size_t)strtol(optarg, NULL, 10) * 1024; if (bsize == 0) bsize = DEFAULT_BUFFERSIZE; break; case 'c': cflag = 1; break; case 'f': dsp_fname = optarg; break; case 's': vflag = 0; break; case 'r': rflag = 1; break; case 'S': rflag = 1; sampling_rate = (int)strtol(optarg, NULL, 10); break; case 'B': rflag = 1; bits_per_sample = (int)strtol(optarg, NULL, 10); break; case 'C': rflag = 1; channels = (int)strtol(optarg, NULL, 10); break; case 'h': default: fprintf(stderr, "Usage: waveplay [-b size] [-f dev] [-chrs]\n" " [-S rate] [-B bits] [-C channels] [-] [wavefile | pcmfile]\n"); return 1; break; } } argc -= optind; argv += optind; if (argc == 0) rc += play("-"); else { while (*argv) { rc += play(argv[0]); argv++; //usleep(1000); } } /* 戻値はエラーの個数 */ if (rc < 0) rc = -rc; return rc; } int play(const char* filename) { int in_fd; int out_fd; WAVEFORMAT wf; u_int datasize; int rc; int stdin_flag = !strcmp(filename, "-"); if (stdin_flag) in_fd = STDIN_FILENO; else { if ((in_fd = open(filename, O_RDONLY)) == -1) { fprintf(stderr, "%s - ", filename); perror("open"); return in_fd; } } if (rflag) { wf.nSamplesPerSec = sampling_rate; wf.wBitsPerSample = bits_per_sample; wf.nChannels = channels; } else { if (readWaveFile(in_fd, &wf, &datasize)) { close(in_fd); return -1; } } if (vflag) { if (!stdin_flag) fprintf(stderr, "File name : %s\n", filename); fprintf(stderr, "Sampling rate : %d Hz\n", wf.nSamplesPerSec); fprintf(stderr, "Bits/Sample : %d Bits\n", wf.wBitsPerSample); fprintf(stderr, "Channels : %d\n", wf.nChannels); if (!rflag) fprintf(stderr, "Size : %d Bytes\n", datasize); fprintf(stderr, "\n"); } if (cflag) out_fd = STDOUT_FILENO; else { if ((out_fd = openDSP(dsp_fname, &wf)) == -1) { //perror("openDSP"); close(in_fd); return -1; } } sbuf = (char *)malloc(bsize); if (sbuf == NULL) { fprintf(stderr, "Error: Can't alloc memory."); return -1; } if (rflag) rc = playRaw(in_fd, out_fd); else rc = playWave(in_fd, out_fd, datasize); close(in_fd); if (!cflag) closeDSP(out_fd); free(sbuf); return rc; } int readWaveFile(int fd, PWAVEFORMAT pwavefmt, u_int *datasize) { int header = 0; int size = 0; char *buff; *datasize = 0; read(fd, (char *)&header, sizeof(int)); if (header != H_RIFF) { fprintf(stderr, "Error: Not RIFF file.\n"); return 1; } read(fd, (char *)&size, sizeof(int)); read(fd, (char *)&header, sizeof(int)); if (header != H_WAVE) { fprintf(stderr, "Error: Not WAVE file.\n"); return 2; } while(read(fd, (char *)&header, sizeof(int)) == sizeof(int)) { read(fd, (char *)&size, sizeof(int)); if (header == H_FMT) { if ((size_t)size < sizeof(WAVEFORMAT)) { fprintf(stderr, "Error: Illegal header.\n"); return 3; } buff = malloc((size_t)size); read(fd, buff, size); memcpy((void *)pwavefmt, (void *)buff, sizeof(WAVEFORMAT)); free(buff); if (pwavefmt->wFormatTag != 1) { fprintf(stderr, "Error: Unsupported format(0x%x).\n", pwavefmt->wFormatTag); return 4; } } else if (header == H_DATA) { /* ファイルポインタがdataチャンクに到達したら関数を終了 */ *datasize = (u_int)size; return 0; } else { /* 余計なチャンクは読み飛ばす */ lseek(fd, size, SEEK_CUR); } } fprintf(stderr, "Error: data chunk not found.\n"); return 10; } int openDSP(const char* devname, PWAVEFORMAT pwf) { int fd; int status; int arg; if ((fd = open(devname, O_WRONLY)) == -1) { fprintf(stderr, "%s - ", devname); perror("openDSP"); return fd; } /* チャンネル(STEREO or MONAURAL)を設定 */ arg = (int)(pwf->nChannels); status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg); if (status < 0) { perror("openDSP"); close(fd); return -1; } if (arg != (int)(pwf->nChannels)) { fprintf(stderr, "Can't set channels.\n"); close(fd); return -1; } /* サンプリングレートを設定 */ arg = (int)(pwf->nSamplesPerSec); status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg); if (status < 0) { perror("openDSP"); fprintf(stderr, "Can't set sampling rate.\n"); close(fd); return -1; } if (vflag && (arg != (int)pwf->nSamplesPerSec)) { fprintf(stderr, "Warning: Can't set sampling rate %d Hz.\n", (int)pwf->nSamplesPerSec); fprintf(stderr, "Using %d Hz instead.\n", arg); } #ifdef DEBUG printf("DSP - Sampling rate: %d\n", arg); #endif /* 量子化ビット数(8 or 16Bit)を設定 */ arg = (int)(pwf->wBitsPerSample); status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg); if (status < 0) { perror("openDSP"); close(fd); return -1; } if (arg != (int)(pwf->wBitsPerSample)) { if (vflag) fprintf(stderr, "Can't set bit width.\n"); close(fd); return -1; } return fd; } int closeDSP(int fd) { ioctl(fd, SNDCTL_DSP_SYNC); return close(fd); } int playRaw(int data_fd, int dsp_fd) { register int nr, nw, off; while ((nr = read(data_fd, sbuf, bsize)) > 0) { for (off = 0; nr; nr -= nw, off += nw) { if ((nw = write(dsp_fd, sbuf + off, nr)) < 0) { fprintf(stderr, "Error: playRaw - write data\n"); return -1; } } } return 0; } int playWave(int data_fd, int dsp_fd, u_int datasize) { register int i, nr, nw, off; int tr, rd; #ifdef DEBUG fprintf(stderr, "datasize = %d, bsize = %d\n", datasize, bsize); #endif tr = datasize / bsize; rd = datasize % bsize; for (i = 0; i < tr + 1; i++) { if (i == tr) { if (rd == 0) break; if ((nr = read(data_fd, sbuf, rd)) <= 0) break; } else { if ((nr = read(data_fd, sbuf, bsize)) <= 0) break; } for (off = 0; nr; nr -= nw, off += nw) { if ((nw = write(dsp_fd, sbuf + off, nr)) < 0) { fprintf(stderr, "Error: playWave - write data\n"); return -1; } } } return 0; }