summaryrefslogtreecommitdiff
path: root/src/libxineadec/adpcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libxineadec/adpcm.c')
-rw-r--r--src/libxineadec/adpcm.c244
1 files changed, 240 insertions, 4 deletions
diff --git a/src/libxineadec/adpcm.c b/src/libxineadec/adpcm.c
index 12ac4c6da..87b03b4dd 100644
--- a/src/libxineadec/adpcm.c
+++ b/src/libxineadec/adpcm.c
@@ -23,8 +23,15 @@
* formats that various entities have created. Details about the data
* formats can be found here:
* http://www.pcisys.net/~melanson/codecs/
+ * CD-ROM/XA ADPCM decoder by Stuart Caie (kyzer@4u.net)
+ * - based on information in the USENET post by Jac Goudsmit (jac@codim.nl)
+ * <01bbc34c$dbf64020$f9c8a8c0@cray.codim.nl>
+ * - tested for correctness using Jon Atkins's CDXA software:
+ * http://jonatkins.org/cdxa/
+ * this is also useful for extracting streams from Playstation discs
*
- * $Id: adpcm.c,v 1.28 2003/02/14 00:55:52 miguelfreitas Exp $
+ *
+ * $Id: adpcm.c,v 1.29 2003/02/14 04:32:28 tmmm Exp $
*/
#include <stdio.h>
@@ -83,6 +90,10 @@ static int ea_adpcm_table[] = {
3, 4, 7, 8, 10, 11, 0, -1, -3, -4
};
+static int xa_adpcm_table[] = {
+ 0, 240, 460, 392, 0, 0, -208, -220
+};
+
#define QT_IMA_ADPCM_PREAMBLE_SIZE 2
#define QT_IMA_ADPCM_BLOCK_SIZE 0x22
#define QT_IMA_ADPCM_SAMPLES_PER_BLOCK \
@@ -134,6 +145,12 @@ typedef struct adpcm_decoder_s {
unsigned int in_block_size;
unsigned int out_block_size; /* size in samples (2 bytes/sample) */
+ int xa_mode; /* 1 for mode A, 0 for mode B or mode C */
+ int xa_p_l; /* previous sample, left/mono channel */
+ int xa_p_r; /* previous sample, right channel */
+ int xa_pp_l; /* 2nd-previous sample, left/mono channel */
+ int xa_pp_r; /* 2nd-previous sample, right channel */
+
} adpcm_decoder_t;
/*
@@ -1147,6 +1164,202 @@ static void dialogic_ima_decode_block(adpcm_decoder_t *this, buf_element_t *buf)
this->size = 0;
}
+
+static void xa_adpcm_decode_block(adpcm_decoder_t *this, buf_element_t *buf) {
+ int32_t p_l, pp_l, coeff_p_l, coeff_pp_l, range_l;
+ int32_t p_r, pp_r, coeff_p_r, coeff_pp_r, range_r;
+ int32_t snd_group, snd_unit, snd_data, samp, i, j;
+ uint8_t *inp;
+
+ /* restore decoding history */
+ p_l = this->xa_p_l; pp_l = this->xa_pp_l;
+ p_r = this->xa_p_r; pp_r = this->xa_pp_r;
+
+ inp = &this->buf[0];
+ j = 0;
+
+ if (this->xa_mode) {
+ if (this->channels == 2) {
+ /* mode A (8 bits per sample / 4 sound units) stereo
+ * - sound units 0,2 are left channel, 1,3 are right channel
+ * - sound data (8 bits) is shifted left to 16-bit border, then
+ * shifted right by the range parameter, therefore it's shifted
+ * (8-range) bits left.
+ * - two coefficients tables (4 entries each) are merged into one
+ * - coefficients are multiples of 1/256, so '>> 8' is applied
+ * after multiplication to get correct answer.
+ */
+ for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) {
+ for (snd_unit = 0; snd_unit < 4; snd_unit += 2) {
+ /* get left channel coeffs and range */
+ coeff_p_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3)];
+ coeff_pp_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3) + 4];
+ range_l = 8 - (inp[snd_unit] & 0xF);
+
+ /* get right channel coeffs and range */
+ coeff_p_r = xa_adpcm_table[((inp[snd_unit+1] >> 4) & 0x3)];
+ coeff_pp_r = xa_adpcm_table[((inp[snd_unit+1] >> 4) & 0x3) + 4];
+ range_r = 8 - (inp[snd_unit+1] & 0xF);
+
+ for (snd_data = 0; snd_data < 28; snd_data++) {
+ /* left channel */
+ samp = ((signed char *)inp)[16 + (snd_data << 2) + snd_unit];
+ samp <<= range_l;
+ samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8;
+ CLAMP_S16(samp);
+ pp_l = p_l;
+ p_l = samp;
+ this->decode_buffer[j++] = (unsigned short) samp;
+
+ /* right channel */
+ samp = ((signed char *)inp)[16 + (snd_data << 2) + snd_unit+1];
+ samp <<= range_r;
+ samp += (coeff_p_r * p_r + coeff_pp_r * pp_r) >> 8;
+ CLAMP_S16(samp);
+ pp_r = p_r;
+ p_r = samp;
+ this->decode_buffer[j++] = (unsigned short) samp;
+ }
+ }
+ }
+ }
+ else {
+ /* mode A (8 bits per sample / 4 sound units) mono
+ * - other details as before
+ */
+ for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) {
+ for (snd_unit = 0; snd_unit < 4; snd_unit++) {
+ /* get coeffs and range */
+ coeff_p_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3)];
+ coeff_pp_l = xa_adpcm_table[((inp[snd_unit] >> 4) & 0x3) + 4];
+ range_l = 8 - (inp[snd_unit] & 0xF);
+
+ for (snd_data = 0; snd_data < 28; snd_data++) {
+ samp = ((signed char *)inp)[16 + (snd_data << 2) + snd_unit];
+ samp <<= range_l;
+ samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8;
+ CLAMP_S16(samp);
+ pp_l = p_l; p_l = samp;
+ this->decode_buffer[j++] = (unsigned short) samp;
+ }
+ }
+ }
+ }
+ }
+ else {
+ if (this->channels == 2) {
+ /* mode B/C (4 bits per sample / 8 sound units) stereo
+ * - sound units 0,2,4,6 are left channel, 1,3,5,7 are right channel
+ * - sound parameters 0-7 are stored as 16 bytes in the order
+ * "0123012345674567", so inp[x+4] gives sound parameter x while
+ * inp[x] doesn't.
+ * - sound data (4 bits) is shifted left to 16-bit border, then
+ * shifted right by the range parameter, therefore it's shifted
+ * (12-range) bits left.
+ * - other details as before
+ */
+ for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) {
+ for (snd_unit = 0; snd_unit < 8; snd_unit += 2) {
+ /* get left channel coeffs and range */
+ coeff_p_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3)];
+ coeff_pp_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3) + 4];
+ range_l = 12 - (inp[snd_unit+4] & 0xF);
+
+ /* get right channel coeffs and range */
+ coeff_p_r = xa_adpcm_table[((inp[snd_unit+5] >> 4) & 0x3)];
+ coeff_pp_r = xa_adpcm_table[((inp[snd_unit+5] >> 4) & 0x3) + 4];
+ range_r = 12 - (inp[snd_unit+5] & 0xF);
+
+ for (snd_data = 0; snd_data < 28; snd_data++) {
+ /* left channel */
+ samp = (inp[16 + (snd_data << 2) + (snd_unit >> 1)]) & 0xF;
+ SE_4BIT(samp);
+ samp <<= range_l;
+ samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8;
+ CLAMP_S16(samp);
+ pp_l = p_l;
+ p_l = samp;
+ this->decode_buffer[j++] = (unsigned short) samp;
+
+ /* right channel */
+ samp = (inp[16 + (snd_data << 2) + (snd_unit >> 1)] >> 4) & 0xF;
+ SE_4BIT(samp);
+ samp <<= range_r;
+ samp += (coeff_p_r * p_r + coeff_pp_r * pp_r) >> 8;
+ CLAMP_S16(samp);
+ pp_r = p_r;
+ p_r = samp;
+ this->decode_buffer[j++] = (unsigned short) samp;
+ }
+ }
+ }
+ }
+ else {
+ /* mode B or C (4 bits per sample / 8 sound units) mono
+ * - other details as before
+ */
+ for (snd_group = 0; snd_group < 18; snd_group++, inp += 128) {
+ for (snd_unit = 0; snd_unit < 8; snd_unit++) {
+ /* get coeffs and range */
+ coeff_p_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3)];
+ coeff_pp_l = xa_adpcm_table[((inp[snd_unit+4] >> 4) & 0x3) + 4];
+ range_l = 12 - (inp[snd_unit+4] & 0xF);
+
+ for (snd_data = 0; snd_data < 28; snd_data++) {
+ samp = inp[16 + (snd_data << 2) + (snd_unit >> 1)];
+ if (snd_unit & 1) samp >>= 4; samp &= 0xF;
+ SE_4BIT(samp);
+ samp <<= range_l;
+ samp += (coeff_p_l * p_l + coeff_pp_l * pp_l) >> 8;
+ CLAMP_S16(samp);
+ pp_l = p_l;
+ p_l = samp;
+ this->decode_buffer[j++] = (unsigned short) samp;
+ }
+ }
+ }
+ }
+ }
+
+ /* store decoding history */
+ this->xa_p_l = p_l; this->xa_pp_l = pp_l;
+ this->xa_p_r = p_r; this->xa_pp_r = pp_r;
+
+ /* despatch the decoded audio */
+ i = 0;
+ while (i < j) {
+ audio_buffer_t *audio_buffer;
+ int bytes_to_send;
+
+ audio_buffer= this->stream->audio_out->get_buffer(this->stream->audio_out);
+ if (audio_buffer->mem_size == 0) {
+ printf ("adpcm: Help! Allocated audio buffer with nothing in it!\n");
+ return;
+ }
+
+ if (((j - i) * 2) > audio_buffer->mem_size) {
+ bytes_to_send = audio_buffer->mem_size;
+ }
+ else {
+ bytes_to_send = (j - i) * 2;
+ }
+
+ xine_fast_memcpy(audio_buffer->mem, &this->decode_buffer[i],
+ bytes_to_send);
+
+ audio_buffer->num_frames = bytes_to_send / (2 * this->channels);
+ audio_buffer->vpts = buf->pts;
+ buf->pts = 0;
+ this->stream->audio_out->put_buffer(this->stream->audio_out,
+ audio_buffer, this->stream);
+
+ i += bytes_to_send / 2;
+ }
+
+ /* reset input buffer */
+ this->size = 0;
+}
+
static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
adpcm_decoder_t *this = (adpcm_decoder_t *) this_gen;
@@ -1163,7 +1376,7 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
this->size = 0;
/* load the stream information */
- switch (buf->type) {
+ switch (buf->type & 0xFFFF0000) {
case BUF_AUDIO_MSADPCM:
this->stream->meta_info[XINE_META_INFO_AUDIOCODEC] =
@@ -1210,6 +1423,11 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
strdup("Dialogic IMA ADPCM");
break;
+ case BUF_AUDIO_XA_ADPCM:
+ this->stream->meta_info[XINE_META_INFO_AUDIOCODEC] =
+ strdup("CD-ROM/XA ADPCM");
+ break;
+
}
/* if the data was transported in an MS-type file (packet size will be
@@ -1274,6 +1492,20 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
this->decode_buffer = xine_xmalloc(this->out_block_size * 2);
}
+ /* XA blocks are always 2304 bytes of input data. For output, there
+ * are 18 sound groups. These sound groups have 4 sound units (mode A)
+ * or 8 sound units (mode B or mode C). The sound units have 28 sound
+ * data samples. So, either 18*4*28=2016 or 18*8*28=4032 samples per
+ * sector. 2 bytes per sample means 4032 or 8064 bytes per sector.
+ */
+ if ((buf->type & 0xFFFF0000) == BUF_AUDIO_XA_ADPCM) {
+ /* initialise decoder state */
+ this->xa_mode = buf->decoder_info[2];
+ this->xa_p_l = this->xa_pp_l = this->xa_p_r = this->xa_pp_r = 0;
+ /* allocate 2 bytes per sample */
+ this->decode_buffer = xine_xmalloc((this->xa_mode) ? 4032 : 8064);
+ }
+
return;
}
@@ -1302,7 +1534,7 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
/* time to decode a frame */
if (buf->decoder_flags & BUF_FLAG_FRAME_END) {
- switch(buf->type) {
+ switch(buf->type & 0xFFFF0000) {
case BUF_AUDIO_MSADPCM:
ms_adpcm_decode_block(this, buf);
@@ -1339,6 +1571,10 @@ static void adpcm_decode_data (audio_decoder_t *this_gen, buf_element_t *buf) {
case BUF_AUDIO_DIALOGIC_IMA:
dialogic_ima_decode_block(this, buf);
break;
+
+ case BUF_AUDIO_XA_ADPCM:
+ xa_adpcm_decode_block(this, buf);
+ break;
}
}
}
@@ -1428,7 +1664,7 @@ static uint32_t audio_types[] = {
BUF_AUDIO_QTIMAADPCM, BUF_AUDIO_DK3ADPCM,
BUF_AUDIO_DK4ADPCM, BUF_AUDIO_SMJPEG_IMA,
BUF_AUDIO_VQA_IMA, BUF_AUDIO_EA_ADPCM,
- BUF_AUDIO_DIALOGIC_IMA,
+ BUF_AUDIO_DIALOGIC_IMA, BUF_AUDIO_XA_ADPCM,
0
};