1 /*
2 * madplay - MPEG audio decoder and player
3 * Copyright (C) 2000-2004 Robert Leslie
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * $Id: audio_aiff.c,v 1.7 2004/01/23 09:41:31 rob Exp $
20 */
21
22 # ifdef HAVE_CONFIG_H
23 # include "config.h"
24 # endif
25
26 # include "global.h"
27
28 # include <stdio.h>
29 # include <string.h>
30 # include <mad.h>
31
32 # include "audio.h"
33
34 static FILE *outfile;
35 static audio_pcmfunc_t *audio_pcm;
36 static unsigned long nsamples;
37
38 static unsigned long form_len, ssnd_len;
39 static long comm_chunk, ssnd_chunk;
40
41 static unsigned int config_channels;
42 static unsigned int config_speed;
43 static unsigned int config_precision;
44
45 # define UNKNOWN_LENGTH "\xff\xff\xff\xff"
46
47 static
init(struct audio_init * init)48 int init(struct audio_init *init)
49 {
50 if (init->path && strcmp(init->path, "-") != 0) {
51 outfile = fopen(init->path, "wb");
52 if (outfile == 0) {
53 audio_error = ":";
54 return -1;
55 }
56 }
57 else
58 outfile = stdout;
59
60 /* group ID and file type ID header */
61
62 if (fwrite("FORM" UNKNOWN_LENGTH "AIFF", 4 + 4 + 4, 1, outfile) != 1) {
63 audio_error = ":fwrite";
64 return -1;
65 }
66
67 form_len = 4;
68 comm_chunk = -1;
69 ssnd_chunk = -1;
70
71 config_channels = 0;
72 config_speed = 0;
73 config_precision = 0;
74
75 return 0;
76 }
77
78 /*
79 * NAME: int32()
80 * DESCRIPTION: store 32-bit big-endian integer
81 */
82 static
int32(unsigned char * ptr,unsigned long num)83 void int32(unsigned char *ptr, unsigned long num)
84 {
85 ptr[0] = num >> 24;
86 ptr[1] = num >> 16;
87 ptr[2] = num >> 8;
88 ptr[3] = num >> 0;
89 }
90
91 /*
92 * NAME: int16()
93 * DESCRIPTION: store 16-bit big-endian integer
94 */
95 static
int16(unsigned char * ptr,unsigned int num)96 void int16(unsigned char *ptr, unsigned int num)
97 {
98 ptr[0] = num >> 8;
99 ptr[1] = num >> 0;
100 }
101
102 /*
103 * NAME: float80()
104 * DESCRIPTION: store 80-bit IEEE Standard 754 floating point number
105 */
106 static
float80(unsigned char * ptr,signed long num)107 void float80(unsigned char *ptr, signed long num)
108 {
109 if (num == 0)
110 memset(ptr, 0, 10);
111 else {
112 int exp;
113 unsigned int s, e;
114 unsigned long abs, sr, f;
115
116 enum {
117 BIAS = 0x3fff
118 };
119
120 s = num < 0;
121 abs = s ? -num : num;
122
123 for (exp = -1, sr = abs; sr; sr >>= 1)
124 ++exp;
125
126 e = exp + BIAS;
127
128 /* write normalized value; high bit of f (i) is always set */
129
130 f = abs << (32 - exp - 1);
131
132 ptr[0] = (s << 7) | (e >> 8);
133 ptr[1] = (e >> 0);
134 ptr[2] = (f >> 24);
135 ptr[3] = (f >> 16);
136 ptr[4] = (f >> 8);
137 ptr[5] = (f >> 0);
138 ptr[6] = 0;
139 ptr[7] = 0;
140 ptr[8] = 0;
141 ptr[9] = 0;
142 }
143 }
144
145 static
config(struct audio_config * config)146 int config(struct audio_config *config)
147 {
148 unsigned int bitdepth;
149 unsigned char chunk[8 + 18];
150
151 if (config_precision) {
152 /* it's not possible to change the format once set */
153
154 config->channels = config_channels;
155 config->speed = config_speed;
156 config->precision = config_precision;
157
158 return 0;
159 }
160
161 bitdepth = config->precision;
162 if (bitdepth == 0)
163 bitdepth = 16;
164 else if (bitdepth > 32)
165 bitdepth = 32;
166
167 /* Common chunk */
168
169 comm_chunk = ftell(outfile);
170
171 memcpy(&chunk[0], "COMM", 4); /* chunkID */
172 int32(&chunk[4], 18); /* chunkSize */
173
174 int16(&chunk[8], config->channels); /* numChannels */
175 int32(&chunk[10], ~0L); /* numSampleFrames */
176 int16(&chunk[14], bitdepth); /* sampleSize */
177 float80(&chunk[16], config->speed); /* sampleRate */
178
179 if (fwrite(chunk, 8 + 18, 1, outfile) != 1) {
180 audio_error = ":fwrite";
181 return -1;
182 }
183
184 form_len += 8 + 18;
185
186 /* Sound Data chunk */
187
188 ssnd_chunk = ftell(outfile);
189
190 memcpy(&chunk[0], "SSND", 4); /* chunkID */
191 int32(&chunk[4], ~0L); /* chunkSize */
192
193 int32(&chunk[8], 0); /* offset */
194 int32(&chunk[12], 0); /* blockSize */
195
196 if (fwrite(chunk, 8 + 8, 1, outfile) != 1) {
197 audio_error = ":fwrite";
198 return -1;
199 }
200
201 form_len += 8 + 8;
202 ssnd_len = 8;
203
204 switch (config->precision = bitdepth) {
205 case 1: case 2: case 3: case 4:
206 case 5: case 6: case 7: case 8:
207 audio_pcm = audio_pcm_s8;
208 break;
209
210 case 9: case 10: case 11: case 12:
211 case 13: case 14: case 15: case 16:
212 audio_pcm = audio_pcm_s16be;
213 break;
214
215 case 17: case 18: case 19: case 20:
216 case 21: case 22: case 23: case 24:
217 audio_pcm = audio_pcm_s24be;
218 break;
219
220 case 25: case 26: case 27: case 28:
221 case 29: case 30: case 31: case 32:
222 audio_pcm = audio_pcm_s32be;
223 break;
224 }
225
226 nsamples = 0;
227
228 config_channels = config->channels;
229 config_speed = config->speed;
230 config_precision = config->precision;
231
232 return 0;
233 }
234
235 static
play(struct audio_play * play)236 int play(struct audio_play *play)
237 {
238 unsigned char data[MAX_NSAMPLES * 4 * 2];
239 unsigned int len;
240
241 len = audio_pcm(data, play->nsamples, play->samples[0], play->samples[1],
242 play->mode, play->stats);
243
244 if (fwrite(data, len, 1, outfile) != 1) {
245 audio_error = ":fwrite";
246 return -1;
247 }
248
249 nsamples += play->nsamples;
250
251 ssnd_len += len;
252 form_len += len;
253
254 return 0;
255 }
256
257 static
stop(struct audio_stop * stop)258 int stop(struct audio_stop *stop)
259 {
260 return 0;
261 }
262
263 static
patch_int32(long address,unsigned long num)264 int patch_int32(long address, unsigned long num)
265 {
266 unsigned char dword[4];
267
268 if (fseek(outfile, address, SEEK_SET) == -1) {
269 audio_error = ":fseek";
270 return -1;
271 }
272
273 int32(dword, num);
274
275 if (fwrite(dword, sizeof(dword), 1, outfile) != 1) {
276 audio_error = ":fwrite";
277 return -1;
278 }
279
280 if (fseek(outfile, 0, SEEK_END) == -1) {
281 audio_error = ":fseek";
282 return -1;
283 }
284
285 return 0;
286 }
287
288 static
finish(struct audio_finish * finish)289 int finish(struct audio_finish *finish)
290 {
291 int result = 0;
292
293 if (config_precision == 0) {
294 struct audio_config dummy;
295
296 /* write empty chunks */
297
298 dummy.command = AUDIO_COMMAND_CONFIG;
299 dummy.channels = 2;
300 dummy.speed = 44100;
301 dummy.precision = 0;
302
303 result = config(&dummy);
304 }
305
306 if (ssnd_len & 1) {
307 if (fputc(0, outfile) == EOF && result == 0) {
308 audio_error = ":fputc";
309 result = -1;
310 }
311
312 ++form_len;
313 }
314
315 if (result == 0 &&
316 ((comm_chunk != -1 && patch_int32(comm_chunk + 10, nsamples) == -1) ||
317 (ssnd_chunk != -1 && patch_int32(ssnd_chunk + 4, ssnd_len) == -1)))
318 result = -1;
319
320 if (result == 0)
321 patch_int32(4, form_len);
322
323 if (outfile != stdout &&
324 fclose(outfile) == EOF &&
325 result == 0) {
326 audio_error = ":fclose";
327 result = -1;
328 }
329
330 return result;
331 }
332
audio_aiff(union audio_control * control)333 int audio_aiff(union audio_control *control)
334 {
335 audio_error = 0;
336
337 switch (control->command) {
338 case AUDIO_COMMAND_INIT:
339 return init(&control->init);
340
341 case AUDIO_COMMAND_CONFIG:
342 return config(&control->config);
343
344 case AUDIO_COMMAND_PLAY:
345 return play(&control->play);
346
347 case AUDIO_COMMAND_STOP:
348 return stop(&control->stop);
349
350 case AUDIO_COMMAND_FINISH:
351 return finish(&control->finish);
352 }
353
354 return 0;
355 }
356