Recognizes if input is ogg or not.
[xiph.git] / ao / src / ao_wav.c
blobf816b220dc9bd1b9a7dbcabe28246cce233f26f9
1 /*
3 * ao_wav.c
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)
14 * any later version.
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.
28 #include <stdio.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <signal.h>
32 #include <ao/ao.h>
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
51 struct riff_struct {
52 unsigned char id[4]; /* RIFF */
53 unsigned int len;
54 unsigned char wave_id[4]; /* WAVE */
58 struct chunk_struct
60 unsigned char id[4];
61 unsigned int len;
64 struct common_struct
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 */
74 struct wave_header
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 =
85 AO_TYPE_FILE,
86 "WAV file output",
87 "wav",
88 "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>",
89 "Sends output to a .wav file",
90 AO_FMT_LITTLE,
92 NULL, /* No options */
96 typedef struct ao_wav_internal
98 struct wave_header wave;
99 } ao_wav_internal;
102 static int ao_wav_test(void)
104 return 1; /* File driver always works */
108 static ao_info *ao_wav_driver_info(void)
110 return &ao_wav_info;
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,
132 const char *value)
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)
188 != WAV_HEADER_LEN) {
189 return 0; /* Could not write wav header */
192 device->driver_byte_format = AO_FMT_LITTLE;
194 return 1;
199 * play the sample to the already opened file descriptor
201 static int ao_wav_play(ao_device *device, const char *output_samples,
202 uint_32 num_bytes)
204 if (fwrite(output_samples, sizeof(char), num_bytes,
205 device->file) < num_bytes)
206 return 0;
207 else
208 return 1;
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 */
217 long size;
219 /* Find how long our file is in total, including header */
220 size = ftell(device->file);
222 if (size < 0) {
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;
256 free(internal);
260 ao_functions ao_wav = {
261 ao_wav_test,
262 ao_wav_driver_info,
263 ao_wav_device_init,
264 ao_wav_set_option,
265 ao_wav_open,
266 ao_wav_play,
267 ao_wav_close,
268 ao_wav_device_clear