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