5 * Original Copyright (C) Aaron Holtzman - May 1999
6 * Modifications Copyright (C) Stan Seibert - July 2000, July 2001
8 * This file is part of libao, a cross-platform audio output library. See
9 * README for a history of this source code.
11 * libao is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
16 * libao is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with GNU Make; see the file COPYING. If not, write to
23 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
34 #define WAVE_FORMAT_PCM 0x0001
35 #define FORMAT_MULAW 0x0101
36 #define IBM_FORMAT_ALAW 0x0102
37 #define IBM_FORMAT_ADPCM 0x0103
39 #define WAV_HEADER_LEN 44
41 #define WRITE_U32(buf, x) *(buf) = (unsigned char)(x&0xff);\
42 *((buf)+1) = (unsigned char)((x>>8)&0xff);\
43 *((buf)+2) = (unsigned char)((x>>16)&0xff);\
44 *((buf)+3) = (unsigned char)((x>>24)&0xff);
46 #define WRITE_U16(buf, x) *(buf) = (unsigned char)(x&0xff);\
47 *((buf)+1) = (unsigned char)((x>>8)&0xff);
49 #define DEFAULT_SWAP_BUFFER_SIZE 2048
52 unsigned char id
[4]; /* RIFF */
54 unsigned char wave_id
[4]; /* WAVE */
66 unsigned short wFormatTag
;
67 unsigned short wChannels
;
68 unsigned int dwSamplesPerSec
;
69 unsigned int dwAvgBytesPerSec
;
70 unsigned short wBlockAlign
;
71 unsigned short wBitsPerSample
; /* Only for PCM */
76 struct riff_struct riff
;
77 struct chunk_struct format
;
78 struct common_struct common
;
79 struct chunk_struct data
;
83 static ao_info ao_wav_info
=
88 "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>",
89 "Sends output to a .wav file",
92 NULL
, /* No options */
96 typedef struct ao_wav_internal
98 struct wave_header wave
;
102 static int ao_wav_test(void)
104 return 1; /* File driver always works */
108 static ao_info
*ao_wav_driver_info(void)
114 static int ao_wav_device_init(ao_device
*device
)
116 ao_wav_internal
*internal
;
118 internal
= (ao_wav_internal
*) malloc(sizeof(ao_wav_internal
));
120 if (internal
== NULL
)
121 return 0; /* Could not initialize device memory */
123 memset(&(internal
->wave
), 0, sizeof(internal
->wave
));
125 device
->internal
= internal
;
127 return 1; /* Memory alloc successful */
131 static int ao_wav_set_option(ao_device
*device
, const char *key
,
134 return 1; /* No options! */
138 static int ao_wav_open(ao_device
*device
, ao_sample_format
*format
)
140 ao_wav_internal
*internal
= (ao_wav_internal
*) device
->internal
;
141 unsigned char buf
[WAV_HEADER_LEN
];
142 int size
= 0x7fffffff; /* Use a bogus size initially */
144 /* Store information */
145 internal
->wave
.common
.wChannels
= format
->channels
;
146 internal
->wave
.common
.wBitsPerSample
= format
->bits
;
147 internal
->wave
.common
.dwSamplesPerSec
= format
->rate
;
149 memset(buf
, 0, WAV_HEADER_LEN
);
151 /* Fill out our wav-header with some information. */
152 strncpy(internal
->wave
.riff
.id
, "RIFF",4);
153 internal
->wave
.riff
.len
= size
- 8;
154 strncpy(internal
->wave
.riff
.wave_id
, "WAVE",4);
156 strncpy(internal
->wave
.format
.id
, "fmt ",4);
157 internal
->wave
.format
.len
= 16;
159 internal
->wave
.common
.wFormatTag
= WAVE_FORMAT_PCM
;
160 internal
->wave
.common
.dwAvgBytesPerSec
=
161 internal
->wave
.common
.wChannels
*
162 internal
->wave
.common
.dwSamplesPerSec
*
163 (internal
->wave
.common
.wBitsPerSample
>> 3);
165 internal
->wave
.common
.wBlockAlign
=
166 internal
->wave
.common
.wChannels
*
167 (internal
->wave
.common
.wBitsPerSample
>> 3);
169 strncpy(internal
->wave
.data
.id
, "data",4);
171 internal
->wave
.data
.len
= size
- 44;
173 strncpy(buf
, internal
->wave
.riff
.id
, 4);
174 WRITE_U32(buf
+4, internal
->wave
.riff
.len
);
175 strncpy(buf
+8, internal
->wave
.riff
.wave_id
, 4);
176 strncpy(buf
+12, internal
->wave
.format
.id
,4);
177 WRITE_U32(buf
+16, internal
->wave
.format
.len
);
178 WRITE_U16(buf
+20, internal
->wave
.common
.wFormatTag
);
179 WRITE_U16(buf
+22, internal
->wave
.common
.wChannels
);
180 WRITE_U32(buf
+24, internal
->wave
.common
.dwSamplesPerSec
);
181 WRITE_U32(buf
+28, internal
->wave
.common
.dwAvgBytesPerSec
);
182 WRITE_U16(buf
+32, internal
->wave
.common
.wBlockAlign
);
183 WRITE_U16(buf
+34, internal
->wave
.common
.wBitsPerSample
);
184 strncpy(buf
+36, internal
->wave
.data
.id
, 4);
185 WRITE_U32(buf
+40, internal
->wave
.data
.len
);
187 if (fwrite(buf
, sizeof(char), WAV_HEADER_LEN
, device
->file
)
189 return 0; /* Could not write wav header */
192 device
->driver_byte_format
= AO_FMT_LITTLE
;
199 * play the sample to the already opened file descriptor
201 static int ao_wav_play(ao_device
*device
, const char *output_samples
,
204 if (fwrite(output_samples
, sizeof(char), num_bytes
,
205 device
->file
) < num_bytes
)
212 static int ao_wav_close(ao_device
*device
)
214 ao_wav_internal
*internal
= (ao_wav_internal
*) device
->internal
;
215 unsigned char buf
[4]; /* For holding length values */
219 /* Find how long our file is in total, including header */
220 size
= ftell(device
->file
);
223 return 0; /* Wav header corrupt */
226 /* Go back and set correct length info */
228 internal
->wave
.riff
.len
= size
- 8;
229 internal
->wave
.data
.len
= size
- 44;
231 /* Rewind to riff len and write it */
232 if (fseek(device
->file
, 4, SEEK_SET
) < 0)
233 return 0; /* Wav header corrupt */
235 WRITE_U32(buf
, internal
->wave
.riff
.len
);
236 if (fwrite(buf
, sizeof(char), 4, device
->file
) < 4)
237 return 0; /* Wav header corrupt */
240 /* Rewind to data len and write it */
241 if (fseek(device
->file
, 40, SEEK_SET
) < 0)
242 return 0; /* Wav header corrupt */
244 WRITE_U32(buf
, internal
->wave
.data
.len
);
245 if (fwrite(buf
, sizeof(char), 4, device
->file
) < 4)
246 return 0; /* Wav header corrupt */
249 return 1; /* Wav header correct */
252 static void ao_wav_device_clear(ao_device
*device
)
254 ao_wav_internal
*internal
= (ao_wav_internal
*) device
->internal
;
260 ao_functions ao_wav
= {