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