4 * Play sound files in wave format. Only MicroSoft PCM is supported.
17 #include <sys/ioctl.h>
18 #include <minix/sound.h>
20 int main(int argc
, char **argv
);
23 /******* Wave format definitions *********/
25 #define RIFF_ID 0x46464952
26 #define WAVE_ID1 0x45564157
27 #define WAVE_ID2 0x20746D66
28 #define DATA_ID 0x61746164
29 #define MS_PCM_FORMAT 0x0001
32 #define DWORD unsigned long
52 struct specific_fields
60 /******** End of wave definitions *********/
65 fprintf(stderr
, "Usage: playwav [-i] file\n");
70 int main ( int argc
, char *argv
[] )
72 int i
, r
, audio
, file
;
73 char *buffer
, *file_name
= NULL
;
75 unsigned int fragment_size
;
76 unsigned int channels
;
81 /* Check Parameters */
84 if (strncmp(argv
[1], "-i", 2) == 0)
92 else file_name
= argv
[1];
95 if ((audio
= open("/dev/audio", O_RDWR
| O_REOPEN
)) < 0)
97 printf("Cannot open /dev/audio: %s\n", strerror(errno
));
101 /* Get maximum fragment size and try to allocate a buffer */
102 ioctl(audio
, DSPIOMAX
, &fragment_size
);
103 if ((buffer
= malloc(fragment_size
)) == (char *)0)
105 fprintf(stderr
, "Cannot allocate buffer\n");
108 ioctl(audio
, DSPIOSIZE
, &fragment_size
);
111 if((file
= open(file_name
, O_RDONLY
)) < 0)
113 printf("Cannot open %s\n", file_name
);
117 /* Check for valid wave format */
118 read(file
, &r_fields
, 20);
119 if(r_fields
.RIFF_id
!= RIFF_ID
)
121 printf("%s not in RIFF format\n", file_name
);
124 if(r_fields
.WAVE_id1
!= WAVE_ID1
|| r_fields
.WAVE_id2
!= WAVE_ID2
)
126 printf("%s not in WAVE format\n", file_name
);
130 /* Store data_chunk position */
131 data_pos
= lseek(file
, 0L, 1) + r_fields
.data_ptr
;
133 /* Read the common and specific fields */
134 read(file
, &c_fields
, 14);
135 read(file
, &s_fields
, 2);
137 /* Check for valid wave format, we can only play MicroSoft PCM */
138 if(c_fields
.FormatTag
!= MS_PCM_FORMAT
)
140 printf("%s not in MicroSoft PCM format\n", file_name
);
144 /* Set DSP parameters */
145 channels
= c_fields
.Channels
;
147 bits
= s_fields
.BitsPerSample
;
148 ioctl(audio
, DSPIOSTEREO
, &channels
);
149 ioctl(audio
, DSPIORATE
, &c_fields
.SamplesPerSec
);
150 ioctl(audio
, DSPIOBITS
, &bits
);
151 sign
= (bits
== 16 ? 1 : 0);
152 ioctl(audio
, DSPIOSIGN
, &sign
);
154 /* Goto data chunk */
155 lseek(file
, data_pos
, SEEK_SET
);
157 /* Check for valid data chunk */
158 read(file
, &data_id
, sizeof(data_id
));
159 if(data_id
!= DATA_ID
)
161 printf("Invalid data chunk\n");
165 /* Get length of data */
166 read(file
, &data_len
, sizeof(data_len
));
170 printf("\nBits per sample : %d \n", s_fields
.BitsPerSample
);
171 printf("Stereo : %s \n", (c_fields
.Channels
== 1 ? "yes" : "no"));
172 printf("Samples per second: %ld \n", c_fields
.SamplesPerSec
);
173 printf("Average bytes/sec : %ld \n", c_fields
.AvgBytesPerSec
);
174 printf("Block alignment : %d \n", c_fields
.BlockAlign
);
175 printf("Datalength (bytes): %ld \n\n", data_len
);
181 if (data_len
> fragment_size
)
183 /* Read next fragment */
184 read(file
, buffer
, fragment_size
);
185 data_len
-= fragment_size
;
189 /* Read until end of file and fill rest of buffer with silence,
190 * in PCM this means: fill buffer with last played value
192 read(file
, buffer
, data_len
);
193 for (i
= data_len
; i
< fragment_size
; i
++)
194 buffer
[i
] = buffer
[(int)data_len
-1];
198 /* Copy data to DSP */
199 r
= write(audio
, buffer
, fragment_size
);
200 if (r
!= fragment_size
)
204 fprintf(stderr
, "playwave: write to audio device failed: %s\n",
209 fprintf(stderr
, "playwave: partial write %d instead of %d\n",