diff src/tta/ttadec.c @ 290:fbd06b4aa776 trunk

[svn] - add TrueAudio plugin
author yaz
date Wed, 22 Nov 2006 09:55:20 -0800
parents
children c0f69d57483b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tta/ttadec.c	Wed Nov 22 09:55:20 2006 -0800
@@ -0,0 +1,506 @@
+/*
+ * ttadec.c
+ *
+ * Description:	 TTAv1 decoder library for HW players.
+ * Developed by: Alexander Djourik <sasha@iszf.irk.ru>
+ *               Pavel Zhilin <pzh@iszf.irk.ru>
+ *
+ * Copyright (c) 1999-2004 Alexander Djourik. All rights reserved.
+ *
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Please see the file COPYING in this directory for full copyright
+ * information.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ttalib.h"
+#include "ttadec.h"
+#include "crc32.h"
+#include "filters.h"
+
+/******************* static variables and structures *******************/
+
+static unsigned char isobuffers[ISO_BUFFERS_SIZE + 4];
+static unsigned char *iso_buffers_end = isobuffers + ISO_BUFFERS_SIZE;
+static unsigned long pcm_buffer_size;
+
+static decoder	tta[MAX_NCH];	// decoder state
+static long	cache[MAX_NCH];		// decoder cache
+
+tta_info *ttainfo;	// currently playing file info
+
+static unsigned long fframes;	// number of frames in file
+static unsigned long framelen;	// the frame length in samples
+static unsigned long lastlen;	// the length of the last frame in samples
+static unsigned long data_pos;	// currently playing frame index
+static unsigned long data_cur;	// the playing position in frame
+
+static long maxvalue;	// output data max value
+static unsigned long *seek_table; // the playing position table
+static unsigned long st_state; //seek table status
+
+static unsigned long frame_crc32;
+static unsigned long bit_count;
+static unsigned long bit_cache;
+static unsigned char *bitpos;
+static unsigned long bitrate;
+
+void get_id3v1_tag (tta_info *ttainfo);
+int  get_id3v2_tag (tta_info *ttainfo);
+
+/************************* bit operations ******************************/
+
+static void init_buffer_read() {
+    frame_crc32 = 0xFFFFFFFFUL;
+    bit_count = bit_cache = 0;
+    bitpos = iso_buffers_end;
+}
+
+__inline void get_binary(unsigned long *value, unsigned long bits) {
+    while (bit_count < bits) {
+		if (bitpos == iso_buffers_end) {
+			long res = fread(isobuffers, 1,
+				ISO_BUFFERS_SIZE, ttainfo->HANDLE);
+			if (!res) {
+				ttainfo->STATE = READ_ERROR;
+				return;
+			}
+			bitpos = isobuffers;
+		}
+
+		UPDATE_CRC32(*bitpos, frame_crc32);
+		bit_cache |= *bitpos << bit_count;
+		bit_count += 8;
+		bitpos++;
+    }
+
+    *value = bit_cache & bit_mask[bits];
+    bit_cache >>= bits;
+    bit_count -= bits;
+    bit_cache &= bit_mask[bit_count];
+}
+
+__inline void get_unary(unsigned long *value) {
+    *value = 0;
+
+    while (!(bit_cache ^ bit_mask[bit_count])) {
+		if (bitpos == iso_buffers_end) {
+			long res = fread(isobuffers, 1,
+				ISO_BUFFERS_SIZE, ttainfo->HANDLE);
+			if (!res) {
+				ttainfo->STATE = READ_ERROR;
+				return;
+			}
+			bitpos = isobuffers;
+		}
+
+		*value += bit_count;
+		bit_cache = *bitpos++;
+		UPDATE_CRC32(bit_cache, frame_crc32);
+		bit_count = 8;
+    }
+
+    while (bit_cache & 1) {
+		(*value)++;
+		bit_cache >>= 1;
+		bit_count--;
+    }
+
+    bit_cache >>= 1;
+    bit_count--;
+}
+
+static long done_buffer_read() {
+    unsigned long crc32, rbytes, res;
+    frame_crc32 ^= 0xFFFFFFFFUL;
+
+    rbytes = iso_buffers_end - bitpos;
+    if (rbytes < sizeof(long)) {
+		memcpy(isobuffers, bitpos, 4);
+		res = fread(isobuffers + rbytes, 1,
+			ISO_BUFFERS_SIZE - rbytes, ttainfo->HANDLE);
+		if (!res) {
+			ttainfo->STATE = READ_ERROR;
+			return 0;
+		}
+		bitpos = isobuffers;
+    }
+
+    memcpy(&crc32, bitpos, 4);
+    crc32 = ENDSWAP_INT32(crc32);
+    bitpos += sizeof(long);
+    res = (crc32 != frame_crc32);
+
+    bit_cache = bit_count = 0;
+    frame_crc32 = 0xFFFFFFFFUL;
+
+    // calculate dynamic bitrate
+    if (data_pos < fframes) {
+		rbytes = seek_table[data_pos] -
+			seek_table[data_pos - 1];
+		bitrate = (rbytes << 3) / 1070;
+    }
+
+    return res;
+}
+
+/************************* decoder functions ****************************/
+
+static long skip_id3v2_header (FILE *infile) {
+	struct {
+		unsigned char	id[3];
+		unsigned short	version;
+		unsigned char	flags;
+		unsigned char	size[4];
+	} __ATTRIBUTE_PACKED__ id3v2;
+	unsigned long len = 0;
+
+	// read ID3V2 header
+	if (fread (&id3v2, sizeof(id3v2), 1, infile) == 0) {
+		fclose (infile);
+		ttainfo->STATE = READ_ERROR;
+		return -1;
+	}
+
+	// skip ID3V2 header
+	if (!memcmp (id3v2.id, "ID3", 3)) {
+		if (id3v2.size[0] & 0x80) {
+			fclose (infile);
+			ttainfo->STATE = FILE_ERROR;
+			return FILE_ERROR;
+		}
+		len = (id3v2.size[0] & 0x7f);
+		len = (len << 7) | (id3v2.size[1] & 0x7f);
+		len = (len << 7) | (id3v2.size[2] & 0x7f);
+		len = (len << 7) | (id3v2.size[3] & 0x7f);
+		len += 10;
+		if (id3v2.flags & (1 << 4)) len += 10;
+		fseek (infile, len, SEEK_SET);
+	} else fseek (infile, 0, SEEK_SET);
+
+	return len;
+}
+
+long open_tta_file (const char *filename, tta_info *info, unsigned long data_offset) {
+	FILE *infile;
+	tta_hdr ttahdr;
+	unsigned long checksum;
+
+	// clear the memory
+	memset (info, 0, sizeof(tta_info));
+
+//	printf("0: open_tta_file\n");
+	info->HANDLE = infile = fopen(filename, "rb");
+	if (!infile) return OPEN_ERROR;
+
+//	printf("1: data_offset %ld\n", data_offset);
+	// read id3v2 header
+	if (!data_offset) {
+//		data_offset = skip_id3v2_header(infile);
+//		data_offset = get_id3v2_tag(info);
+		data_offset = skip_v2_header(info);
+//		printf("2: data_offset %ld\n", data_offset);
+//		get_id3v1_tag (info);
+		if (data_offset < 0) return -1;
+	} else fseek (infile, data_offset, SEEK_SET);
+
+	get_id3_tags (filename, info);
+
+	// read TTA header
+	if (fread (&ttahdr, 1, sizeof (ttahdr), infile) == 0) {
+		fclose (infile);
+		info->STATE = READ_ERROR;
+		return -1;
+	}
+
+	// check for TTA3 signature
+	if (ENDSWAP_INT32(ttahdr.TTAid) != TTA1_SIGN) {
+		fclose (infile);
+		info->STATE = FORMAT_ERROR;
+		return -1;
+	}
+
+	ttahdr.CRC32 = ENDSWAP_INT32(ttahdr.CRC32);
+	checksum = crc32((unsigned char *) &ttahdr,
+	sizeof(tta_hdr) - sizeof(long));
+	if (checksum != ttahdr.CRC32) {
+		fclose (infile);
+		info->STATE = FILE_ERROR;
+		return -1;
+	}
+
+	ttahdr.AudioFormat = ENDSWAP_INT16(ttahdr.AudioFormat);
+	ttahdr.NumChannels = ENDSWAP_INT16(ttahdr.NumChannels);
+	ttahdr.BitsPerSample = ENDSWAP_INT16(ttahdr.BitsPerSample);
+	ttahdr.SampleRate = ENDSWAP_INT32(ttahdr.SampleRate);
+	ttahdr.DataLength = ENDSWAP_INT32(ttahdr.DataLength);
+
+	// check for player supported formats
+	if (ttahdr.AudioFormat != WAVE_FORMAT_PCM ||
+		ttahdr.NumChannels > MAX_NCH ||
+		ttahdr.BitsPerSample > MAX_BPS ||(
+		ttahdr.SampleRate != 16000 &&
+		ttahdr.SampleRate != 22050 &&
+		ttahdr.SampleRate != 24000 &&
+		ttahdr.SampleRate != 32000 &&
+		ttahdr.SampleRate != 44100 &&
+		ttahdr.SampleRate != 48000 &&
+		ttahdr.SampleRate != 64000 &&
+		ttahdr.SampleRate != 88200 &&
+		ttahdr.SampleRate != 96000)) {
+		fclose (infile);
+		info->STATE = FORMAT_ERROR;
+		return FORMAT_ERROR;
+	}
+
+	// fill the File Info
+	info->HANDLE = infile;
+	info->NCH = ttahdr.NumChannels;
+	info->BPS = ttahdr.BitsPerSample;
+	info->BSIZE = (ttahdr.BitsPerSample + 7)/8;
+	info->FORMAT = ttahdr.AudioFormat;
+	info->SAMPLERATE = ttahdr.SampleRate;
+	info->DATALENGTH = ttahdr.DataLength;
+	info->FRAMELEN = (long) (FRAME_TIME * ttahdr.SampleRate);
+	info->LENGTH = ttahdr.DataLength / ttahdr.SampleRate;
+	info->DATAPOS = data_offset;
+
+
+	return 0;
+}
+
+static void rice_init(adapt *rice, unsigned long k0, unsigned long k1) {
+    rice->k0 = k0;
+    rice->k1 = k1;
+    rice->sum0 = shift_16[k0];
+    rice->sum1 = shift_16[k1];
+}
+
+static void decoder_init(decoder *tta, long nch, long byte_size) {
+    long shift = flt_set[byte_size - 1];
+    long i;
+
+    for (i = 0; i < nch; i++) {
+		filter_init(&tta[i].fst, shift);
+		rice_init(&tta[i].rice, 10, 10);
+		tta[i].last = 0;
+    }
+}
+
+static void seek_table_init (unsigned long *seek_table,
+	unsigned long len, unsigned long data_offset) {
+	unsigned long *st, frame_len;
+
+	for (st = seek_table; st < (seek_table + len); st++) {
+		frame_len = ENDSWAP_INT32(*st);
+		*st = data_offset;
+		data_offset += frame_len;
+	}
+}
+
+long set_position (unsigned long pos) {
+	unsigned long seek_pos;
+
+	if (pos >= fframes) return 0;
+	if (!st_state) {
+		ttainfo->STATE = FILE_ERROR;
+		return -1;
+	}
+
+	seek_pos = ttainfo->DATAPOS + seek_table[data_pos = pos];
+	fseek(ttainfo->HANDLE, seek_pos, SEEK_SET);
+
+	data_cur = 0;
+	framelen = 0;
+
+	// init bit reader
+	init_buffer_read();
+
+	return 0;
+}
+
+long player_init (tta_info *info) {
+	unsigned long checksum;
+	unsigned long data_offset;
+	unsigned long st_size;
+
+	ttainfo = info;
+
+	framelen = 0;
+	data_pos = 0;
+	data_cur = 0;
+	bitrate  = 0;
+
+	lastlen = ttainfo->DATALENGTH % ttainfo->FRAMELEN;
+	fframes = ttainfo->DATALENGTH / ttainfo->FRAMELEN + (lastlen ? 1:0);
+	st_size = (fframes + 1) * sizeof(long);
+
+	seek_table = (unsigned long *) malloc(st_size);
+	if (!seek_table) {
+		ttainfo->STATE = MEMORY_ERROR;
+		return -1;
+	}
+
+	// read seek table
+	if (!fread(seek_table, st_size, 1, ttainfo->HANDLE)) {
+		ttainfo->STATE = READ_ERROR;
+		return -1;
+	}
+
+	checksum = crc32((unsigned char *) seek_table, st_size - sizeof(long));
+	st_state = (checksum == ENDSWAP_INT32(seek_table[fframes]));
+	data_offset = sizeof(tta_hdr) + st_size;
+
+	// init seek table
+	seek_table_init(seek_table, fframes, data_offset);
+
+	// init bit reader
+	init_buffer_read();
+
+	pcm_buffer_size = PCM_BUFFER_LENGTH * ttainfo->BSIZE * ttainfo->NCH;
+	maxvalue = (1UL << ttainfo->BPS) - 1;
+
+	return 0;
+}
+
+void close_tta_file (tta_info *info) {
+	if (info->HANDLE) {
+		fclose (info->HANDLE);
+		info->HANDLE = NULL;
+	}
+}
+
+void player_stop () {
+	if (seek_table) {
+		free(seek_table);
+		seek_table = NULL;
+	}
+}
+
+long get_bitrate () {
+	return bitrate;
+}
+
+long get_samples (byte *buffer) {
+	unsigned long k, depth, unary, binary;
+	byte *p = buffer;
+	decoder *dec = tta;
+	long *prev = cache;
+	long value, res;
+
+	for (res = 0; p < buffer + pcm_buffer_size;) {
+		fltst *fst = &dec->fst;
+		adapt *rice = &dec->rice;
+		long  *last = &dec->last;
+
+		if (data_cur == framelen) {
+			if (data_pos == fframes) break;
+			if (framelen && done_buffer_read()) {
+				if (set_position(data_pos) < 0)
+					return -1;
+				if (res) break;
+			}
+
+			if (data_pos == fframes - 1 && lastlen)
+				framelen = lastlen;
+			else framelen = ttainfo->FRAMELEN;
+
+			decoder_init(tta, ttainfo->NCH, ttainfo->BSIZE);
+			data_pos++; data_cur = 0;
+		}
+
+		// decode Rice unsigned
+		get_unary(&unary);
+
+		switch (unary) {
+		case 0: depth = 0; k = rice->k0; break;
+		default:
+				depth = 1; k = rice->k1;
+				unary--;
+		}
+
+		if (k) {
+			get_binary(&binary, k);
+			value = (unary << k) + binary;
+		} else value = unary;
+
+		switch (depth) {
+		case 1: 
+			rice->sum1 += value - (rice->sum1 >> 4);
+			if (rice->k1 > 0 && rice->sum1 < shift_16[rice->k1])
+				rice->k1--;
+			else if (rice->sum1 > shift_16[rice->k1 + 1])
+				rice->k1++;
+			value += bit_shift[rice->k0];
+		default:
+			rice->sum0 += value - (rice->sum0 >> 4);
+			if (rice->k0 > 0 && rice->sum0 < shift_16[rice->k0])
+				rice->k0--;
+			else if (rice->sum0 > shift_16[rice->k0 + 1])
+			rice->k0++;
+		}
+
+		value = DEC(value);
+
+		// decompress stage 1: adaptive hybrid filter
+		hybrid_filter(fst, &value);
+
+		// decompress stage 2: fixed order 1 prediction
+		switch (ttainfo->BSIZE) {
+		case 1: value += PREDICTOR1(*last, 4); break;	// bps 8
+		case 2: value += PREDICTOR1(*last, 5); break;	// bps 16
+		case 3: value += PREDICTOR1(*last, 5); break;	// bps 24
+		case 4: value += *last; break;		// bps 32
+		} *last = value;
+
+		// check for errors
+		if (abs(value) > maxvalue) {
+			unsigned long tail =
+				pcm_buffer_size / (ttainfo->BSIZE * ttainfo->NCH) - res;
+			memset(buffer, 0, pcm_buffer_size);
+			data_cur += tail; res += tail;
+			break;
+		}
+
+		if (dec < tta + (ttainfo->NCH - 1)) {
+			*prev++ = value; dec++;
+		} else {
+			*prev = value;
+			if (ttainfo->NCH > 1) {
+				long *r = prev - 1;
+				for (*prev += *r/2; r >= cache; r--)
+					*r = *(r + 1) - *r;
+				for (r = cache; r < prev; r++)
+					WRITE_BUFFER(r, ttainfo->BSIZE, p)
+			}
+			WRITE_BUFFER(prev, ttainfo->BSIZE, p)
+			prev = cache;
+			data_cur++; res++;
+			dec = tta;
+		}
+	}
+
+	return res;
+}
+
+/* end */
+