]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/acm-unix.cpp
initial import
[taylor/freespace2.git] / src / sound / acm-unix.cpp
1 /***********************************************************
2  * Portions of this file are Copyright (c) Ryan C. Gordon
3  ***********************************************************/
4
5 #include "pstypes.h"
6 #include "acm.h"
7
8
9 typedef struct adpcmcoef_tag{
10         short iCoef1;
11         short iCoef2;
12 } ADPCMCOEFSET;
13
14 typedef struct adpcmblockheader_tag {
15         ubyte bPredictor;
16         ushort iDelta;
17         short iSamp1;
18         short iSamp2;
19 } ADPCMBLOCKHEADER;
20
21 typedef struct adpcmwaveformat_tag {
22         WAVEFORMATEX wav;
23         WORD wSamplesPerBlock;
24         WORD wNumCoef;
25         ADPCMCOEFSET *aCoef;
26 } ADPCMWAVEFORMAT;
27
28 typedef struct ADPCM_FMT_T {
29         ADPCMWAVEFORMAT adpcm;
30         ADPCMBLOCKHEADER *header;
31
32         int bytes_remaining;
33         uint bytes_processed;
34         uint buffer_size;
35         uint sample_frame_size;
36         uint samples_left_in_block;
37         int nibble_state;
38         ubyte nibble;
39 } adpcm_fmt_t;
40
41
42 // similar to BIAL_IF_MACRO in SDL_sound
43 #define IF_ERR(a, b) if (a) { printf("IF_ERR-ACM, function: %s, line %d...\n", __FUNCTION__, __LINE__); return b; }
44
45 static int ACM_inited = 0;
46
47
48 /*****************************************************************************
49  * Begin ADPCM compression handler...                                       */
50
51 /*
52  * ADPCM decoding routines taken with permission from SDL_sound
53  * Copyright (C) 2001  Ryan C. Gordon.
54  */
55
56 #define FIXED_POINT_COEF_BASE      256
57 #define FIXED_POINT_ADAPTION_BASE  256
58 #define SMALLEST_ADPCM_DELTA       16
59
60
61 // utility functions
62 static int read_ushort(SDL_RWops *rw, ushort *i)
63 {
64         int rc = SDL_RWread(rw, i, sizeof(ushort), 1);
65         IF_ERR(rc != 1, 0);
66         *i = INTEL_SHORT(*i);
67         return 1;
68 }
69
70 static int read_word(SDL_RWops *rw, WORD *i)
71 {
72         int rc = SDL_RWread(rw, i, sizeof(WORD), 1);
73         IF_ERR(rc != 1, 0);
74         return 1;
75 }
76
77 // same as read_word() but swapped
78 static int read_word_s(SDL_RWops *rw, WORD *i)
79 {
80         int rc = SDL_RWread(rw, i, sizeof(WORD), 1);
81         IF_ERR(rc != 1, 0);
82         *i = INTEL_SHORT(*i);
83         return 1;
84 }
85
86 static int read_short(SDL_RWops *rw, short *i)
87 {
88         int rc = SDL_RWread(rw, i, sizeof(short), 1);
89         IF_ERR(rc != 1, 0);
90         *i = INTEL_SHORT(*i);
91         return 1;
92 }
93
94 static int read_dword(SDL_RWops *rw, DWORD *i)
95 {
96         int rc = SDL_RWread(rw, i, sizeof(DWORD), 1);
97         IF_ERR(rc != 1, 0);
98         return 1;
99 }
100
101 static int read_ubyte(SDL_RWops *rw, ubyte *i)
102 {
103         int rc = SDL_RWread(rw, i, sizeof(ubyte), 1);
104         IF_ERR(rc != 1, 0);
105         return 1;
106 }
107
108 // decoding functions
109 static int read_adpcm_block_headers(SDL_RWops *rw, adpcm_fmt_t *fmt)
110 {
111         int i;
112         int max = fmt->adpcm.wav.nChannels;
113
114         if (fmt->bytes_remaining < fmt->adpcm.wav.nBlockAlign) {
115                 return 0;
116         }
117
118         fmt->bytes_remaining -= fmt->adpcm.wav.nBlockAlign;
119         fmt->bytes_processed += fmt->adpcm.wav.nBlockAlign;
120
121         for (i = 0; i < max; i++)
122                 IF_ERR(!read_ubyte(rw, &fmt->header[i].bPredictor), 0);
123
124         for (i = 0; i < max; i++)
125                 IF_ERR(!read_ushort(rw, &fmt->header[i].iDelta), 0);
126
127         for (i = 0; i < max; i++)
128                 IF_ERR(!read_short(rw, &fmt->header[i].iSamp1), 0);
129
130         for (i = 0; i < max; i++)
131                 IF_ERR(!read_short(rw, &fmt->header[i].iSamp2), 0);
132         
133         fmt->samples_left_in_block = fmt->adpcm.wSamplesPerBlock;
134         fmt->nibble_state = 0;
135
136         return 1;
137 }
138
139 static void do_adpcm_nibble(ubyte nib, ADPCMBLOCKHEADER *header, int lPredSamp)
140 {
141         static const short max_audioval = ((1<<(16-1))-1);
142         static const short min_audioval = -(1<<(16-1));
143         static const ushort AdaptionTable[] = {
144                 230, 230, 230, 230, 307, 409, 512, 614,
145                 768, 614, 512, 409, 307, 230, 230, 230
146         };
147
148         int lNewSamp;
149         ushort delta;
150
151         if (nib & 0x08) {
152                 lNewSamp = lPredSamp + (header->iDelta * (nib - 0x10));
153         } else {
154                 lNewSamp = lPredSamp + (header->iDelta * nib);
155         }
156
157         // clamp value...
158         if (lNewSamp < min_audioval) {
159                 lNewSamp = min_audioval;
160         } else if (lNewSamp > max_audioval) {
161                 lNewSamp = max_audioval;
162         }
163
164         delta = (header->iDelta * AdaptionTable[nib]) / FIXED_POINT_ADAPTION_BASE;
165
166         if (delta < SMALLEST_ADPCM_DELTA)
167                 delta = SMALLEST_ADPCM_DELTA;
168
169         header->iDelta = delta;
170         header->iSamp2 = header->iSamp1;
171         header->iSamp1 = lNewSamp;
172 }
173
174 static int decode_adpcm_sample_frame(SDL_RWops *rw, adpcm_fmt_t *fmt)
175 {
176         int i;
177         int max = fmt->adpcm.wav.nChannels;
178         ubyte nib = fmt->nibble;
179         short iCoef1, iCoef2;
180         int lPredSamp;
181
182         for (i = 0; i < max; i++) {
183                 iCoef1 = fmt->adpcm.aCoef[fmt->header[i].bPredictor].iCoef1;
184                 iCoef2 = fmt->adpcm.aCoef[fmt->header[i].bPredictor].iCoef2;
185                 lPredSamp = ((fmt->header[i].iSamp1 * iCoef1) + (fmt->header[i].iSamp2 * iCoef2)) / FIXED_POINT_COEF_BASE;
186
187                 if (fmt->nibble_state == 0) {
188                         IF_ERR(!read_ubyte(rw, &nib), 0);
189                         fmt->nibble_state = 1;
190                         do_adpcm_nibble(nib >> 4, &fmt->header[i], lPredSamp);
191                 } else {
192                         fmt->nibble_state = 0;
193                         do_adpcm_nibble(nib & 0x0F, &fmt->header[i], lPredSamp);
194                 }
195         }
196
197         fmt->nibble = nib;
198
199         return 1;
200 }
201
202 static void put_adpcm_sample_frame1(ubyte *_buf, adpcm_fmt_t *fmt)
203 {
204         short *buf = (short *)_buf;
205         int i;
206         
207         for (i = 0; i < fmt->adpcm.wav.nChannels; i++)
208                 *buf++ = fmt->header[i].iSamp1;
209 }
210
211 static void put_adpcm_sample_frame2(ubyte *_buf, adpcm_fmt_t *fmt)
212 {
213         short *buf = (short *)_buf;
214         int i;
215
216         for (i = 0; i < fmt->adpcm.wav.nChannels; i++)
217                 *buf++ = fmt->header[i].iSamp2;
218 }
219
220 static uint read_sample_fmt_adpcm(ubyte *data, SDL_RWops *rw, adpcm_fmt_t *fmt)
221 {
222         uint bw = 0;
223
224         while (bw < fmt->buffer_size) {
225                 // write ongoing sample frame before reading more data...
226                 switch (fmt->samples_left_in_block) {
227                         case 0:  // need to read a new block...
228                                 if (!read_adpcm_block_headers(rw, fmt))
229                                         return(bw);             // EOF
230
231                                 // only write first sample frame for now.
232                                 put_adpcm_sample_frame2(data + bw, fmt);
233                                 fmt->samples_left_in_block--;
234                                 bw += fmt->sample_frame_size;
235                                 break;
236
237                         case 1:  // output last sample frame of block...
238                                 put_adpcm_sample_frame1(data + bw, fmt);
239                                 fmt->samples_left_in_block--;
240                                 bw += fmt->sample_frame_size;
241                                 break;
242
243                         default: // output latest sample frame and read a new one...
244                                 put_adpcm_sample_frame1(data + bw, fmt);
245                                 fmt->samples_left_in_block--;
246                                 bw += fmt->sample_frame_size;
247
248                                 if (!decode_adpcm_sample_frame(rw, fmt))
249                                         return(bw);
250                 }
251         }
252
253         return(bw);
254 }
255
256 /* End ADPCM Compression Handler                                              *
257  *****************************************************************************/
258
259 static void adpcm_memory_free(adpcm_fmt_t *fmt)
260 {
261         if (fmt->adpcm.aCoef != NULL) {
262                 free(fmt->adpcm.aCoef);
263                 fmt->adpcm.aCoef = NULL;
264         }
265         
266         if (fmt->header != NULL) {
267                 free(fmt->header);
268                 fmt->header = NULL;
269         }
270         
271         if (fmt != NULL) {
272                 free(fmt);
273                 fmt = NULL;
274         }
275 }
276
277 // =============================================================================
278 // ACM_convert_ADPCM_to_PCM()
279 //
280 // Convert an ADPCM wave file to a PCM wave file using the Audio Compression Manager
281 //
282 // parameters:  *pwfxSrc   => address of WAVEFORMATEX structure describing the source wave
283 //                              *src       => pointer to raw source wave data
284 //                              src_len    => num bytes of source wave data
285 //                              **dest     => pointer to pointer to dest buffer for wave data
286 //                                                        (mem is allocated in this function if *dest is NULL)
287 //                              max_dest_bytes   => Maximum memory allocated to dest
288 //                              *dest_len        => returns num bytes of wave data in converted form (OUTPUT PARAMETER)
289 //                              *src_bytes_used  =>     returns num bytes of src actually used in the conversion
290 //                              dest_bps         => bits per sample that data should be uncompressed to
291 //
292 // returns:        0 => success
293 //                         -1 => could not convert wav file
294 //
295 //
296 // NOTES:
297 // 1. Storage for the decompressed audio will be allocated in this function if *dest in NULL.
298 //    The caller is responsible for freeing this memory later.
299 //
300 int ACM_convert_ADPCM_to_PCM(WAVEFORMATEX *pwfxSrc, ubyte *src, int src_len, ubyte **dest, int max_dest_bytes, int *dest_len, unsigned int *src_bytes_used, unsigned short dest_bps)
301 {
302         Assert( pwfxSrc != NULL );
303         Assert( pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM );
304         Assert( src != NULL );
305         Assert( src_len > 0 );
306         Assert( dest_len != NULL );
307
308         SDL_RWops *hdr = SDL_RWFromMem(pwfxSrc, sizeof(WAVEFORMATEX) + pwfxSrc->cbSize);
309         SDL_RWops *rw = SDL_RWFromMem(src, src_len);
310         uint rc;
311         uint new_size = 0;
312
313         if ( ACM_inited == 0 ) {
314                 rc = ACM_init();
315                 if ( rc != 0 )
316                         return -1;
317         }
318
319         // estimate size of uncompressed data
320         new_size = src_len * ( (dest_bps * pwfxSrc->nChannels * pwfxSrc->wBitsPerSample) / 8 );
321
322         // DO NOT free() here, *estimated size*
323         if ( *dest == NULL ) {
324                 *dest = (ubyte *)malloc(new_size);
325                 
326                 IF_ERR(*dest == NULL, -1);
327                 
328                 memset(*dest, 0x80, new_size);  // silence (for 8 bits/sec)
329         }
330
331         adpcm_fmt_t *fmt = (adpcm_fmt_t *)malloc(sizeof(adpcm_fmt_t));
332         IF_ERR(fmt == NULL, -1);
333         memset(fmt, '\0', sizeof(adpcm_fmt_t));
334
335         // wav header info (WAVEFORMATEX)
336         IF_ERR(!read_word(hdr, &fmt->adpcm.wav.wFormatTag), -1);
337         IF_ERR(!read_word(hdr, &fmt->adpcm.wav.nChannels), -1);
338         IF_ERR(!read_dword(hdr, &fmt->adpcm.wav.nSamplesPerSec), -1);
339         IF_ERR(!read_dword(hdr, &fmt->adpcm.wav.nAvgBytesPerSec), -1);
340         IF_ERR(!read_word(hdr, &fmt->adpcm.wav.nBlockAlign), -1);
341         IF_ERR(!read_word(hdr, &fmt->adpcm.wav.wBitsPerSample), -1);
342         IF_ERR(!read_word(hdr, &fmt->adpcm.wav.cbSize), -1);
343         // adpcm specific header info
344         IF_ERR(!read_word_s(hdr, &fmt->adpcm.wSamplesPerBlock), -1);
345         IF_ERR(!read_word_s(hdr, &fmt->adpcm.wNumCoef), -1);
346
347         // allocate memory for COEF struct and fill it
348         fmt->adpcm.aCoef = (ADPCMCOEFSET *)malloc(sizeof(ADPCMCOEFSET) * fmt->adpcm.wNumCoef);
349         IF_ERR(fmt->adpcm.aCoef == NULL, -1);
350
351         for (int i=0; i<fmt->adpcm.wNumCoef; i++) {
352                 IF_ERR(!read_short(hdr, &fmt->adpcm.aCoef[i].iCoef1), -1);
353                 IF_ERR(!read_short(hdr, &fmt->adpcm.aCoef[i].iCoef2), -1);
354         }
355
356         // allocate memory for the ADPCM block header that's to be filled later
357         fmt->header = (ADPCMBLOCKHEADER *)malloc(sizeof(ADPCMBLOCKHEADER) * fmt->adpcm.wav.nChannels);
358         IF_ERR(fmt->header == NULL, -1);
359
360         // buffer to estimated size since we have to process the whole thing at once
361         fmt->buffer_size = new_size;
362         fmt->bytes_remaining = src_len;
363         fmt->bytes_processed = 0;
364
365         // sanity check, should always be 4
366         if (fmt->adpcm.wav.wBitsPerSample != 4) {
367                 adpcm_memory_free(fmt);
368                 return -1;
369         }
370
371         fmt->sample_frame_size = 2;
372
373         if ( !max_dest_bytes ) {
374                 max_dest_bytes = new_size;
375         }
376
377         // convert to PCM
378         rc = read_sample_fmt_adpcm(*dest, rw, fmt);
379
380         // send back actual sizes
381         *dest_len = rc;
382         *src_bytes_used = fmt->bytes_processed;
383
384         // cleanup
385         adpcm_memory_free(fmt);
386
387         return 0;
388 }
389
390 int ACM_stream_open(WAVEFORMATEX *pwfxSrc, WAVEFORMATEX *pwfxDest, void **stream, int dest_bps)
391 {
392         return -1;
393 }
394
395 int ACM_stream_close(void *stream)
396 {
397         return -1;
398 }
399
400 int ACM_query_source_size(void *stream, int dest_len)
401 {
402         return -1;
403 }
404
405 int ACM_query_dest_size(void *stream, int src_len)
406 {
407         return -1;
408 }
409
410 int ACM_convert(void *stream, ubyte *src, int src_len, ubyte *dest, int max_dest_bytes, unsigned int *dest_len, unsigned int *src_bytes_used)
411 {
412         return -1;
413 }
414
415 // ACM_init() - decoding should always work
416 int ACM_init()
417 {
418         if ( ACM_inited == 1 )
419                 return 0;
420
421         ACM_inited = 1;
422
423         return 0;
424 }
425
426 // close out
427 void ACM_close()
428 {
429         if ( ACM_inited == 0 )
430                 return;
431
432         ACM_inited = 0;
433 }
434
435 // Query if the ACM system is initialized
436 int ACM_is_inited()
437 {
438         return ACM_inited;
439 }