]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/acm.cpp
get rid of some platform specific stuff
[taylor/freespace2.git] / src / sound / acm.cpp
1 /***********************************************************
2  * Portions of this file are Copyright (c) Ryan C. Gordon
3  ***********************************************************/
4  
5 /*
6  * $Logfile: /Freespace2/code/Sound/ACM.cpp $
7  * $Revision$
8  * $Date$
9  * $Author$
10  *
11  * ADPCM decoder
12  *
13  * $Log$
14  * Revision 1.6  2005/03/29 02:18:47  taylor
15  * Various 64-bit platform fixes
16  * Fix compiler errors with MAKE_FS1 and fix gr_set_bitmap() too
17  * Make sure that turrets can fire at asteroids for FS1 (needed for a couple missions)
18  * Streaming audio support (big thanks to Pierre Willenbrock!!)
19  * Removed dependance on strings.tbl for FS1 since we don't actually need it now
20  *
21  *
22  * $NoKeywords: $
23  */
24  
25  
26 #include "pstypes.h"
27 #include "acm.h"
28 #include "oal.h"
29
30
31 typedef struct adpcmcoef_tag{
32         short iCoef1;
33         short iCoef2;
34 } ADPCMCOEFSET;
35
36 typedef struct adpcmblockheader_tag {
37         ubyte bPredictor;
38         ushort iDelta;
39         short iSamp1;
40         short iSamp2;
41 } ADPCMBLOCKHEADER;
42
43 typedef struct adpcmwaveformat_tag {
44         WAVE_chunk wav;
45         ushort wSamplesPerBlock;
46         ushort wNumCoef;
47         ADPCMCOEFSET *aCoef;
48 } ADPCMWAVEFORMAT;
49
50 typedef struct ADPCM_FMT_T {
51         ADPCMWAVEFORMAT adpcm;
52         ADPCMBLOCKHEADER *header;
53
54         int bytes_remaining;
55         uint bytes_processed;
56         uint buffer_size;
57         uint sample_frame_size;
58         uint samples_left_in_block;
59         int nibble_state;
60         ubyte nibble;
61 } adpcm_fmt_t;
62
63 typedef struct acm_stream_t {
64         adpcm_fmt_t *fmt;
65         ushort dest_bps;
66         ushort src_bps;
67 } acm_stream_t;
68
69 // similar to BIAL_IF_MACRO in SDL_sound
70 #define IF_ERR(a, b) if (a) { printf("IF_ERR-ACM, function: %s, line %d...\n", __FUNCTION__, __LINE__); return b; }
71
72
73 /*****************************************************************************
74  * Begin ADPCM compression handler...                                       */
75
76 /*
77  * ADPCM decoding routines taken with permission from SDL_sound
78  * Copyright (C) 2001  Ryan C. Gordon.
79  */
80
81 #define FIXED_POINT_COEF_BASE      256
82 #define FIXED_POINT_ADAPTION_BASE  256
83 #define SMALLEST_ADPCM_DELTA       16
84
85
86 // utility functions
87 static int read_ushort(SDL_RWops *rw, ushort *i)
88 {
89         int rc = SDL_RWread(rw, i, sizeof(ushort), 1);
90         IF_ERR(rc != 1, 0);
91         *i = INTEL_SHORT(*i);
92         return 1;
93 }
94
95 static int read_short(SDL_RWops *rw, short *i)
96 {
97         int rc = SDL_RWread(rw, i, sizeof(short), 1);
98         IF_ERR(rc != 1, 0);
99         *i = INTEL_SHORT(*i);
100         return 1;
101 }
102
103 static int read_ubyte(SDL_RWops *rw, ubyte *i)
104 {
105         int rc = SDL_RWread(rw, i, sizeof(ubyte), 1);
106         IF_ERR(rc != 1, 0);
107         return 1;
108 }
109
110 // decoding functions
111 static int read_adpcm_block_headers(SDL_RWops *rw, adpcm_fmt_t *fmt)
112 {
113         int i;
114         int max = fmt->adpcm.wav.num_channels;
115
116         if (fmt->bytes_remaining < fmt->adpcm.wav.block_align) {
117                 return 0;
118         }
119
120         fmt->bytes_remaining -= fmt->adpcm.wav.block_align;
121         fmt->bytes_processed += fmt->adpcm.wav.block_align;
122
123         for (i = 0; i < max; i++)
124                 IF_ERR(!read_ubyte(rw, &fmt->header[i].bPredictor), 0);
125
126         for (i = 0; i < max; i++)
127                 IF_ERR(!read_ushort(rw, &fmt->header[i].iDelta), 0);
128
129         for (i = 0; i < max; i++)
130                 IF_ERR(!read_short(rw, &fmt->header[i].iSamp1), 0);
131
132         for (i = 0; i < max; i++)
133                 IF_ERR(!read_short(rw, &fmt->header[i].iSamp2), 0);
134         
135         fmt->samples_left_in_block = fmt->adpcm.wSamplesPerBlock;
136         fmt->nibble_state = 0;
137
138         return 1;
139 }
140
141 static void do_adpcm_nibble(ubyte nib, ADPCMBLOCKHEADER *header, int lPredSamp)
142 {
143         static const short max_audioval = ((1<<(16-1))-1);
144         static const short min_audioval = -(1<<(16-1));
145         static const ushort AdaptionTable[] = {
146                 230, 230, 230, 230, 307, 409, 512, 614,
147                 768, 614, 512, 409, 307, 230, 230, 230
148         };
149
150         int lNewSamp;
151         ushort delta;
152
153         if (nib & 0x08) {
154                 lNewSamp = lPredSamp + (header->iDelta * (nib - 0x10));
155         } else {
156                 lNewSamp = lPredSamp + (header->iDelta * nib);
157         }
158
159         // clamp value...
160         if (lNewSamp < min_audioval) {
161                 lNewSamp = min_audioval;
162         } else if (lNewSamp > max_audioval) {
163                 lNewSamp = max_audioval;
164         }
165
166         delta = (header->iDelta * AdaptionTable[nib]) / FIXED_POINT_ADAPTION_BASE;
167
168         if (delta < SMALLEST_ADPCM_DELTA)
169                 delta = SMALLEST_ADPCM_DELTA;
170
171         header->iDelta = delta;
172         header->iSamp2 = header->iSamp1;
173         header->iSamp1 = lNewSamp;
174 }
175
176 static int decode_adpcm_sample_frame(SDL_RWops *rw, adpcm_fmt_t *fmt)
177 {
178         int i;
179         int max = fmt->adpcm.wav.num_channels;
180         ubyte nib = fmt->nibble;
181         short iCoef1, iCoef2;
182         int lPredSamp;
183
184         for (i = 0; i < max; i++) {
185                 iCoef1 = fmt->adpcm.aCoef[fmt->header[i].bPredictor].iCoef1;
186                 iCoef2 = fmt->adpcm.aCoef[fmt->header[i].bPredictor].iCoef2;
187                 lPredSamp = ((fmt->header[i].iSamp1 * iCoef1) + (fmt->header[i].iSamp2 * iCoef2)) / FIXED_POINT_COEF_BASE;
188
189                 if (fmt->nibble_state == 0) {
190                         IF_ERR(!read_ubyte(rw, &nib), 0);
191                         fmt->nibble_state = 1;
192                         do_adpcm_nibble(nib >> 4, &fmt->header[i], lPredSamp);
193                 } else {
194                         fmt->nibble_state = 0;
195                         do_adpcm_nibble(nib & 0x0F, &fmt->header[i], lPredSamp);
196                 }
197         }
198
199         fmt->nibble = nib;
200
201         return 1;
202 }
203
204 static void put_adpcm_sample_frame1(ubyte *_buf, adpcm_fmt_t *fmt)
205 {
206         short *buf = (short *)_buf;
207         int i;
208         
209         for (i = 0; i < fmt->adpcm.wav.num_channels; i++)
210                 *buf++ = fmt->header[i].iSamp1;
211 }
212
213 static void put_adpcm_sample_frame2(ubyte *_buf, adpcm_fmt_t *fmt)
214 {
215         short *buf = (short *)_buf;
216         int i;
217
218         for (i = 0; i < fmt->adpcm.wav.num_channels; i++)
219                 *buf++ = fmt->header[i].iSamp2;
220 }
221
222 static uint read_sample_fmt_adpcm(ubyte *data, SDL_RWops *rw, adpcm_fmt_t *fmt)
223 {
224         uint bw = 0;
225
226         while (bw < fmt->buffer_size) {
227                 // write ongoing sample frame before reading more data...
228                 switch (fmt->samples_left_in_block) {
229                         case 0:  // need to read a new block...
230                                 if (!read_adpcm_block_headers(rw, fmt))
231                                         return(bw);             // EOF
232
233                                 // only write first sample frame for now.
234                                 put_adpcm_sample_frame2(data + bw, fmt);
235                                 fmt->samples_left_in_block--;
236                                 bw += fmt->sample_frame_size;
237                                 break;
238
239                         case 1:  // output last sample frame of block...
240                                 put_adpcm_sample_frame1(data + bw, fmt);
241                                 fmt->samples_left_in_block--;
242                                 bw += fmt->sample_frame_size;
243                                 break;
244
245                         default: // output latest sample frame and read a new one...
246                                 put_adpcm_sample_frame1(data + bw, fmt);
247                                 fmt->samples_left_in_block--;
248                                 bw += fmt->sample_frame_size;
249
250                                 if (!decode_adpcm_sample_frame(rw, fmt))
251                                         return(bw);
252                 }
253         }
254
255         return(bw);
256 }
257
258 /* End ADPCM Compression Handler                                              *
259  *****************************************************************************/
260
261 static void adpcm_memory_free(adpcm_fmt_t *fmt)
262 {
263         SDL_assert( fmt != NULL );
264
265         if (fmt->adpcm.aCoef != NULL) {
266                 free(fmt->adpcm.aCoef);
267                 fmt->adpcm.aCoef = NULL;
268         }
269         
270         if (fmt->header != NULL) {
271                 free(fmt->header);
272                 fmt->header = NULL;
273         }
274
275         free(fmt);
276 }
277
278 // =============================================================================
279 // ACM_convert_ADPCM_to_PCM()
280 //
281 // Convert an ADPCM wave file to a PCM wave file using the Audio Compression Manager
282 //
283 // parameters:  *pwfxSrc   => address of WAVE_chunk structure describing the source wave
284 //                              *src       => pointer to raw source wave data
285 //                              src_len    => num bytes of source wave data
286 //                              **dest     => pointer to pointer to dest buffer for wave data
287 //                                                        (mem is allocated in this function if *dest is NULL)
288 //                              max_dest_bytes   => Maximum memory allocated to dest
289 //                              *dest_len        => returns num bytes of wave data in converted form (OUTPUT PARAMETER)
290 //                              *src_bytes_used  =>     returns num bytes of src actually used in the conversion
291 //                              dest_bps         => bits per sample that data should be uncompressed to
292 //
293 // returns:        0 => success
294 //                         -1 => could not convert wav file
295 //
296 //
297 // NOTES:
298 // 1. Storage for the decompressed audio will be allocated in this function if *dest in NULL.
299 //    The caller is responsible for freeing this memory later.
300 //
301 int ACM_convert_ADPCM_to_PCM(WAVE_chunk *pwfxSrc, ubyte *src, int src_len, ubyte **dest, int max_dest_bytes, int *dest_len, unsigned int *src_bytes_used, unsigned short dest_bps)
302 {
303         SDL_assert( pwfxSrc != NULL );
304         SDL_assert( pwfxSrc->code == WAVE_FORMAT_ADPCM );
305         SDL_assert( pwfxSrc->extra_data != NULL );
306         SDL_assert( src != NULL );
307         SDL_assert( src_len > 0 );
308         SDL_assert( dest_len != NULL );
309
310         uint rc;
311         uint new_size = 0;
312
313         SDL_RWops *hdr = SDL_RWFromMem(pwfxSrc->extra_data, pwfxSrc->extra_size);
314         SDL_RWops *rw = SDL_RWFromMem(src, src_len);
315
316         adpcm_fmt_t *fmt = NULL;
317
318         // estimate size of uncompressed data
319         // uncompressed data has: channels=pfwxScr->nChannels, bitPerSample=destbits
320         // compressed data has:   channels=pfwxScr->nChannels, bitPerSample=pwfxSrc->wBitsPerSample
321         new_size = ( src_len * dest_bps ) / pwfxSrc->bits_per_sample;
322         new_size *= 2;//buffer must be large enough for all data
323
324         // DO NOT free() here, *estimated size*
325         if ( *dest == NULL ) {
326                 *dest = (ubyte *)malloc(new_size);
327
328                 if ( (*dest == NULL) ) {
329                         goto Fail;
330                 }
331
332 //              memset(*dest, 0x80, new_size);  // silence (for 8 bits/sample)
333                 memset(*dest, 0x00, new_size);  // silence (for 16 bits/sample)
334         }
335
336         fmt = (adpcm_fmt_t *)malloc(sizeof(adpcm_fmt_t));
337
338         if (fmt == NULL) {
339                 goto Fail;
340         }
341
342         memset(fmt, '\0', sizeof(adpcm_fmt_t));
343
344         // wav header info (WAVE_chunk)
345         fmt->adpcm.wav.code = pwfxSrc->code;
346         fmt->adpcm.wav.num_channels = pwfxSrc->num_channels;
347         fmt->adpcm.wav.sample_rate = pwfxSrc->sample_rate;
348         fmt->adpcm.wav.bytes_per_second = pwfxSrc->bytes_per_second;
349         fmt->adpcm.wav.block_align = pwfxSrc->block_align;
350         fmt->adpcm.wav.bits_per_sample = pwfxSrc->bits_per_sample;
351
352         // sanity check, should always be 4
353         if (fmt->adpcm.wav.bits_per_sample != 4) {
354                 goto Fail;
355         }
356
357         // adpcm specific header info
358         if ( !read_ushort(hdr, &fmt->adpcm.wSamplesPerBlock) ) {
359                 goto Fail;
360         }
361
362         if ( !read_ushort(hdr, &fmt->adpcm.wNumCoef) ) {
363                 goto Fail;
364         }
365
366         // allocate memory for COEF struct and fill it
367         fmt->adpcm.aCoef = (ADPCMCOEFSET *)malloc(sizeof(ADPCMCOEFSET) * fmt->adpcm.wNumCoef);
368
369         if (fmt->adpcm.aCoef == NULL) {
370                 goto Fail;
371         }
372
373         for (int i=0; i<fmt->adpcm.wNumCoef; i++) {
374                 if ( !read_short(hdr, &fmt->adpcm.aCoef[i].iCoef1) ) {
375                         goto Fail;
376                 }
377
378                 if ( !read_short(hdr, &fmt->adpcm.aCoef[i].iCoef2) ) {
379                         goto Fail;
380                 }
381         }
382
383         // allocate memory for the ADPCM block header that's to be filled later
384         fmt->header = (ADPCMBLOCKHEADER *)malloc(sizeof(ADPCMBLOCKHEADER) * fmt->adpcm.wav.num_channels);
385
386         if (fmt->header == NULL) {
387                 goto Fail;
388         }
389
390         // buffer to estimated size since we have to process the whole thing at once
391         fmt->buffer_size = new_size;
392         fmt->bytes_remaining = src_len;
393         fmt->bytes_processed = 0;
394
395         fmt->sample_frame_size = dest_bps/8*pwfxSrc->num_channels;
396
397         if ( !max_dest_bytes ) {
398                 max_dest_bytes = new_size;
399         }
400
401         // convert to PCM
402         rc = read_sample_fmt_adpcm(*dest, rw, fmt);
403
404         if (rc == 0) {
405                 goto Fail;
406         }
407
408         // send back actual sizes
409         *dest_len = rc;
410         *src_bytes_used = fmt->bytes_processed;
411
412         // cleanup
413         adpcm_memory_free(fmt);
414         SDL_RWclose(hdr);
415         SDL_RWclose(rw);
416
417         return 0;
418
419 Fail:
420         if (fmt) {
421                 adpcm_memory_free(fmt);
422         }
423
424         SDL_RWclose(hdr);
425         SDL_RWclose(rw);
426
427         return -1;
428 }
429
430 int ACM_stream_open(WAVE_chunk *pwfxSrc, WAVE_chunk *pwfxDest, void **stream, int dest_bps)
431 {
432         SDL_assert( pwfxSrc != NULL );
433         SDL_assert( pwfxSrc->code == WAVE_FORMAT_ADPCM );
434         SDL_assert( pwfxSrc->extra_data != NULL );
435         SDL_assert( stream != NULL );
436
437         SDL_RWops *hdr = SDL_RWFromMem(pwfxSrc->extra_data, pwfxSrc->extra_size);
438         acm_stream_t *str = NULL;
439
440         adpcm_fmt_t *fmt = (adpcm_fmt_t *)malloc(sizeof(adpcm_fmt_t));
441
442         if (fmt == NULL) {
443                 goto Fail;
444         }
445
446         memset(fmt, '\0', sizeof(adpcm_fmt_t));
447
448         // wav header info (WAVE_chunk)
449         fmt->adpcm.wav.code = pwfxSrc->code;
450         fmt->adpcm.wav.num_channels = pwfxSrc->num_channels;
451         fmt->adpcm.wav.sample_rate = pwfxSrc->sample_rate;
452         fmt->adpcm.wav.bytes_per_second = pwfxSrc->bytes_per_second;
453         fmt->adpcm.wav.block_align = pwfxSrc->block_align;
454         fmt->adpcm.wav.bits_per_sample = pwfxSrc->bits_per_sample;
455
456         // sanity check, should always be 4
457         if (fmt->adpcm.wav.bits_per_sample != 4) {
458                 goto Fail;
459         }
460
461         // adpcm specific header info
462         if ( !read_ushort(hdr, &fmt->adpcm.wSamplesPerBlock) ) {
463                 goto Fail;
464         }
465
466         if ( !read_ushort(hdr, &fmt->adpcm.wNumCoef) ) {
467                 goto Fail;
468         }
469
470         // allocate memory for COEF struct and fill it
471         fmt->adpcm.aCoef = (ADPCMCOEFSET *)malloc(sizeof(ADPCMCOEFSET) * fmt->adpcm.wNumCoef);
472
473         if (fmt->adpcm.aCoef == NULL) {
474                 goto Fail;
475         }
476
477         for (int i=0; i<fmt->adpcm.wNumCoef; i++) {
478                 if ( !read_short(hdr, &fmt->adpcm.aCoef[i].iCoef1) ) {
479                         goto Fail;
480                 }
481
482                 if ( !read_short(hdr, &fmt->adpcm.aCoef[i].iCoef2) ) {
483                         goto Fail;
484                 }
485         }
486
487         // allocate memory for the ADPCM block header that's to be filled later
488         fmt->header = (ADPCMBLOCKHEADER *)malloc(sizeof(ADPCMBLOCKHEADER) * fmt->adpcm.wav.num_channels);
489
490         if (fmt->header == NULL) {
491                 goto Fail;
492         }
493
494         fmt->sample_frame_size = dest_bps/8*pwfxSrc->num_channels;
495         
496         str = (acm_stream_t *)malloc(sizeof(acm_stream_t));
497
498         if (str == NULL) {
499                 goto Fail;
500         }
501
502         str->fmt = fmt;
503         str->dest_bps = dest_bps;
504         str->src_bps = pwfxSrc->bits_per_sample;
505         *stream = str;
506
507         SDL_RWclose(hdr);
508
509         return 0;
510
511 Fail:
512         if (fmt) {
513                 adpcm_memory_free(fmt);
514         }
515
516         SDL_RWclose(hdr);
517
518         return -1;
519 }
520
521 int ACM_stream_close(void *stream)
522 {
523         SDL_assert(stream != NULL);
524
525         acm_stream_t *str = (acm_stream_t *)stream;
526
527         adpcm_memory_free(str->fmt);
528         free(str);
529
530         return 0;
531 }
532
533 /*
534  * How many bytes are needed to get approximately dest_len bytes output?
535  */
536 int ACM_query_source_size(void *stream, int dest_len)
537 {
538         SDL_assert(stream != NULL);
539
540         acm_stream_t *str = (acm_stream_t *)stream;
541
542         // estimate size of compressed data
543         // uncompressed data has: channels=pfwxScr->nChannels, bitPerSample=destbits
544         // compressed data has:   channels=pfwxScr->nChannels, bitPerSample=pwfxSrc->wBitsPerSample
545         return (dest_len * str->src_bps) / str->dest_bps;
546 }
547
548 /*
549  * How many output bytes would approximately be produced by src_len bytes input?
550  */
551 int ACM_query_dest_size(void *stream, int src_len)
552 {
553         SDL_assert(stream != NULL);
554
555         acm_stream_t *str = (acm_stream_t *)stream;
556
557         // estimate size of uncompressed data
558         // uncompressed data has: channels=pfwxScr->nChannels, bitPerSample=destbits
559         // compressed data has:   channels=pfwxScr->nChannels, bitPerSample=pwfxSrc->wBitsPerSample
560         return ( src_len * str->dest_bps ) / str->src_bps;
561 }
562
563 /*
564  * We are allowed to use fewer bytes than delivered to us
565  */
566 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)
567 {
568         SDL_assert(stream != NULL);
569         SDL_assert( src != NULL );
570         SDL_assert( src_len > 0 );
571         SDL_assert( dest_len != NULL );
572
573         acm_stream_t *str = (acm_stream_t *)stream;
574         uint rc;
575
576         SDL_RWops *rw = SDL_RWFromMem(src, src_len);
577
578         // buffer to estimated size since we have to process the whole thing at once
579         str->fmt->buffer_size = max_dest_bytes;
580         str->fmt->bytes_remaining = src_len;
581         str->fmt->bytes_processed = 0;
582
583         // convert to PCM
584         rc = read_sample_fmt_adpcm(dest, rw, str->fmt);
585
586         // send back actual sizes
587         *dest_len = rc;
588         *src_bytes_used = str->fmt->bytes_processed;
589
590         SDL_RWclose(rw);
591
592         return 0;
593 }