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");
69 int open_audio(unsigned int *fragment_size
, unsigned int channels
,
70 unsigned int samples_per_sec
, unsigned int bits
)
76 if ((audio
= open("/dev/audio", O_RDWR
)) < 0)
78 printf("Cannot open /dev/audio: %s\n", strerror(errno
));
82 ioctl(audio
, DSPIOMAX
, fragment_size
); /* Get maximum fragment size. */
84 /* Set DSP parameters (should check return values..) */
85 ioctl(audio
, DSPIOSIZE
, fragment_size
); /* Use max. fragment size. */
86 ioctl(audio
, DSPIOSTEREO
, &channels
);
87 ioctl(audio
, DSPIORATE
, &samples_per_sec
);
88 ioctl(audio
, DSPIOBITS
, &bits
);
89 sign
= (bits
== 16 ? 1 : 0);
90 ioctl(audio
, DSPIOSIGN
, &sign
);
94 int main ( int argc
, char *argv
[] )
96 int i
, r
, audio
, file
;
97 char *buffer
, *file_name
= NULL
;
98 unsigned int fragment_size
, fragment_size2
;
102 /* Check Parameters */
105 if (strncmp(argv
[1], "-i", 2) == 0)
113 else file_name
= argv
[1];
116 if((file
= open(file_name
, O_RDONLY
)) < 0)
118 printf("Cannot open %s\n", file_name
);
122 /* Check for valid wave format */
123 read(file
, &r_fields
, 20);
124 if(r_fields
.RIFF_id
!= RIFF_ID
)
126 printf("%s not in RIFF format\n", file_name
);
129 if(r_fields
.WAVE_id1
!= WAVE_ID1
|| r_fields
.WAVE_id2
!= WAVE_ID2
)
131 printf("%s not in WAVE format\n", file_name
);
135 /* Store data_chunk position */
136 data_pos
= lseek(file
, 0L, 1) + r_fields
.data_ptr
;
138 /* Read the common and specific fields */
139 read(file
, &c_fields
, 14);
140 read(file
, &s_fields
, 2);
142 /* Check for valid wave format, we can only play MicroSoft PCM */
143 if(c_fields
.FormatTag
!= MS_PCM_FORMAT
)
145 printf("%s not in MicroSoft PCM format\n", file_name
);
149 /* Open audio device and set DSP parameters */
150 audio
= open_audio(&fragment_size
, c_fields
.Channels
- 1,
151 c_fields
.SamplesPerSec
, s_fields
.BitsPerSample
);
153 if ((buffer
= malloc(fragment_size
)) == (char *)0)
155 fprintf(stderr
, "Cannot allocate buffer\n");
159 /* Goto data chunk */
160 lseek(file
, data_pos
, SEEK_SET
);
162 /* Check for valid data chunk */
163 read(file
, &data_id
, sizeof(data_id
));
164 if(data_id
!= DATA_ID
)
166 printf("Invalid data chunk\n");
170 /* Get length of data */
171 read(file
, &data_len
, sizeof(data_len
));
175 printf("\nBits per sample : %d \n", s_fields
.BitsPerSample
);
176 printf("Stereo : %s \n", (c_fields
.Channels
== 1 ? "yes" : "no"));
177 printf("Samples per second: %ld \n", c_fields
.SamplesPerSec
);
178 printf("Average bytes/sec : %ld \n", c_fields
.AvgBytesPerSec
);
179 printf("Block alignment : %d \n", c_fields
.BlockAlign
);
180 printf("Datalength (bytes): %ld \n\n", data_len
);
186 if (data_len
> fragment_size
)
188 /* Read next fragment */
189 read(file
, buffer
, fragment_size
);
190 data_len
-= fragment_size
;
194 /* Read until end of file and fill rest of buffer with silence,
195 * in PCM this means: fill buffer with last played value
197 read(file
, buffer
, data_len
);
198 for (i
= data_len
; i
< fragment_size
; i
++)
199 buffer
[i
] = buffer
[(int)data_len
-1];
203 /* Copy data to DSP */
204 r
= write(audio
, buffer
, fragment_size
);
205 if (r
!= fragment_size
)
209 fprintf(stderr
, "playwave: write to audio device failed: %s\n",
212 /* If we get EIO, the driver might have restarted. Reopen the
217 audio
= open_audio(&fragment_size2
,
218 c_fields
.Channels
- 1, c_fields
.SamplesPerSec
,
219 s_fields
.BitsPerSample
);
220 if (fragment_size2
!= fragment_size
) {
221 fprintf(stderr
, "Fragment size has changed\n");
228 fprintf(stderr
, "playwave: partial write %d instead of %d\n",