| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2005 Dave Chapman |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| |
| #include "codeclib.h" |
| #include "inttypes.h" |
| |
| CODEC_HEADER |
| |
| /* Macro that sign extends an unsigned byte */ |
| #define SE(x) ((int32_t)((int8_t)(x))) |
| |
| /* This codec support WAVE files with the following formats: |
| * - PCM, up to 32 bits, supporting 32 bits playback when useful. |
| * - ALAW and MULAW (16 bits compressed on 8 bits). |
| * - DVI_ADPCM (16 bits compressed on 3 or 4 bits). |
| * |
| * For a good documentation on WAVE files, see: |
| * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/WAVE/WAVE.html |
| * and |
| * http://www.sonicspot.com/guide/wavefiles.html |
| * |
| * For sample WAV files, see: |
| * http://www.tsp.ece.mcgill.ca/MMSP/Documents/AudioFormats/WAVE/Samples.html |
| * |
| * The most common formats seem to be PCM, ADPCM, DVI_ADPCM, IEEE_FLOAT, |
| * ALAW and MULAW |
| */ |
| |
| /* These constants are from RFC 2361. */ |
| enum |
| { |
| WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Unknown Wave Format */ |
| WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */ |
| WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */ |
| WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */ |
| WAVE_FORMAT_VSELP = 0x0004, /* Compaq Computer's VSELP */ |
| WAVE_FORMAT_IBM_CVSD = 0x0005, /* IBM CVSD */ |
| WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */ |
| WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */ |
| WAVE_FORMAT_OKI_ADPCM = 0x0010, /* OKI ADPCM */ |
| WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */ |
| WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012, /* Videologic's MediaSpace ADPCM */ |
| WAVE_FORMAT_SIERRA_ADPCM = 0x0013, /* Sierra ADPCM */ |
| WAVE_FORMAT_G723_ADPCM = 0x0014, /* G.723 ADPCM */ |
| WAVE_FORMAT_DIGISTD = 0x0015, /* DSP Solutions' DIGISTD */ |
| WAVE_FORMAT_DIGIFIX = 0x0016, /* DSP Solutions' DIGIFIX */ |
| WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */ |
| WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018, /* MediaVision ADPCM */ |
| WAVE_FORMAT_CU_CODEC = 0x0019, /* HP CU */ |
| WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */ |
| WAVE_FORMAT_SONARC = 0x0021, /* Speech Compression's Sonarc */ |
| WAVE_FORMAT_DSP_TRUESPEECH = 0x0022, /* DSP Group's True Speech */ |
| WAVE_FORMAT_ECHOSC1 = 0x0023, /* Echo Speech's EchoSC1 */ |
| WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024, /* Audiofile AF36 */ |
| WAVE_FORMAT_APTX = 0x0025, /* APTX */ |
| WAVE_FORMAT_DOLBY_AC2 = 0x0030, /* Dolby AC2 */ |
| WAVE_FORMAT_GSM610 = 0x0031, /* GSM610 */ |
| WAVE_FORMAT_MSNAUDIO = 0x0032, /* MSNAudio */ |
| WAVE_FORMAT_ANTEX_ADPCME = 0x0033, /* Antex ADPCME */ |
| |
| WAVE_FORMAT_MPEG = 0x0050, /* MPEG */ |
| WAVE_FORMAT_MPEGLAYER3 = 0x0055, /* MPEG layer 3 */ |
| WAVE_FORMAT_LUCENT_G723 = 0x0059, /* Lucent G.723 */ |
| WAVE_FORMAT_G726_ADPCM = 0x0064, /* G.726 ADPCM */ |
| WAVE_FORMAT_G722_ADPCM = 0x0065, /* G.722 ADPCM */ |
| |
| IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */ |
| IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */ |
| IBM_FORMAT_ADPCM = 0x0103, |
| |
| WAVE_FORMAT_CREATIVE_ADPCM = 0x0200, |
| |
| WAVE_FORMAT_EXTENSIBLE = 0xFFFE |
| }; |
| |
| /* Maximum number of bytes to process in one iteration */ |
| /* for 44.1kHz stereo 16bits, this represents 0.023s ~= 1/50s */ |
| #define WAV_CHUNK_SIZE (1024*2) |
| |
| static const int16_t alaw2linear16[256] ICONST_ATTR = { |
| -5504, -5248, -6016, -5760, -4480, -4224, -4992, |
| -4736, -7552, -7296, -8064, -7808, -6528, -6272, |
| -7040, -6784, -2752, -2624, -3008, -2880, -2240, |
| -2112, -2496, -2368, -3776, -3648, -4032, -3904, |
| -3264, -3136, -3520, -3392, -22016, -20992, -24064, |
| -23040, -17920, -16896, -19968, -18944, -30208, -29184, |
| -32256, -31232, -26112, -25088, -28160, -27136, -11008, |
| -10496, -12032, -11520, -8960, -8448, -9984, -9472, |
| -15104, -14592, -16128, -15616, -13056, -12544, -14080, |
| -13568, -344, -328, -376, -360, -280, -264, |
| -312, -296, -472, -456, -504, -488, -408, |
| -392, -440, -424, -88, -72, -120, -104, |
| -24, -8, -56, -40, -216, -200, -248, |
| -232, -152, -136, -184, -168, -1376, -1312, |
| -1504, -1440, -1120, -1056, -1248, -1184, -1888, |
| -1824, -2016, -1952, -1632, -1568, -1760, -1696, |
| -688, -656, -752, -720, -560, -528, -624, |
| -592, -944, -912, -1008, -976, -816, -784, |
| -880, -848, 5504, 5248, 6016, 5760, 4480, |
| 4224, 4992, 4736, 7552, 7296, 8064, 7808, |
| 6528, 6272, 7040, 6784, 2752, 2624, 3008, |
| 2880, 2240, 2112, 2496, 2368, 3776, 3648, |
| 4032, 3904, 3264, 3136, 3520, 3392, 22016, |
| 20992, 24064, 23040, 17920, 16896, 19968, 18944, |
| 30208, 29184, 32256, 31232, 26112, 25088, 28160, |
| 27136, 11008, 10496, 12032, 11520, 8960, 8448, |
| 9984, 9472, 15104, 14592, 16128, 15616, 13056, |
| 12544, 14080, 13568, 344, 328, 376, 360, |
| 280, 264, 312, 296, 472, 456, 504, |
| 488, 408, 392, 440, 424, 88, 72, |
| 120, 104, 24, 8, 56, 40, 216, |
| 200, 248, 232, 152, 136, 184, 168, |
| 1376, 1312, 1504, 1440, 1120, 1056, 1248, |
| 1184, 1888, 1824, 2016, 1952, 1632, 1568, |
| 1760, 1696, 688, 656, 752, 720, 560, |
| 528, 624, 592, 944, 912, 1008, 976, |
| 816, 784, 880, 848 |
| }; |
| |
| static const int16_t ulaw2linear16[256] ICONST_ATTR = { |
| -32124, -31100, -30076, -29052, -28028, -27004, -25980, |
| -24956, -23932, -22908, -21884, -20860, -19836, -18812, |
| -17788, -16764, -15996, -15484, -14972, -14460, -13948, |
| -13436, -12924, -12412, -11900, -11388, -10876, -10364, |
| -9852, -9340, -8828, -8316, -7932, -7676, -7420, |
| -7164, -6908, -6652, -6396, -6140, -5884, -5628, |
| -5372, -5116, -4860, -4604, -4348, -4092, -3900, |
| -3772, -3644, -3516, -3388, -3260, -3132, -3004, |
| -2876, -2748, -2620, -2492, -2364, -2236, -2108, |
| -1980, -1884, -1820, -1756, -1692, -1628, -1564, |
| -1500, -1436, -1372, -1308, -1244, -1180, -1116, |
| -1052, -988, -924, -876, -844, -812, -780, |
| -748, -716, -684, -652, -620, -588, -556, |
| -524, -492, -460, -428, -396, -372, -356, |
| -340, -324, -308, -292, -276, -260, -244, |
| -228, -212, -196, -180, -164, -148, -132, |
| -120, -112, -104, -96, -88, -80, -72, |
| -64, -56, -48, -40, -32, -24, -16, |
| -8, 0, 32124, 31100, 30076, 29052, 28028, |
| 27004, 25980, 24956, 23932, 22908, 21884, 20860, |
| 19836, 18812, 17788, 16764, 15996, 15484, 14972, |
| 14460, 13948, 13436, 12924, 12412, 11900, 11388, |
| 10876, 10364, 9852, 9340, 8828, 8316, 7932, |
| 7676, 7420, 7164, 6908, 6652, 6396, 6140, |
| 5884, 5628, 5372, 5116, 4860, 4604, 4348, |
| 4092, 3900, 3772, 3644, 3516, 3388, 3260, |
| 3132, 3004, 2876, 2748, 2620, 2492, 2364, |
| 2236, 2108, 1980, 1884, 1820, 1756, 1692, |
| 1628, 1564, 1500, 1436, 1372, 1308, 1244, |
| 1180, 1116, 1052, 988, 924, 876, 844, |
| 812, 780, 748, 716, 684, 652, 620, |
| 588, 556, 524, 492, 460, 428, 396, |
| 372, 356, 340, 324, 308, 292, 276, |
| 260, 244, 228, 212, 196, 180, 164, |
| 148, 132, 120, 112, 104, 96, 88, |
| 80, 72, 64, 56, 48, 40, 32, |
| 24, 16, 8, 0 |
| }; |
| |
| static const uint16_t dvi_adpcm_steptab[89] ICONST_ATTR = { |
| 7, 8, 9, 10, 11, 12, 13, 14, |
| 16, 17, 19, 21, 23, 25, 28, 31, |
| 34, 37, 41, 45, 50, 55, 60, 66, |
| 73, 80, 88, 97, 107, 118, 130, 143, |
| 157, 173, 190, 209, 230, 253, 279, 307, |
| 337, 371, 408, 449, 494, 544, 598, 658, |
| 724, 796, 876, 963, 1060, 1166, 1282, 1411, |
| 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, |
| 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, |
| 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, |
| 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, |
| 32767 }; |
| |
| static const int dvi_adpcm_indextab4[8] ICONST_ATTR = { |
| -1, -1, -1, -1, 2, 4, 6, 8 }; |
| |
| static const int dvi_adpcm_indextab3[4] ICONST_ATTR = { -1, -1, 1, 2 }; |
| |
| static int32_t samples[WAV_CHUNK_SIZE] IBSS_ATTR; |
| |
| static enum codec_status |
| decode_dvi_adpcm(struct codec_api *ci, |
| const uint8_t *buf, |
| int n, |
| uint16_t channels, uint16_t bitspersample, |
| int32_t *pcmout, |
| size_t *pcmoutsize); |
| |
| /* this is the codec entry point */ |
| enum codec_status codec_main(void) |
| { |
| uint32_t numbytes, bytesdone; |
| uint32_t totalsamples = 0; |
| uint16_t channels = 0; |
| uint16_t samplesperblock = 0; |
| int bytespersample = 0; |
| uint16_t bitspersample; |
| uint32_t i; |
| size_t n; |
| int bufcount; |
| int endofstream; |
| unsigned char *buf; |
| uint8_t *wavbuf; |
| long chunksize; |
| uint16_t formattag = 0; |
| uint16_t blockalign = 0; |
| uint32_t avgbytespersec = 0; |
| off_t firstblockposn; /* position of the first block in file */ |
| |
| |
| /* Generic codec initialisation */ |
| ci->configure(DSP_SET_SAMPLE_DEPTH, 28); |
| ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); |
| |
| next_track: |
| if (codec_init()) { |
| i = CODEC_ERROR; |
| goto exit; |
| } |
| |
| while (!*ci->taginfo_ready && !ci->stop_codec) |
| ci->sleep(1); |
| |
| codec_set_replaygain(ci->id3); |
| |
| /* Need to save offset for later use (cleared indirectly by advance_buffer) */ |
| bytesdone = ci->id3->offset; |
| |
| /* get RIFF chunk header */ |
| buf = ci->request_buffer(&n, 12); |
| if (n < 12) { |
| i = CODEC_ERROR; |
| goto done; |
| } |
| if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) { |
| i = CODEC_ERROR; |
| goto done; |
| } |
| |
| /* advance to first WAVE chunk */ |
| ci->advance_buffer(12); |
| |
| firstblockposn = 12; |
| bitspersample = 0; |
| numbytes = 0; |
| totalsamples = 0; |
| |
| /* iterate over WAVE chunks until the 'data' chunk, which should be after the 'fmt ' chunk */ |
| while (true) { |
| /* get WAVE chunk header */ |
| buf = ci->request_buffer(&n, 1024); |
| if (n < 8) { |
| /* no more chunks, 'data' chunk must not have been found */ |
| i = CODEC_ERROR; |
| goto done; |
| } |
| |
| /* chunkSize */ |
| i = (buf[4]|(buf[5]<<8)|(buf[6]<<16)|(buf[7]<<24)); |
| if (memcmp(buf, "fmt ", 4) == 0) { |
| if (i < 16) { |
| DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n", |
| (unsigned long)i); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| /* wFormatTag */ |
| formattag=buf[8]|(buf[9]<<8); |
| /* wChannels */ |
| channels=buf[10]|(buf[11]<<8); |
| /* skipping dwSamplesPerSec */ |
| /* dwAvgBytesPerSec */ |
| avgbytespersec = buf[16]|(buf[17]<<8)|(buf[18]<<16)|(buf[19]<<24); |
| /* wBlockAlign */ |
| blockalign=buf[20]|(buf[21]<<8); |
| /* wBitsPerSample */ |
| bitspersample=buf[22]|(buf[23]<<8); |
| if (formattag != WAVE_FORMAT_PCM) { |
| uint16_t size; |
| if (i < 18) { |
| /* this is not a fatal error with some formats, |
| * we'll see later if we can't decode it */ |
| DEBUGF("CODEC_WARNING: non-PCM WAVE (formattag=0x%x) " |
| "doesn't have ext. fmt descr (chunksize=%ld<18).\n", |
| formattag, (long)i); |
| } |
| size = buf[24]|(buf[25]<<8); |
| if (formattag == WAVE_FORMAT_DVI_ADPCM) { |
| if (size < 2) { |
| DEBUGF("CODEC_ERROR: dvi_adpcm is missing " |
| "SamplesPerBlock value\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| samplesperblock = buf[26]|(buf[27]<<8); |
| } else if (formattag == WAVE_FORMAT_EXTENSIBLE) { |
| if (size < 22) { |
| DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is " |
| "missing extension\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| /* wValidBitsPerSample */ |
| bitspersample = buf[26]|(buf[27]<<8); |
| /* skipping dwChannelMask (4bytes) */ |
| /* SubFormat (only get the first two bytes) */ |
| formattag = buf[32]|(buf[33]<<8); |
| } |
| } |
| } else if (memcmp(buf, "data", 4) == 0) { |
| numbytes = i; |
| /* advance to start of data */ |
| ci->advance_buffer(8); |
| firstblockposn += 8; |
| break; |
| } else if (memcmp(buf, "fact", 4) == 0) { |
| /* dwSampleLength */ |
| if (i >= 4) |
| totalsamples = (buf[8]|(buf[9]<<8)|(buf[10]<<16)|(buf[11]<<24)); |
| } else { |
| DEBUGF("unknown WAVE chunk: '%c%c%c%c', size=%lu\n", |
| buf[0], buf[1], buf[2], buf[3], (unsigned long)i); |
| } |
| |
| /* go to next chunk (even chunk sizes must be padded) */ |
| if (i & 0x01) |
| i++; |
| ci->advance_buffer(i+8); |
| firstblockposn += i + 8; |
| } |
| |
| if (channels == 0) { |
| DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| if (numbytes == 0) { |
| DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| if (formattag != WAVE_FORMAT_PCM && totalsamples == 0) { |
| /* This is non-fatal for some formats */ |
| DEBUGF("CODEC_WARNING: non-PCM WAVE doesn't have a 'fact' chunk\n"); |
| } |
| if (formattag == WAVE_FORMAT_ALAW || formattag == WAVE_FORMAT_MULAW || |
| formattag == IBM_FORMAT_ALAW || formattag == IBM_FORMAT_MULAW) { |
| if (bitspersample != 8) { |
| DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| bytespersample = channels; |
| } |
| if (formattag == WAVE_FORMAT_DVI_ADPCM |
| && bitspersample != 4 && bitspersample != 3) { |
| DEBUGF("CODEC_ERROR: dvi_adpcm must have 3 or 4 bitspersample\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| if (formattag == WAVE_FORMAT_PCM && bitspersample > 32) { |
| DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample " |
| "is unsupported\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| |
| ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); |
| if (channels == 2) { |
| ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); |
| } else if (channels == 1) { |
| ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); |
| } else { |
| DEBUGF("CODEC_ERROR: more than 2 channels\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| |
| if (totalsamples == 0) { |
| if (formattag == WAVE_FORMAT_PCM || |
| formattag == WAVE_FORMAT_ALAW || formattag == WAVE_FORMAT_MULAW || |
| formattag == IBM_FORMAT_ALAW || formattag == IBM_FORMAT_MULAW) { |
| /* for PCM and derived formats only */ |
| bytespersample = (((bitspersample - 1)/8 + 1)*channels); |
| totalsamples = numbytes/bytespersample; |
| } else { |
| DEBUGF("CODEC_ERROR: cannot compute totalsamples\n"); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| } |
| |
| /* make sure we're at the correct offset */ |
| if (bytesdone > (uint32_t) firstblockposn) { |
| /* Round down to previous block */ |
| uint32_t offset = bytesdone - bytesdone % blockalign; |
| |
| ci->advance_buffer(offset-firstblockposn); |
| bytesdone = offset - firstblockposn; |
| } else { |
| /* already where we need to be */ |
| bytesdone = 0; |
| } |
| |
| /* The main decoder loop */ |
| endofstream = 0; |
| /* chunksize is computed so that one chunk is about 1/50s. |
| * this make 4096 for 44.1kHz 16bits stereo. |
| * It also has to be a multiple of blockalign */ |
| chunksize = (1 + avgbytespersec / (50*blockalign))*blockalign; |
| /* check that the output buffer is big enough (convert to samplespersec, |
| then round to the blockalign multiple below) */ |
| if (((uint64_t)chunksize*ci->id3->frequency*channels*2) |
| /(uint64_t)avgbytespersec >= WAV_CHUNK_SIZE) { |
| chunksize = ((uint64_t)WAV_CHUNK_SIZE*avgbytespersec |
| /((uint64_t)ci->id3->frequency*channels*2 |
| *blockalign))*blockalign; |
| } |
| |
| while (!endofstream) { |
| ci->yield(); |
| if (ci->stop_codec || ci->new_track) { |
| break; |
| } |
| |
| if (ci->seek_time) { |
| uint32_t newpos; |
| |
| /* use avgbytespersec to round to the closest blockalign multiple, |
| add firstblockposn. 64-bit casts to avoid overflows. */ |
| newpos = (((uint64_t)avgbytespersec*(ci->seek_time - 1)) |
| / (1000LL*blockalign))*blockalign; |
| if (newpos > numbytes) |
| break; |
| if (ci->seek_buffer(firstblockposn + newpos)) |
| bytesdone = newpos; |
| ci->seek_complete(); |
| } |
| wavbuf = (uint8_t *)ci->request_buffer(&n, chunksize); |
| |
| if (n == 0) |
| break; /* End of stream */ |
| |
| if (bytesdone + n > numbytes) { |
| n = numbytes - bytesdone; |
| endofstream = 1; |
| } |
| |
| if (formattag == WAVE_FORMAT_PCM) { |
| if (bitspersample > 24) { |
| for (i = 0; i < n; i += 4) { |
| samples[i/4] = (wavbuf[i] >> 3)| |
| (wavbuf[i + 1]<<5)|(wavbuf[i + 2]<<13)| |
| (SE(wavbuf[i + 3])<<21); |
| } |
| bufcount = n >> 2; |
| } else if (bitspersample > 16) { |
| for (i = 0; i < n; i += 3) { |
| samples[i/3] = (wavbuf[i]<<5)| |
| (wavbuf[i + 1]<<13)|(SE(wavbuf[i + 2])<<21); |
| } |
| bufcount = n/3; |
| } else if (bitspersample > 8) { |
| for (i = 0; i < n; i += 2) { |
| samples[i/2] = (wavbuf[i]<<13)|(SE(wavbuf[i + 1])<<21); |
| } |
| bufcount = n >> 1; |
| } else { |
| for (i = 0; i < n; i++) { |
| samples[i] = (wavbuf[i] - 0x80)<<21; |
| } |
| bufcount = n; |
| } |
| |
| if (channels == 2) |
| bufcount >>= 1; |
| } else if (formattag == WAVE_FORMAT_ALAW |
| || formattag == IBM_FORMAT_ALAW) { |
| for (i = 0; i < n; i++) |
| samples[i] = alaw2linear16[wavbuf[i]] << 13; |
| |
| bufcount = (channels == 2) ? (n >> 1) : n; |
| } else if (formattag == WAVE_FORMAT_MULAW |
| || formattag == IBM_FORMAT_MULAW) { |
| for (i = 0; i < n; i++) |
| samples[i] = ulaw2linear16[wavbuf[i]] << 13; |
| |
| bufcount = (channels == 2) ? (n >> 1) : n; |
| } |
| else if (formattag == WAVE_FORMAT_DVI_ADPCM) { |
| unsigned int nblocks = chunksize/blockalign; |
| |
| for (i = 0; i < nblocks; i++) { |
| size_t decodedsize = samplesperblock*channels; |
| if (decode_dvi_adpcm(ci, wavbuf + i*blockalign, |
| blockalign, channels, bitspersample, |
| samples + i*samplesperblock*channels, |
| &decodedsize) != CODEC_OK) { |
| i = CODEC_ERROR; |
| goto done; |
| } |
| } |
| bufcount = nblocks*samplesperblock; |
| } else { |
| DEBUGF("CODEC_ERROR: unsupported format %x\n", formattag); |
| i = CODEC_ERROR; |
| goto done; |
| } |
| |
| ci->pcmbuf_insert(samples, NULL, bufcount); |
| |
| ci->advance_buffer(n); |
| bytesdone += n; |
| if (bytesdone >= numbytes) |
| endofstream = 1; |
| ci->set_elapsed(bytesdone*1000LL/avgbytespersec); |
| } |
| i = CODEC_OK; |
| |
| done: |
| if (ci->request_next_track()) |
| goto next_track; |
| |
| exit: |
| return i; |
| } |
| |
| static enum codec_status |
| decode_dvi_adpcm(struct codec_api *ci, |
| const uint8_t *buf, |
| int n, |
| uint16_t channels, uint16_t bitspersample, |
| int32_t *pcmout, |
| size_t *pcmoutsize) |
| { |
| size_t nsamples = 0; |
| int sample[2]; |
| int samplecode[32][2]; |
| int i; |
| int stepindex[2]; |
| int c; |
| int diff; |
| int step; |
| int codem; |
| int code; |
| |
| (void)ci; |
| if (bitspersample != 4 && bitspersample != 3) { |
| DEBUGF("decode_dvi_adpcm: wrong bitspersample\n"); |
| return CODEC_ERROR; |
| } |
| |
| /* decode block header */ |
| for (c = 0; c < channels && n >= 4; c++) { |
| /* decode + push first sample */ |
| sample[c] = (short)(buf[0]|(buf[1]<<8));/* need cast for sign-extend */ |
| pcmout[c] = sample[c] << 13; |
| nsamples++; |
| stepindex[c] = buf[2]; |
| /* check for step table index overflow */ |
| if (stepindex[c] > 88) { |
| DEBUGF("decode_dvi_adpcm: stepindex[%d]=%d>88\n",c,stepindex[c]); |
| return CODEC_ERROR; |
| } |
| |
| buf += 4; |
| n -= 4; |
| } |
| if (bitspersample == 4) { |
| while (n>= channels*4 && (nsamples + 8*channels) <= *pcmoutsize) { |
| for (c = 0; c < channels; c++) { |
| samplecode[0][c] = buf[0]&0xf; |
| samplecode[1][c] = buf[0]>>4; |
| samplecode[2][c] = buf[1]&0xf; |
| samplecode[3][c] = buf[1]>>4; |
| samplecode[4][c] = buf[2]&0xf; |
| samplecode[5][c] = buf[2]>>4; |
| samplecode[6][c] = buf[3]&0xf; |
| samplecode[7][c] = buf[3]>>4; |
| buf += 4; |
| n -= 4; |
| } |
| for (i = 0; i < 8; i++) { |
| for (c = 0; c < channels; c++) { |
| step = dvi_adpcm_steptab[stepindex[c]]; |
| codem = samplecode[i][c]; |
| code = codem & 0x07; |
| |
| /* adjust the step table index */ |
| stepindex[c] += dvi_adpcm_indextab4[code]; |
| /* check for step table index overflow and underflow */ |
| if (stepindex[c] > 88) |
| stepindex[c] = 88; |
| else if (stepindex[c] < 0) |
| stepindex[c] = 0; |
| /* calculate the difference */ |
| #ifdef STRICT_IMA |
| diff = 0; |
| if (code & 4) |
| diff += step; |
| step = step >> 1; |
| if (code & 2) |
| diff += step; |
| step = step >> 1; |
| if (code & 1) |
| diff += step; |
| step = step >> 1; |
| diff += step; |
| #else |
| diff = ((code + code + 1) * step) >> 3; /* faster */ |
| #endif |
| /* check the sign bit */ |
| /* check for overflow and underflow errors */ |
| if (code != codem) { |
| sample[c] -= diff; |
| if (sample[c] < -32768) |
| sample[c] = -32768; |
| } else { |
| sample[c] += diff; |
| if (sample[c] > 32767) |
| sample[c] = 32767; |
| } |
| /* output the new sample */ |
| pcmout[nsamples] = sample[c] << 13; |
| nsamples++; |
| } |
| } |
| } |
| } else { /* bitspersample == 3 */ |
| while (n >= channels*12 && (nsamples + 32*channels) <= *pcmoutsize) { |
| for (c = 0; c < channels; c++) { |
| uint16_t bitstream = 0; |
| int bitsread = 0; |
| for (i = 0; i < 32 && n > 0; i++) { |
| if (bitsread < 3) { |
| /* read 8 more bits */ |
| bitstream |= buf[0]<<bitsread; |
| bitsread += 8; |
| n--; |
| buf++; |
| } |
| samplecode[i][c] = bitstream & 7; |
| bitstream = bitstream>>3; |
| bitsread -= 3; |
| } |
| if (bitsread != 0) { |
| /* 32*3 = 3 words, so we should end with bitsread==0 */ |
| DEBUGF("decode_dvi_adpcm: error in implementation\n"); |
| return CODEC_ERROR; |
| } |
| } |
| |
| for (i = 0; i < 32; i++) { |
| for (c = 0; c < channels; c++) { |
| step = dvi_adpcm_steptab[stepindex[c]]; |
| codem = samplecode[i][c]; |
| code = codem & 0x03; |
| |
| /* adjust the step table index */ |
| stepindex[c] += dvi_adpcm_indextab3[code]; |
| /* check for step table index overflow and underflow */ |
| if (stepindex[c] > 88) |
| stepindex[c] = 88; |
| else if (stepindex[c] < 0) |
| stepindex[c] = 0; |
| /* calculate the difference */ |
| #ifdef STRICT_IMA |
| diff = 0; |
| if (code & 2) |
| diff += step; |
| step = step >> 1; |
| if (code & 1) |
| diff += step; |
| step = step >> 1; |
| diff += step; |
| #else |
| diff = ((code + code + 1) * step) >> 3; /* faster */ |
| #endif |
| /* check the sign bit */ |
| /* check for overflow and underflow errors */ |
| if (code != codem) { |
| sample[c] -= diff; |
| if (sample[c] < -32768) |
| sample[c] = -32768; |
| } |
| else { |
| sample[c] += diff; |
| if (sample[c] > 32767) |
| sample[c] = 32767; |
| } |
| /* output the new sample */ |
| pcmout[nsamples] = sample[c] << 13; |
| nsamples++; |
| } |
| } |
| } |
| } |
| |
| if (nsamples > *pcmoutsize) { |
| DEBUGF("decode_dvi_adpcm: output buffer overflow!\n"); |
| return CODEC_ERROR; |
| } |
| *pcmoutsize = nsamples; |
| if (n != 0) { |
| DEBUGF("decode_dvi_adpcm: n=%d unprocessed bytes\n", n); |
| } |
| return CODEC_OK; |
| } |
| |