1 /*
2  * Copyright (c) 1998-2001 Yoshihide SONODA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 
37 #if defined (__FreeBSD__) && __FreeBSD__ < 4
38 #include <machine/soundcard.h>
39 #else
40 #include <sys/soundcard.h>
41 #endif
42 
43 #include "wavefmt.h"
44 
45 #ifndef DEFAULT_DSP
46 #define DEFAULT_DSP "/dev/dsp"
47 #endif
48 
49 #ifndef DEFAULT_BUFFERSIZE
50 #define DEFAULT_BUFFERSIZE 2048
51 #endif
52 
53 /* �ؿ��ץ�ȥ����� */
54 int readWaveFile(int fd, PWAVEFORMAT pwavefmt, u_int *datasize);
55 int openDSP(const char* devname, PWAVEFORMAT pwf);
56 int closeDSP(int fd);
57 int playWave(int data_fd, int dsp_fd, u_int datasize);
58 int playRaw(int data_fd, int dsp_fd);
59 int play(const char* filename);
60 
61 /* �����Х��ѿ� */
62 static int vflag = 1;
63 static int cflag = 0;
64 static int rflag = 0;
65 static int sampling_rate = 44100;
66 static int channels = 2;
67 static int bits_per_sample = 16;
68 
69 static size_t bsize = DEFAULT_BUFFERSIZE;
70 static char *dsp_fname = DEFAULT_DSP;
71 static char *sbuf = NULL;
72 
73 int main(int argc, char* argv[])
74 {
75     int ch;
76     int rc = 0;
77 
78     while ((ch = getopt(argc, argv, "csrhb:f:B:C:S:")) != -1)
79     {
80 		switch(ch)
81 		{
82 		case 'b':
83 			bsize = (size_t)strtol(optarg, NULL, 10) * 1024;
84 			if (bsize == 0)
85 				bsize = DEFAULT_BUFFERSIZE;
86 			break;
87 		case 'c':
88 			cflag = 1;
89 			break;
90 		case 'f':
91 			dsp_fname = optarg;
92 			break;
93 		case 's':
94 			vflag = 0;
95 			break;
96 		case 'r':
97 			rflag = 1;
98 			break;
99 		case 'S':
100 			rflag = 1;
101 			sampling_rate = (int)strtol(optarg, NULL, 10);
102 			break;
103 		case 'B':
104 			rflag = 1;
105 			bits_per_sample = (int)strtol(optarg, NULL, 10);
106 			break;
107 		case 'C':
108 			rflag = 1;
109 			channels = (int)strtol(optarg, NULL, 10);
110 			break;
111 		case 'h':
112 		default:
113 			fprintf(stderr,
114 					"Usage: waveplay [-b size] [-f dev] [-chrs]\n"
115 					"                [-S rate] [-B bits] [-C channels] [-] [wavefile | pcmfile]\n");
116 			return 1;
117 			break;
118 		}
119     }
120     argc -= optind;
121     argv += optind;
122 
123     if (argc == 0)
124     	rc += play("-");
125     else
126     {
127 		while (*argv)
128 		{
129 			rc += play(argv[0]);
130 			argv++;
131 			//usleep(1000);
132 		}
133     }
134 
135     /* ���ͤϥ��顼�θĿ� */
136     if (rc < 0)
137         rc = -rc;
138 
139     return rc;
140 }
141 
142 int play(const char* filename)
143 {
144     int in_fd;
145     int out_fd;
146     WAVEFORMAT wf;
147     u_int datasize;
148     int rc;
149     int stdin_flag = !strcmp(filename, "-");
150 
151     if (stdin_flag)
152     	in_fd = STDIN_FILENO;
153     else
154     {
155 		if ((in_fd = open(filename, O_RDONLY)) == -1)
156 		{
157 			fprintf(stderr, "%s - ", filename);
158 			perror("open");
159 			return in_fd;
160 		}
161     }
162 
163     if (rflag)
164     {
165 		wf.nSamplesPerSec = sampling_rate;
166 		wf.wBitsPerSample = bits_per_sample;
167 		wf.nChannels = channels;
168     }
169     else
170     {
171 		if (readWaveFile(in_fd, &wf, &datasize))
172 		{
173 			close(in_fd);
174 			return -1;
175 		}
176     }
177 
178     if (vflag)
179     {
180 		if (!stdin_flag)
181             fprintf(stderr, "File name     : %s\n", filename);
182         fprintf(stderr, "Sampling rate : %d Hz\n", wf.nSamplesPerSec);
183         fprintf(stderr, "Bits/Sample   : %d Bits\n", wf.wBitsPerSample);
184         fprintf(stderr, "Channels      : %d\n", wf.nChannels);
185 		if (!rflag)
186             fprintf(stderr, "Size          : %d Bytes\n", datasize);
187         fprintf(stderr, "\n");
188     }
189 
190     if (cflag)
191         out_fd = STDOUT_FILENO;
192     else
193     {
194         if ((out_fd = openDSP(dsp_fname, &wf)) == -1)
195 		{
196             //perror("openDSP");
197             close(in_fd);
198             return -1;
199 		}
200     }
201 
202     sbuf = (char *)malloc(bsize);
203     if (sbuf == NULL)
204     {
205         fprintf(stderr, "Error: Can't alloc memory.");
206         return -1;
207     }
208 
209     if (rflag)
210 		rc = playRaw(in_fd, out_fd);
211     else
212 		rc = playWave(in_fd, out_fd, datasize);
213 
214     close(in_fd);
215     if (!cflag)
216         closeDSP(out_fd);
217 
218     free(sbuf);
219     return rc;
220 }
221 
222 int readWaveFile(int fd, PWAVEFORMAT pwavefmt, u_int *datasize)
223 {
224     int header = 0;
225     int size = 0;
226     char *buff;
227 
228     *datasize = 0;
229     read(fd, (char *)&header, sizeof(int));
230     if (header != H_RIFF)
231     {
232 		fprintf(stderr, "Error: Not RIFF file.\n");
233 		return 1;
234     }
235 
236     read(fd, (char *)&size, sizeof(int));
237     read(fd, (char *)&header, sizeof(int));
238     if (header != H_WAVE)
239     {
240 		fprintf(stderr, "Error: Not WAVE file.\n");
241 		return 2;
242     }
243 
244     while(read(fd, (char *)&header, sizeof(int)) == sizeof(int))
245     {
246 		read(fd, (char *)&size, sizeof(int));
247 
248 		if (header == H_FMT)
249 		{
250 			if ((size_t)size < sizeof(WAVEFORMAT))
251 			{
252 				fprintf(stderr, "Error: Illegal header.\n");
253 				return 3;
254 			}
255 			buff = malloc((size_t)size);
256 			read(fd, buff, size);
257 			memcpy((void *)pwavefmt, (void *)buff, sizeof(WAVEFORMAT));
258 			free(buff);
259 			if (pwavefmt->wFormatTag != 1)
260 			{
261 				fprintf(stderr, "Error: Unsupported format(0x%x).\n",
262                         pwavefmt->wFormatTag);
263 				return 4;
264 			}
265 		}
266 		else if (header == H_DATA)
267 		{
268 			/* �ե�����ݥ�����data���������ã������ؿ���λ */
269 			*datasize = (u_int)size;
270 			return 0;
271 		}
272 		else
273 		{
274 			/* ;�פʥ�������ɤ����Ф� */
275 			lseek(fd, size, SEEK_CUR);
276 		}
277     }
278 
279     fprintf(stderr, "Error: data chunk not found.\n");
280     return 10;
281 }
282 
283 int openDSP(const char* devname, PWAVEFORMAT pwf)
284 {
285     int fd;
286     int status;
287     int arg;
288 
289     if ((fd = open(devname, O_WRONLY)) == -1) {
290         fprintf(stderr, "%s - ", devname);
291         perror("openDSP");
292     	return fd;
293     }
294 
295     /* �����ͥ�(STEREO or MONAURAL)������ */
296     arg = (int)(pwf->nChannels);
297     status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
298 	if (status < 0)
299 	{
300 		perror("openDSP");
301 		close(fd);
302 		return -1;
303 	}
304 
305     if (arg != (int)(pwf->nChannels))
306     {
307 		fprintf(stderr, "Can't set channels.\n");
308 		close(fd);
309 		return -1;
310     }
311 
312     /* ����ץ���졼�Ȥ����� */
313     arg = (int)(pwf->nSamplesPerSec);
314     status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
315     if (status < 0)
316     {
317 		perror("openDSP");
318 		fprintf(stderr, "Can't set sampling rate.\n");
319 		close(fd);
320 		return -1;
321     }
322 
323 	if (vflag && (arg != (int)pwf->nSamplesPerSec))
324 	{
325 		fprintf(stderr, "Warning: Can't set sampling rate %d Hz.\n",
326 				(int)pwf->nSamplesPerSec);
327 		fprintf(stderr, "Using %d Hz instead.\n", arg);
328 	}
329 #ifdef DEBUG
330     printf("DSP - Sampling rate: %d\n", arg);
331 #endif
332 
333     /* �̻Ҳ��ӥåȿ�(8 or 16Bit)������ */
334     arg = (int)(pwf->wBitsPerSample);
335     status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
336     if (status < 0)
337 	{
338 		perror("openDSP");
339 		close(fd);
340 		return -1;
341 	}
342 
343 	if (arg != (int)(pwf->wBitsPerSample))
344     {
345 		if (vflag)
346 			fprintf(stderr, "Can't set bit width.\n");
347 		close(fd);
348 		return -1;
349     }
350 
351     return fd;
352 }
353 
354 int closeDSP(int fd)
355 {
356     ioctl(fd, SNDCTL_DSP_SYNC);
357     return close(fd);
358 }
359 
360 int playRaw(int data_fd, int dsp_fd)
361 {
362     register int nr, nw, off;
363 
364     while ((nr = read(data_fd, sbuf, bsize)) > 0)
365     {
366 		for (off = 0; nr; nr -= nw, off += nw)
367 		{
368 			if ((nw = write(dsp_fd, sbuf + off, nr)) < 0)
369 			{
370                 fprintf(stderr, "Error: playRaw - write data\n");
371 				return -1;
372 			}
373 		}
374     }
375 
376     return 0;
377 }
378 
379 int playWave(int data_fd, int dsp_fd, u_int datasize)
380 {
381     register int i, nr, nw, off;
382     int tr, rd;
383 
384 #ifdef DEBUG
385     fprintf(stderr, "datasize = %d, bsize =  %d\n", datasize, bsize);
386 #endif
387     tr = datasize / bsize;
388     rd = datasize % bsize;
389 
390     for (i = 0; i < tr + 1; i++)
391     {
392 		if (i == tr)
393 		{
394 			if (rd == 0)
395 				break;
396 
397 			if ((nr = read(data_fd, sbuf, rd)) <= 0)
398 				break;
399 		}
400 		else
401 		{
402 			if ((nr = read(data_fd, sbuf, bsize)) <= 0)
403 				break;
404 		}
405 
406 		for (off = 0; nr; nr -= nw, off += nw)
407 		{
408 			if ((nw = write(dsp_fd, sbuf + off, nr)) < 0)
409 			{
410 				fprintf(stderr, "Error: playWave - write data\n");
411 				return -1;
412 			}
413 		}
414     }
415 
416     return 0;
417 }
418