Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2005 Dave Chapman |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
| 21 | |
Thom Johansen | c91e0bb | 2005-10-13 11:32:52 +0000 | [diff] [blame] | 22 | #include "codeclib.h" |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 23 | #include "inttypes.h" |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 24 | |
Jens Arnold | b8749fd | 2006-01-18 00:05:14 +0000 | [diff] [blame] | 25 | CODEC_HEADER |
| 26 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 27 | /* Macro that sign extends an unsigned byte */ |
| 28 | #define SE(x) ((int32_t)((int8_t)(x))) |
| 29 | |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 30 | /* This codec support WAVE files with the following formats: |
| 31 | * - PCM, up to 32 bits, supporting 32 bits playback when useful. |
| 32 | * - ALAW and MULAW (16 bits compressed on 8 bits). |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 33 | * - DVI_ADPCM (16 bits compressed on 3 or 4 bits). |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 34 | * |
| 35 | * For a good documentation on WAVE files, see: |
| 36 | * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/WAVE/WAVE.html |
| 37 | * and |
| 38 | * http://www.sonicspot.com/guide/wavefiles.html |
| 39 | * |
| 40 | * For sample WAV files, see: |
| 41 | * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/WAVE/Samples.html |
| 42 | * |
| 43 | * The most common formats seem to be PCM, ADPCM, DVI_ADPCM, IEEE_FLOAT, |
| 44 | * ALAW and MULAW |
| 45 | */ |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 46 | |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 47 | /* These constants are from RFC 2361. */ |
| 48 | enum |
| 49 | { |
| 50 | WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Unknown Wave Format */ |
| 51 | WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */ |
| 52 | WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */ |
| 53 | WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */ |
| 54 | WAVE_FORMAT_VSELP = 0x0004, /* Compaq Computer's VSELP */ |
| 55 | WAVE_FORMAT_IBM_CVSD = 0x0005, /* IBM CVSD */ |
| 56 | WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */ |
| 57 | WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */ |
| 58 | WAVE_FORMAT_OKI_ADPCM = 0x0010, /* OKI ADPCM */ |
| 59 | WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */ |
| 60 | WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012, /* Videologic's MediaSpace ADPCM */ |
| 61 | WAVE_FORMAT_SIERRA_ADPCM = 0x0013, /* Sierra ADPCM */ |
| 62 | WAVE_FORMAT_G723_ADPCM = 0x0014, /* G.723 ADPCM */ |
| 63 | WAVE_FORMAT_DIGISTD = 0x0015, /* DSP Solutions' DIGISTD */ |
| 64 | WAVE_FORMAT_DIGIFIX = 0x0016, /* DSP Solutions' DIGIFIX */ |
| 65 | WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */ |
| 66 | WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018, /* MediaVision ADPCM */ |
| 67 | WAVE_FORMAT_CU_CODEC = 0x0019, /* HP CU */ |
| 68 | WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */ |
| 69 | WAVE_FORMAT_SONARC = 0x0021, /* Speech Compression's Sonarc */ |
| 70 | WAVE_FORMAT_DSP_TRUESPEECH = 0x0022, /* DSP Group's True Speech */ |
| 71 | WAVE_FORMAT_ECHOSC1 = 0x0023, /* Echo Speech's EchoSC1 */ |
| 72 | WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024, /* Audiofile AF36 */ |
| 73 | WAVE_FORMAT_APTX = 0x0025, /* APTX */ |
| 74 | WAVE_FORMAT_DOLBY_AC2 = 0x0030, /* Dolby AC2 */ |
| 75 | WAVE_FORMAT_GSM610 = 0x0031, /* GSM610 */ |
| 76 | WAVE_FORMAT_MSNAUDIO = 0x0032, /* MSNAudio */ |
| 77 | WAVE_FORMAT_ANTEX_ADPCME = 0x0033, /* Antex ADPCME */ |
| 78 | |
| 79 | WAVE_FORMAT_MPEG = 0x0050, /* MPEG */ |
| 80 | WAVE_FORMAT_MPEGLAYER3 = 0x0055, /* MPEG layer 3 */ |
| 81 | WAVE_FORMAT_LUCENT_G723 = 0x0059, /* Lucent G.723 */ |
| 82 | WAVE_FORMAT_G726_ADPCM = 0x0064, /* G.726 ADPCM */ |
| 83 | WAVE_FORMAT_G722_ADPCM = 0x0065, /* G.722 ADPCM */ |
| 84 | |
| 85 | IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */ |
| 86 | IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */ |
| 87 | IBM_FORMAT_ADPCM = 0x0103, |
| 88 | |
| 89 | WAVE_FORMAT_CREATIVE_ADPCM = 0x0200, |
| 90 | |
| 91 | WAVE_FORMAT_EXTENSIBLE = 0xFFFE |
| 92 | }; |
| 93 | |
| 94 | /* Maximum number of bytes to process in one iteration */ |
| 95 | /* for 44.1kHz stereo 16bits, this represents 0.023s ~= 1/50s */ |
| 96 | #define WAV_CHUNK_SIZE (1024*2) |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 97 | |
Dave Chapman | 62e9e89 | 2005-11-02 01:29:35 +0000 | [diff] [blame] | 98 | static const int16_t alaw2linear16[256] ICONST_ATTR = { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 99 | -5504, -5248, -6016, -5760, -4480, -4224, -4992, |
| 100 | -4736, -7552, -7296, -8064, -7808, -6528, -6272, |
| 101 | -7040, -6784, -2752, -2624, -3008, -2880, -2240, |
| 102 | -2112, -2496, -2368, -3776, -3648, -4032, -3904, |
| 103 | -3264, -3136, -3520, -3392, -22016, -20992, -24064, |
| 104 | -23040, -17920, -16896, -19968, -18944, -30208, -29184, |
| 105 | -32256, -31232, -26112, -25088, -28160, -27136, -11008, |
| 106 | -10496, -12032, -11520, -8960, -8448, -9984, -9472, |
| 107 | -15104, -14592, -16128, -15616, -13056, -12544, -14080, |
| 108 | -13568, -344, -328, -376, -360, -280, -264, |
| 109 | -312, -296, -472, -456, -504, -488, -408, |
| 110 | -392, -440, -424, -88, -72, -120, -104, |
| 111 | -24, -8, -56, -40, -216, -200, -248, |
| 112 | -232, -152, -136, -184, -168, -1376, -1312, |
| 113 | -1504, -1440, -1120, -1056, -1248, -1184, -1888, |
| 114 | -1824, -2016, -1952, -1632, -1568, -1760, -1696, |
| 115 | -688, -656, -752, -720, -560, -528, -624, |
| 116 | -592, -944, -912, -1008, -976, -816, -784, |
| 117 | -880, -848, 5504, 5248, 6016, 5760, 4480, |
| 118 | 4224, 4992, 4736, 7552, 7296, 8064, 7808, |
| 119 | 6528, 6272, 7040, 6784, 2752, 2624, 3008, |
| 120 | 2880, 2240, 2112, 2496, 2368, 3776, 3648, |
| 121 | 4032, 3904, 3264, 3136, 3520, 3392, 22016, |
| 122 | 20992, 24064, 23040, 17920, 16896, 19968, 18944, |
| 123 | 30208, 29184, 32256, 31232, 26112, 25088, 28160, |
| 124 | 27136, 11008, 10496, 12032, 11520, 8960, 8448, |
| 125 | 9984, 9472, 15104, 14592, 16128, 15616, 13056, |
| 126 | 12544, 14080, 13568, 344, 328, 376, 360, |
| 127 | 280, 264, 312, 296, 472, 456, 504, |
| 128 | 488, 408, 392, 440, 424, 88, 72, |
| 129 | 120, 104, 24, 8, 56, 40, 216, |
| 130 | 200, 248, 232, 152, 136, 184, 168, |
| 131 | 1376, 1312, 1504, 1440, 1120, 1056, 1248, |
| 132 | 1184, 1888, 1824, 2016, 1952, 1632, 1568, |
| 133 | 1760, 1696, 688, 656, 752, 720, 560, |
| 134 | 528, 624, 592, 944, 912, 1008, 976, |
| 135 | 816, 784, 880, 848 |
| 136 | }; |
| 137 | |
Dave Chapman | 62e9e89 | 2005-11-02 01:29:35 +0000 | [diff] [blame] | 138 | static const int16_t ulaw2linear16[256] ICONST_ATTR = { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 139 | -32124, -31100, -30076, -29052, -28028, -27004, -25980, |
| 140 | -24956, -23932, -22908, -21884, -20860, -19836, -18812, |
| 141 | -17788, -16764, -15996, -15484, -14972, -14460, -13948, |
| 142 | -13436, -12924, -12412, -11900, -11388, -10876, -10364, |
| 143 | -9852, -9340, -8828, -8316, -7932, -7676, -7420, |
| 144 | -7164, -6908, -6652, -6396, -6140, -5884, -5628, |
| 145 | -5372, -5116, -4860, -4604, -4348, -4092, -3900, |
| 146 | -3772, -3644, -3516, -3388, -3260, -3132, -3004, |
| 147 | -2876, -2748, -2620, -2492, -2364, -2236, -2108, |
| 148 | -1980, -1884, -1820, -1756, -1692, -1628, -1564, |
| 149 | -1500, -1436, -1372, -1308, -1244, -1180, -1116, |
| 150 | -1052, -988, -924, -876, -844, -812, -780, |
| 151 | -748, -716, -684, -652, -620, -588, -556, |
| 152 | -524, -492, -460, -428, -396, -372, -356, |
| 153 | -340, -324, -308, -292, -276, -260, -244, |
| 154 | -228, -212, -196, -180, -164, -148, -132, |
| 155 | -120, -112, -104, -96, -88, -80, -72, |
| 156 | -64, -56, -48, -40, -32, -24, -16, |
| 157 | -8, 0, 32124, 31100, 30076, 29052, 28028, |
| 158 | 27004, 25980, 24956, 23932, 22908, 21884, 20860, |
| 159 | 19836, 18812, 17788, 16764, 15996, 15484, 14972, |
| 160 | 14460, 13948, 13436, 12924, 12412, 11900, 11388, |
| 161 | 10876, 10364, 9852, 9340, 8828, 8316, 7932, |
| 162 | 7676, 7420, 7164, 6908, 6652, 6396, 6140, |
| 163 | 5884, 5628, 5372, 5116, 4860, 4604, 4348, |
| 164 | 4092, 3900, 3772, 3644, 3516, 3388, 3260, |
| 165 | 3132, 3004, 2876, 2748, 2620, 2492, 2364, |
| 166 | 2236, 2108, 1980, 1884, 1820, 1756, 1692, |
| 167 | 1628, 1564, 1500, 1436, 1372, 1308, 1244, |
| 168 | 1180, 1116, 1052, 988, 924, 876, 844, |
| 169 | 812, 780, 748, 716, 684, 652, 620, |
| 170 | 588, 556, 524, 492, 460, 428, 396, |
| 171 | 372, 356, 340, 324, 308, 292, 276, |
| 172 | 260, 244, 228, 212, 196, 180, 164, |
| 173 | 148, 132, 120, 112, 104, 96, 88, |
| 174 | 80, 72, 64, 56, 48, 40, 32, |
| 175 | 24, 16, 8, 0 |
| 176 | }; |
| 177 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 178 | static const uint16_t dvi_adpcm_steptab[89] ICONST_ATTR = { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 179 | 7, 8, 9, 10, 11, 12, 13, 14, |
| 180 | 16, 17, 19, 21, 23, 25, 28, 31, |
| 181 | 34, 37, 41, 45, 50, 55, 60, 66, |
| 182 | 73, 80, 88, 97, 107, 118, 130, 143, |
| 183 | 157, 173, 190, 209, 230, 253, 279, 307, |
| 184 | 337, 371, 408, 449, 494, 544, 598, 658, |
| 185 | 724, 796, 876, 963, 1060, 1166, 1282, 1411, |
| 186 | 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, |
| 187 | 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, |
| 188 | 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, |
| 189 | 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, |
| 190 | 32767 }; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 191 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 192 | static const int dvi_adpcm_indextab4[8] ICONST_ATTR = { |
| 193 | -1, -1, -1, -1, 2, 4, 6, 8 }; |
| 194 | |
| 195 | static const int dvi_adpcm_indextab3[4] ICONST_ATTR = { -1, -1, 1, 2 }; |
| 196 | |
| 197 | static int32_t samples[WAV_CHUNK_SIZE] IBSS_ATTR; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 198 | |
| 199 | static enum codec_status |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 200 | decode_dvi_adpcm(struct codec_api *ci, |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 201 | const uint8_t *buf, |
| 202 | int n, |
| 203 | uint16_t channels, uint16_t bitspersample, |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 204 | int32_t *pcmout, |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 205 | size_t *pcmoutsize); |
| 206 | |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 207 | /* this is the codec entry point */ |
Tomasz Malesinski | 80da8b1 | 2006-11-26 18:31:41 +0000 | [diff] [blame] | 208 | enum codec_status codec_main(void) |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 209 | { |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 210 | uint32_t numbytes, bytesdone; |
| 211 | uint32_t totalsamples = 0; |
| 212 | uint16_t channels = 0; |
| 213 | uint16_t samplesperblock = 0; |
| 214 | int bytespersample = 0; |
| 215 | uint16_t bitspersample; |
| 216 | uint32_t i; |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 217 | size_t n; |
| 218 | int bufcount; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 219 | int endofstream; |
| 220 | unsigned char *buf; |
| 221 | uint8_t *wavbuf; |
| 222 | long chunksize; |
| 223 | uint16_t formattag = 0; |
| 224 | uint16_t blockalign = 0; |
| 225 | uint32_t avgbytespersec = 0; |
| 226 | off_t firstblockposn; /* position of the first block in file */ |
Magnus Holmgren | 8a3b6da | 2006-08-23 08:19:29 +0000 | [diff] [blame] | 227 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 228 | |
| 229 | /* Generic codec initialisation */ |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 230 | ci->configure(DSP_SET_SAMPLE_DEPTH, 28); |
| 231 | ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 232 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 233 | next_track: |
Tomasz Malesinski | 80da8b1 | 2006-11-26 18:31:41 +0000 | [diff] [blame] | 234 | if (codec_init()) { |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 235 | i = CODEC_ERROR; |
| 236 | goto exit; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 237 | } |
| 238 | |
Magnus Holmgren | 8a3b6da | 2006-08-23 08:19:29 +0000 | [diff] [blame] | 239 | while (!*ci->taginfo_ready && !ci->stop_codec) |
| 240 | ci->sleep(1); |
Michael Sevakis | 9b9e227 | 2007-02-26 17:15:04 +0000 | [diff] [blame] | 241 | |
| 242 | codec_set_replaygain(ci->id3); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 243 | |
Magnus Holmgren | 8a3b6da | 2006-08-23 08:19:29 +0000 | [diff] [blame] | 244 | /* Need to save offset for later use (cleared indirectly by advance_buffer) */ |
| 245 | bytesdone = ci->id3->offset; |
| 246 | |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 247 | /* get RIFF chunk header */ |
| 248 | buf = ci->request_buffer(&n, 12); |
| 249 | if (n < 12) { |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 250 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 251 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 252 | } |
| 253 | if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) { |
| 254 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 255 | goto done; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 256 | } |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 257 | |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 258 | /* advance to first WAVE chunk */ |
| 259 | ci->advance_buffer(12); |
| 260 | |
| 261 | firstblockposn = 12; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 262 | bitspersample = 0; |
| 263 | numbytes = 0; |
| 264 | totalsamples = 0; |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 265 | |
| 266 | /* iterate over WAVE chunks until the 'data' chunk, which should be after the 'fmt ' chunk */ |
| 267 | while (true) { |
| 268 | /* get WAVE chunk header */ |
| 269 | buf = ci->request_buffer(&n, 1024); |
| 270 | if (n < 8) { |
| 271 | /* no more chunks, 'data' chunk must not have been found */ |
| 272 | i = CODEC_ERROR; |
| 273 | goto done; |
| 274 | } |
| 275 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 276 | /* chunkSize */ |
| 277 | i = (buf[4]|(buf[5]<<8)|(buf[6]<<16)|(buf[7]<<24)); |
| 278 | if (memcmp(buf, "fmt ", 4) == 0) { |
| 279 | if (i < 16) { |
Jens Arnold | bd5c0ad | 2007-03-17 10:50:58 +0000 | [diff] [blame] | 280 | DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n", |
| 281 | (unsigned long)i); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 282 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 283 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 284 | } |
| 285 | /* wFormatTag */ |
| 286 | formattag=buf[8]|(buf[9]<<8); |
| 287 | /* wChannels */ |
| 288 | channels=buf[10]|(buf[11]<<8); |
| 289 | /* skipping dwSamplesPerSec */ |
| 290 | /* dwAvgBytesPerSec */ |
| 291 | avgbytespersec = buf[16]|(buf[17]<<8)|(buf[18]<<16)|(buf[19]<<24); |
| 292 | /* wBlockAlign */ |
| 293 | blockalign=buf[20]|(buf[21]<<8); |
| 294 | /* wBitsPerSample */ |
| 295 | bitspersample=buf[22]|(buf[23]<<8); |
| 296 | if (formattag != WAVE_FORMAT_PCM) { |
| 297 | uint16_t size; |
| 298 | if (i < 18) { |
| 299 | /* this is not a fatal error with some formats, |
| 300 | * we'll see later if we can't decode it */ |
| 301 | DEBUGF("CODEC_WARNING: non-PCM WAVE (formattag=0x%x) " |
Jens Arnold | f68362a | 2007-03-17 09:54:28 +0000 | [diff] [blame] | 302 | "doesn't have ext. fmt descr (chunksize=%ld<18).\n", |
Jens Arnold | bd5c0ad | 2007-03-17 10:50:58 +0000 | [diff] [blame] | 303 | formattag, (long)i); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 304 | } |
| 305 | size = buf[24]|(buf[25]<<8); |
| 306 | if (formattag == WAVE_FORMAT_DVI_ADPCM) { |
| 307 | if (size < 2) { |
| 308 | DEBUGF("CODEC_ERROR: dvi_adpcm is missing " |
| 309 | "SamplesPerBlock value\n"); |
| 310 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 311 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 312 | } |
| 313 | samplesperblock = buf[26]|(buf[27]<<8); |
| 314 | } else if (formattag == WAVE_FORMAT_EXTENSIBLE) { |
| 315 | if (size < 22) { |
| 316 | DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is " |
| 317 | "missing extension\n"); |
| 318 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 319 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 320 | } |
| 321 | /* wValidBitsPerSample */ |
| 322 | bitspersample = buf[26]|(buf[27]<<8); |
| 323 | /* skipping dwChannelMask (4bytes) */ |
| 324 | /* SubFormat (only get the first two bytes) */ |
| 325 | formattag = buf[32]|(buf[33]<<8); |
| 326 | } |
| 327 | } |
| 328 | } else if (memcmp(buf, "data", 4) == 0) { |
| 329 | numbytes = i; |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 330 | /* advance to start of data */ |
| 331 | ci->advance_buffer(8); |
| 332 | firstblockposn += 8; |
| 333 | break; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 334 | } else if (memcmp(buf, "fact", 4) == 0) { |
| 335 | /* dwSampleLength */ |
| 336 | if (i >= 4) |
| 337 | totalsamples = (buf[8]|(buf[9]<<8)|(buf[10]<<16)|(buf[11]<<24)); |
| 338 | } else { |
| 339 | DEBUGF("unknown WAVE chunk: '%c%c%c%c', size=%lu\n", |
Jens Arnold | bd5c0ad | 2007-03-17 10:50:58 +0000 | [diff] [blame] | 340 | buf[0], buf[1], buf[2], buf[3], (unsigned long)i); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 341 | } |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 342 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 343 | /* go to next chunk (even chunk sizes must be padded) */ |
| 344 | if (i & 0x01) |
| 345 | i++; |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 346 | ci->advance_buffer(i+8); |
| 347 | firstblockposn += i + 8; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 348 | } |
| 349 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 350 | if (channels == 0) { |
| 351 | DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n"); |
| 352 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 353 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 354 | } |
| 355 | if (numbytes == 0) { |
| 356 | DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); |
| 357 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 358 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 359 | } |
| 360 | if (formattag != WAVE_FORMAT_PCM && totalsamples == 0) { |
| 361 | /* This is non-fatal for some formats */ |
| 362 | DEBUGF("CODEC_WARNING: non-PCM WAVE doesn't have a 'fact' chunk\n"); |
| 363 | } |
| 364 | if (formattag == WAVE_FORMAT_ALAW || formattag == WAVE_FORMAT_MULAW || |
| 365 | formattag == IBM_FORMAT_ALAW || formattag == IBM_FORMAT_MULAW) { |
| 366 | if (bitspersample != 8) { |
| 367 | DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample\n"); |
| 368 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 369 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 370 | } |
| 371 | bytespersample = channels; |
| 372 | } |
| 373 | if (formattag == WAVE_FORMAT_DVI_ADPCM |
| 374 | && bitspersample != 4 && bitspersample != 3) { |
| 375 | DEBUGF("CODEC_ERROR: dvi_adpcm must have 3 or 4 bitspersample\n"); |
| 376 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 377 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 378 | } |
| 379 | if (formattag == WAVE_FORMAT_PCM && bitspersample > 32) { |
| 380 | DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample " |
| 381 | "is unsupported\n"); |
| 382 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 383 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 384 | } |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 385 | |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 386 | ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 387 | if (channels == 2) { |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 388 | ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 389 | } else if (channels == 1) { |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 390 | ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 391 | } else { |
| 392 | DEBUGF("CODEC_ERROR: more than 2 channels\n"); |
| 393 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 394 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 395 | } |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 396 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 397 | if (totalsamples == 0) { |
| 398 | if (formattag == WAVE_FORMAT_PCM || |
| 399 | formattag == WAVE_FORMAT_ALAW || formattag == WAVE_FORMAT_MULAW || |
| 400 | formattag == IBM_FORMAT_ALAW || formattag == IBM_FORMAT_MULAW) { |
| 401 | /* for PCM and derived formats only */ |
| 402 | bytespersample = (((bitspersample - 1)/8 + 1)*channels); |
| 403 | totalsamples = numbytes/bytespersample; |
| 404 | } else { |
| 405 | DEBUGF("CODEC_ERROR: cannot compute totalsamples\n"); |
| 406 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 407 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 408 | } |
| 409 | } |
| 410 | |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 411 | /* make sure we're at the correct offset */ |
Magnus Holmgren | 8a3b6da | 2006-08-23 08:19:29 +0000 | [diff] [blame] | 412 | if (bytesdone > (uint32_t) firstblockposn) { |
Magnus Holmgren | f95dd56 | 2006-06-04 15:04:03 +0000 | [diff] [blame] | 413 | /* Round down to previous block */ |
Magnus Holmgren | 8a3b6da | 2006-08-23 08:19:29 +0000 | [diff] [blame] | 414 | uint32_t offset = bytesdone - bytesdone % blockalign; |
Magnus Holmgren | f95dd56 | 2006-06-04 15:04:03 +0000 | [diff] [blame] | 415 | |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 416 | ci->advance_buffer(offset-firstblockposn); |
Magnus Holmgren | f95dd56 | 2006-06-04 15:04:03 +0000 | [diff] [blame] | 417 | bytesdone = offset - firstblockposn; |
| 418 | } else { |
Adam Boot | 71cf604 | 2006-06-27 22:27:21 +0000 | [diff] [blame] | 419 | /* already where we need to be */ |
Magnus Holmgren | f95dd56 | 2006-06-04 15:04:03 +0000 | [diff] [blame] | 420 | bytesdone = 0; |
| 421 | } |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 422 | |
| 423 | /* The main decoder loop */ |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 424 | endofstream = 0; |
| 425 | /* chunksize is computed so that one chunk is about 1/50s. |
| 426 | * this make 4096 for 44.1kHz 16bits stereo. |
| 427 | * It also has to be a multiple of blockalign */ |
| 428 | chunksize = (1 + avgbytespersec / (50*blockalign))*blockalign; |
| 429 | /* check that the output buffer is big enough (convert to samplespersec, |
| 430 | then round to the blockalign multiple below) */ |
Thom Johansen | 09ed0d6 | 2006-03-22 21:52:48 +0000 | [diff] [blame] | 431 | if (((uint64_t)chunksize*ci->id3->frequency*channels*2) |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 432 | /(uint64_t)avgbytespersec >= WAV_CHUNK_SIZE) { |
| 433 | chunksize = ((uint64_t)WAV_CHUNK_SIZE*avgbytespersec |
Thom Johansen | 09ed0d6 | 2006-03-22 21:52:48 +0000 | [diff] [blame] | 434 | /((uint64_t)ci->id3->frequency*channels*2 |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 435 | *blockalign))*blockalign; |
| 436 | } |
| 437 | |
| 438 | while (!endofstream) { |
| 439 | ci->yield(); |
Brandon Low | ebadcc6 | 2006-04-15 02:03:11 +0000 | [diff] [blame] | 440 | if (ci->stop_codec || ci->new_track) { |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 441 | break; |
| 442 | } |
| 443 | |
| 444 | if (ci->seek_time) { |
| 445 | uint32_t newpos; |
| 446 | |
| 447 | /* use avgbytespersec to round to the closest blockalign multiple, |
| 448 | add firstblockposn. 64-bit casts to avoid overflows. */ |
| 449 | newpos = (((uint64_t)avgbytespersec*(ci->seek_time - 1)) |
| 450 | / (1000LL*blockalign))*blockalign; |
| 451 | if (newpos > numbytes) |
| 452 | break; |
| 453 | if (ci->seek_buffer(firstblockposn + newpos)) |
| 454 | bytesdone = newpos; |
| 455 | ci->seek_complete(); |
| 456 | } |
Brandon Low | c76904b | 2006-03-24 14:02:27 +0000 | [diff] [blame] | 457 | wavbuf = (uint8_t *)ci->request_buffer(&n, chunksize); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 458 | |
| 459 | if (n == 0) |
| 460 | break; /* End of stream */ |
| 461 | |
| 462 | if (bytesdone + n > numbytes) { |
| 463 | n = numbytes - bytesdone; |
| 464 | endofstream = 1; |
| 465 | } |
| 466 | |
| 467 | if (formattag == WAVE_FORMAT_PCM) { |
| 468 | if (bitspersample > 24) { |
| 469 | for (i = 0; i < n; i += 4) { |
| 470 | samples[i/4] = (wavbuf[i] >> 3)| |
| 471 | (wavbuf[i + 1]<<5)|(wavbuf[i + 2]<<13)| |
| 472 | (SE(wavbuf[i + 3])<<21); |
| 473 | } |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 474 | bufcount = n >> 2; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 475 | } else if (bitspersample > 16) { |
| 476 | for (i = 0; i < n; i += 3) { |
| 477 | samples[i/3] = (wavbuf[i]<<5)| |
| 478 | (wavbuf[i + 1]<<13)|(SE(wavbuf[i + 2])<<21); |
| 479 | } |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 480 | bufcount = n/3; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 481 | } else if (bitspersample > 8) { |
| 482 | for (i = 0; i < n; i += 2) { |
| 483 | samples[i/2] = (wavbuf[i]<<13)|(SE(wavbuf[i + 1])<<21); |
| 484 | } |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 485 | bufcount = n >> 1; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 486 | } else { |
| 487 | for (i = 0; i < n; i++) { |
| 488 | samples[i] = (wavbuf[i] - 0x80)<<21; |
| 489 | } |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 490 | bufcount = n; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 491 | } |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 492 | |
| 493 | if (channels == 2) |
| 494 | bufcount >>= 1; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 495 | } else if (formattag == WAVE_FORMAT_ALAW |
| 496 | || formattag == IBM_FORMAT_ALAW) { |
| 497 | for (i = 0; i < n; i++) |
| 498 | samples[i] = alaw2linear16[wavbuf[i]] << 13; |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 499 | |
| 500 | bufcount = (channels == 2) ? (n >> 1) : n; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 501 | } else if (formattag == WAVE_FORMAT_MULAW |
| 502 | || formattag == IBM_FORMAT_MULAW) { |
| 503 | for (i = 0; i < n; i++) |
| 504 | samples[i] = ulaw2linear16[wavbuf[i]] << 13; |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 505 | |
| 506 | bufcount = (channels == 2) ? (n >> 1) : n; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 507 | } |
| 508 | else if (formattag == WAVE_FORMAT_DVI_ADPCM) { |
| 509 | unsigned int nblocks = chunksize/blockalign; |
| 510 | |
| 511 | for (i = 0; i < nblocks; i++) { |
| 512 | size_t decodedsize = samplesperblock*channels; |
Thom Johansen | 09ed0d6 | 2006-03-22 21:52:48 +0000 | [diff] [blame] | 513 | if (decode_dvi_adpcm(ci, wavbuf + i*blockalign, |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 514 | blockalign, channels, bitspersample, |
| 515 | samples + i*samplesperblock*channels, |
Thom Johansen | 09ed0d6 | 2006-03-22 21:52:48 +0000 | [diff] [blame] | 516 | &decodedsize) != CODEC_OK) { |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 517 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 518 | goto done; |
Thom Johansen | 09ed0d6 | 2006-03-22 21:52:48 +0000 | [diff] [blame] | 519 | } |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 520 | } |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 521 | bufcount = nblocks*samplesperblock; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 522 | } else { |
| 523 | DEBUGF("CODEC_ERROR: unsupported format %x\n", formattag); |
| 524 | i = CODEC_ERROR; |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 525 | goto done; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 526 | } |
| 527 | |
Michael Sevakis | aba6ca0 | 2007-02-07 00:51:50 +0000 | [diff] [blame] | 528 | ci->pcmbuf_insert(samples, NULL, bufcount); |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 529 | |
| 530 | ci->advance_buffer(n); |
| 531 | bytesdone += n; |
| 532 | if (bytesdone >= numbytes) |
| 533 | endofstream = 1; |
| 534 | ci->set_elapsed(bytesdone*1000LL/avgbytespersec); |
| 535 | } |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 536 | i = CODEC_OK; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 537 | |
Brandon Low | f3bc1ef | 2006-04-22 14:40:13 +0000 | [diff] [blame] | 538 | done: |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 539 | if (ci->request_next_track()) |
| 540 | goto next_track; |
| 541 | |
Brandon Low | 1060e44 | 2006-01-18 20:22:03 +0000 | [diff] [blame] | 542 | exit: |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 543 | return i; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 544 | } |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 545 | |
| 546 | static enum codec_status |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 547 | decode_dvi_adpcm(struct codec_api *ci, |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 548 | const uint8_t *buf, |
| 549 | int n, |
| 550 | uint16_t channels, uint16_t bitspersample, |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 551 | int32_t *pcmout, |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 552 | size_t *pcmoutsize) |
| 553 | { |
| 554 | size_t nsamples = 0; |
| 555 | int sample[2]; |
| 556 | int samplecode[32][2]; |
| 557 | int i; |
| 558 | int stepindex[2]; |
| 559 | int c; |
| 560 | int diff; |
| 561 | int step; |
| 562 | int codem; |
| 563 | int code; |
| 564 | |
Dave Chapman | 0eb6754 | 2005-11-02 01:24:45 +0000 | [diff] [blame] | 565 | (void)ci; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 566 | if (bitspersample != 4 && bitspersample != 3) { |
| 567 | DEBUGF("decode_dvi_adpcm: wrong bitspersample\n"); |
| 568 | return CODEC_ERROR; |
| 569 | } |
| 570 | |
| 571 | /* decode block header */ |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 572 | for (c = 0; c < channels && n >= 4; c++) { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 573 | /* decode + push first sample */ |
| 574 | sample[c] = (short)(buf[0]|(buf[1]<<8));/* need cast for sign-extend */ |
Thom Johansen | 09ed0d6 | 2006-03-22 21:52:48 +0000 | [diff] [blame] | 575 | pcmout[c] = sample[c] << 13; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 576 | nsamples++; |
| 577 | stepindex[c] = buf[2]; |
| 578 | /* check for step table index overflow */ |
| 579 | if (stepindex[c] > 88) { |
| 580 | DEBUGF("decode_dvi_adpcm: stepindex[%d]=%d>88\n",c,stepindex[c]); |
| 581 | return CODEC_ERROR; |
| 582 | } |
| 583 | |
| 584 | buf += 4; |
| 585 | n -= 4; |
| 586 | } |
| 587 | if (bitspersample == 4) { |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 588 | while (n>= channels*4 && (nsamples + 8*channels) <= *pcmoutsize) { |
| 589 | for (c = 0; c < channels; c++) { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 590 | samplecode[0][c] = buf[0]&0xf; |
| 591 | samplecode[1][c] = buf[0]>>4; |
| 592 | samplecode[2][c] = buf[1]&0xf; |
| 593 | samplecode[3][c] = buf[1]>>4; |
| 594 | samplecode[4][c] = buf[2]&0xf; |
| 595 | samplecode[5][c] = buf[2]>>4; |
| 596 | samplecode[6][c] = buf[3]&0xf; |
| 597 | samplecode[7][c] = buf[3]>>4; |
| 598 | buf += 4; |
| 599 | n -= 4; |
| 600 | } |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 601 | for (i = 0; i < 8; i++) { |
| 602 | for (c = 0; c < channels; c++) { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 603 | step = dvi_adpcm_steptab[stepindex[c]]; |
| 604 | codem = samplecode[i][c]; |
| 605 | code = codem & 0x07; |
| 606 | |
| 607 | /* adjust the step table index */ |
| 608 | stepindex[c] += dvi_adpcm_indextab4[code]; |
| 609 | /* check for step table index overflow and underflow */ |
| 610 | if (stepindex[c] > 88) |
| 611 | stepindex[c] = 88; |
| 612 | else if (stepindex[c] < 0) |
| 613 | stepindex[c] = 0; |
| 614 | /* calculate the difference */ |
| 615 | #ifdef STRICT_IMA |
| 616 | diff = 0; |
| 617 | if (code & 4) |
| 618 | diff += step; |
| 619 | step = step >> 1; |
| 620 | if (code & 2) |
| 621 | diff += step; |
| 622 | step = step >> 1; |
| 623 | if (code & 1) |
| 624 | diff += step; |
| 625 | step = step >> 1; |
| 626 | diff += step; |
| 627 | #else |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 628 | diff = ((code + code + 1) * step) >> 3; /* faster */ |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 629 | #endif |
| 630 | /* check the sign bit */ |
| 631 | /* check for overflow and underflow errors */ |
| 632 | if (code != codem) { |
| 633 | sample[c] -= diff; |
| 634 | if (sample[c] < -32768) |
| 635 | sample[c] = -32768; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 636 | } else { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 637 | sample[c] += diff; |
| 638 | if (sample[c] > 32767) |
| 639 | sample[c] = 32767; |
| 640 | } |
| 641 | /* output the new sample */ |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 642 | pcmout[nsamples] = sample[c] << 13; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 643 | nsamples++; |
| 644 | } |
| 645 | } |
| 646 | } |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 647 | } else { /* bitspersample == 3 */ |
| 648 | while (n >= channels*12 && (nsamples + 32*channels) <= *pcmoutsize) { |
| 649 | for (c = 0; c < channels; c++) { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 650 | uint16_t bitstream = 0; |
| 651 | int bitsread = 0; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 652 | for (i = 0; i < 32 && n > 0; i++) { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 653 | if (bitsread < 3) { |
| 654 | /* read 8 more bits */ |
| 655 | bitstream |= buf[0]<<bitsread; |
| 656 | bitsread += 8; |
| 657 | n--; |
| 658 | buf++; |
| 659 | } |
| 660 | samplecode[i][c] = bitstream & 7; |
| 661 | bitstream = bitstream>>3; |
| 662 | bitsread -= 3; |
| 663 | } |
| 664 | if (bitsread != 0) { |
| 665 | /* 32*3 = 3 words, so we should end with bitsread==0 */ |
| 666 | DEBUGF("decode_dvi_adpcm: error in implementation\n"); |
| 667 | return CODEC_ERROR; |
| 668 | } |
| 669 | } |
| 670 | |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 671 | for (i = 0; i < 32; i++) { |
| 672 | for (c = 0; c < channels; c++) { |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 673 | step = dvi_adpcm_steptab[stepindex[c]]; |
| 674 | codem = samplecode[i][c]; |
| 675 | code = codem & 0x03; |
| 676 | |
| 677 | /* adjust the step table index */ |
| 678 | stepindex[c] += dvi_adpcm_indextab3[code]; |
| 679 | /* check for step table index overflow and underflow */ |
| 680 | if (stepindex[c] > 88) |
| 681 | stepindex[c] = 88; |
| 682 | else if (stepindex[c] < 0) |
| 683 | stepindex[c] = 0; |
| 684 | /* calculate the difference */ |
| 685 | #ifdef STRICT_IMA |
| 686 | diff = 0; |
| 687 | if (code & 2) |
| 688 | diff += step; |
| 689 | step = step >> 1; |
| 690 | if (code & 1) |
| 691 | diff += step; |
| 692 | step = step >> 1; |
| 693 | diff += step; |
| 694 | #else |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 695 | diff = ((code + code + 1) * step) >> 3; /* faster */ |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 696 | #endif |
| 697 | /* check the sign bit */ |
| 698 | /* check for overflow and underflow errors */ |
| 699 | if (code != codem) { |
| 700 | sample[c] -= diff; |
| 701 | if (sample[c] < -32768) |
| 702 | sample[c] = -32768; |
| 703 | } |
| 704 | else { |
| 705 | sample[c] += diff; |
| 706 | if (sample[c] > 32767) |
| 707 | sample[c] = 32767; |
| 708 | } |
| 709 | /* output the new sample */ |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 710 | pcmout[nsamples] = sample[c] << 13; |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 711 | nsamples++; |
| 712 | } |
| 713 | } |
| 714 | } |
| 715 | } |
| 716 | |
| 717 | if (nsamples > *pcmoutsize) { |
| 718 | DEBUGF("decode_dvi_adpcm: output buffer overflow!\n"); |
| 719 | return CODEC_ERROR; |
| 720 | } |
| 721 | *pcmoutsize = nsamples; |
Thom Johansen | 0968536 | 2006-03-20 20:32:19 +0000 | [diff] [blame] | 722 | if (n != 0) { |
| 723 | DEBUGF("decode_dvi_adpcm: n=%d unprocessed bytes\n", n); |
Magnus Holmgren | b5f3365 | 2005-09-22 19:36:25 +0000 | [diff] [blame] | 724 | } |
| 725 | return CODEC_OK; |
| 726 | } |
| 727 | |