add True Audio (TTA) codec

decoding speed iPod video ~153%
But in some players, the decoding speed is not enough.
(e.g., H180 52.4% (thanks amiconn), H300 55.09% (thanks n1s))

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@25994 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Yoshihisa Uchida 2010-05-13 12:40:09 +00:00
parent 889b4a8ce8
commit 0f5c6d47d4
19 changed files with 1689 additions and 1 deletions

View file

@ -197,6 +197,7 @@ metadata/oma.c
metadata/smaf.c
metadata/au.c
metadata/vox.c
metadata/tta.c
#endif
#ifdef HAVE_TAGCACHE
tagcache.c

View file

@ -32,6 +32,7 @@ smaf.c
au.c
vox.c
wav64.c
tta.c
#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
/* encoders */
aiff_enc.c

View file

@ -41,6 +41,7 @@ include $(APPSDIR)/codecs/libcook/libcook.make
include $(APPSDIR)/codecs/librm/librm.make
include $(APPSDIR)/codecs/libatrac/libatrac.make
include $(APPSDIR)/codecs/libpcm/libpcm.make
include $(APPSDIR)/codecs/libtta/libtta.make
# compile flags for codecs
CODECFLAGS = $(filter-out -fno-strict-aliasing,$(CFLAGS)) -fstrict-aliasing \
@ -96,6 +97,7 @@ $(CODECDIR)/smaf.codec : $(CODECDIR)/libpcm.a
$(CODECDIR)/au.codec : $(CODECDIR)/libpcm.a
$(CODECDIR)/vox.codec : $(CODECDIR)/libpcm.a
$(CODECDIR)/wav64.codec : $(CODECDIR)/libpcm.a
$(CODECDIR)/tta.codec : $(CODECDIR)/libtta.a
$(CODECS): $(CODECLIB) # this must be last in codec dependency list

72
apps/codecs/libtta/README Normal file
View file

@ -0,0 +1,72 @@
TTA Hardware Players Library
============================
Version 1.2, (c) 2004 Alexander Djourik. All rights reserved.
* Introduction
This library provides to decode a multichannel 8,16 and 24
bits TTA audio files. TTA is a lossless audio format. Being
"lossless" means that no data/quality is lost in the compression
- when uncompressed, the data will be identical to the original.
The compression ratios of TTA depend on the type of music file
being compressed, but the compression size will generally range
between 30% - 70% of the original.
TTA format supports both of ID3v1/v2 tags. Detailed format
description is available at http://www.true-audio.com.
The decoder process has a minimal system requirements and does
not required to create a big additional memory pools. As the
TTA algorithms has a same system requirements both for decoding
and for encoding processes - the TTA recorder can be easily
realized also.
* Changes
14/04/2004 1.0 Initial release
16/04/2004 1.1 Code optimization
Code clean-up
29/10/2004 1.2 ID3 tags support
Code clean-up
* To Do
- TTA recorder functions.
* Developers
Alexander Djourik <ald@true-audio.com>
Pavel Zhilin <pzh@true-audio.com>
* Copying
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the True Audio Software nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* See also
Please visit the TTA homepage at http://tta.sourceforge.net for the
latest in news and downloads.

View file

@ -0,0 +1,34 @@
Library: True Audio
Imported by : Yoshihisa Uchida
Import date : 2010-03-05
Baseed by : TTA library version 1.2 for hardware players (ttalib-hwplayer-1.2.tgz)
from http://true-audio.com/Free_Downloads
This directory contains a decoder version of True Auido.
LICENSING INFORMATION
True Audio license is described in the README file or each source file (excepts filter_arm.S)
in this directory.
Limitation
In some players, the decoding speed is not enough ( < 110%).
(For example, H180: decoding speed < 60%)
IMPORT DETAILS
The .[ch] files from ttalib-hwplayer-1.2.tgz were imported into Rockbox.
But the following files do not include.
Makefile
tta.vcproj
samples/*
When source files import in Rockbox, I changed below.
all files
- TAB => 4 spaces.
- // style comments changes to /* */ style.
Moreover, I modify to optimize the decoding speed.

View file

@ -0,0 +1,4 @@
ttadec.c
#ifdef CPU_ARM
filter_arm.S
#endif

136
apps/codecs/libtta/filter.h Normal file
View file

@ -0,0 +1,136 @@
/*
* filter.h
*
* Description: TTAv1 filter functions
* Developed by: Alexander Djourik <ald@true-audio.com>
* Pavel Zhilin <pzh@true-audio.com>
*
* Copyright (c) 2004 True Audio Software. All rights reserved.
*
*/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the True Audio Software nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FILTER_H
#define FILTER_H
///////// Filter Settings //////////
static int flt_set[3] = {10, 9, 10};
#ifdef CPU_ARM
int hybrid_filter(fltst *fs, int *in); /* implements in filter_arm.S */
#else
static inline void
memshl (register int *pA) {
register int *pB = pA + 16;
*pA++ = *pB++;
*pA++ = *pB++;
*pA++ = *pB++;
*pA++ = *pB++;
*pA++ = *pB++;
*pA++ = *pB++;
*pA++ = *pB++;
*pA = *pB;
}
static inline void
hybrid_filter (fltst *fs, int *in) {
register int *pA = fs->dl + fs->index;
register int *pB = fs->qm;
register int *pM = fs->dx + fs->index;
register int sum = fs->round;
if (!fs->error) {
sum += *pA++ * *pB++;
sum += *pA++ * *pB++;
sum += *pA++ * *pB++;
sum += *pA++ * *pB++;
sum += *pA++ * *pB++;
sum += *pA++ * *pB++;
sum += *pA++ * *pB++;
sum += *pA * *pB;
pM += 8;
} else if (fs->error < 0) {
sum += *pA++ * (*pB++ -= *pM++);
sum += *pA++ * (*pB++ -= *pM++);
sum += *pA++ * (*pB++ -= *pM++);
sum += *pA++ * (*pB++ -= *pM++);
sum += *pA++ * (*pB++ -= *pM++);
sum += *pA++ * (*pB++ -= *pM++);
sum += *pA++ * (*pB++ -= *pM++);
sum += *pA * (*pB -= *pM++);
} else {
sum += *pA++ * (*pB++ += *pM++);
sum += *pA++ * (*pB++ += *pM++);
sum += *pA++ * (*pB++ += *pM++);
sum += *pA++ * (*pB++ += *pM++);
sum += *pA++ * (*pB++ += *pM++);
sum += *pA++ * (*pB++ += *pM++);
sum += *pA++ * (*pB++ += *pM++);
sum += *pA * (*pB += *pM++);
}
pB = pA++;
fs->error = *in;
*in += (sum >> fs->shift);
*pA = *in;
*pM-- = ((*pB-- >> 30) | 1) << 2;
*pM-- = ((*pB-- >> 30) | 1) << 1;
*pM-- = ((*pB-- >> 30) | 1) << 1;
*pM = ((*pB >> 30) | 1);
*(pA-1) = *(pA-0) - *(pA-1);
*(pA-2) = *(pA-1) - *(pA-2);
*(pA-3) = *(pA-2) - *(pA-3);
/*
* Rockbox speciffic
* in order to make speed up, memshl() is executed at the rate once every 16 times.
*/
if (++fs->index == 16)
{
memshl (fs->dl);
memshl (fs->dx);
fs->index = 0;
}
}
#endif
static inline void
filter_init (fltst *fs, int shift) {
ci->memset (fs, 0, sizeof(fltst));
fs->shift = shift;
fs->round = 1 << (shift - 1);
fs->index = 0;
}
#endif /* FILTER_H */

View file

@ -0,0 +1,203 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Yoshihisa Uchida
*
* 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 "config.h"
/*
* The following are assembler optimised version of
* void hybrid_filter(fltst *fs, int *in)
*/
#ifdef USE_IRAM
.section .icode, "ax", %progbits
#else
.text
#endif
.align
.global hybrid_filter
.type hybrid_filter, %function
hybrid_filter:
@ input: r0 = fs, r1 = in
stmdb sp!, {r4 - r12, lr}
@ get fs members
@ r2 pA := fs->dl + fs->index
@ r3 pM := fs->dx + fs->index
@ r4 pB := fs->qm
@ r5 fs->index
@ r6 fs->error
@ lr sum := fs->round
add r2, r0, #148 @ r2 = fs->dl
add r3, r0, #52 @ r3 = fs->dx
add r4, r0, #20 @ r4 = fs->qm
ldmia r0, {r5, r6, lr} @ r5 = fs->index
@ r6 = fs->error
@ lr = fs->round
mov r5, r5, asl #2
add r2, r2, r5 @ r2 = fs->dl + fs->index
add r3, r3, r5 @ r3 = fs->dx + fs->index
cmp r6, #0
bne .hf_positive
@ case fs->error == 0
add r3, r3, #32
ldmia r4!, {r5, r6, r7, r8 }
ldmia r2!, {r9, r10, r11, r12}
mla lr, r5, r9, lr
mla lr, r6, r10, lr
mla lr, r7, r11, lr
mla lr, r8, r12, lr
ldmia r4!, {r5, r6, r7, r8 }
b .hf2
.hf_positive:
blt .hf_negative
@ case fs->error > 0
ldmia r4, {r5, r6, r7, r8 }
ldmia r3!, {r9, r10, r11, r12}
add r5, r5, r9
add r6, r6, r10
add r7, r7, r11
add r8, r8, r12
stmia r4!, {r5, r6, r7, r8 } @ update fs->qm[0], ..., fs->qm[3]
ldmia r2!, {r9, r10, r11, r12}
mla lr, r5, r9, lr
mla lr, r6, r10, lr
mla lr, r7, r11, lr
mla lr, r8, r12, lr
ldmia r4, {r5, r6, r7, r8 }
ldmia r3!, {r9, r10, r11, r12}
add r5, r5, r9
add r6, r6, r10
add r7, r7, r11
add r8, r8, r12
stmia r4!, {r5, r6, r7, r8 } @ update fs->qm[4], ..., fs->qm[7]
b .hf2
.hf_negative:
@ case fs->error < 0
ldmia r4, {r5, r6, r7, r8 }
ldmia r3!, {r9, r10, r11, r12}
sub r5, r5, r9
sub r6, r6, r10
sub r7, r7, r11
sub r8, r8, r12
stmia r4!, {r5, r6, r7, r8 } @ update fs->qm[0], ..., fs->qm[3]
ldmia r2!, {r9, r10, r11, r12}
mla lr, r5, r9, lr
mla lr, r6, r10, lr
mla lr, r7, r11, lr
mla lr, r8, r12, lr
ldmia r4, {r5, r6, r7, r8 }
ldmia r3!, {r9, r10, r11, r12}
sub r5, r5, r9
sub r6, r6, r10
sub r7, r7, r11
sub r8, r8, r12
stmia r4!, {r5, r6, r7, r8 } @ update fs->qm[4], ..., fs->qm[7]
.hf2:
ldmia r2!, {r9, r10, r11, r12}
mla lr, r5, r9, lr
mla lr, r6, r10, lr
mla lr, r7, r11, lr
mla lr, r8, r12, lr
@ fs->error = *in;
@ *in += (sum >> fs->shift)
@ *pA = *in
ldr r5, [r1] @ r5 = *in
ldr r6, [r0, #12] @ r6 = fs->shift
add lr, r5, lr, asr r6
str lr, [r1] @ *in += (sum >> fs->shift)
@ update fs->index
ldr r1, [r0] @ r1 = fs->index
add r1, r1, #1
ands r1, r1, #15 @ set Z flag (after this, CPSR must keep !!)
stmia r0, {r1, r5} @ fs->index = (++fs->index & 15)
@ fs->error = (original) *in
@ change *pM, *(pM-1), *(pM-2), *(pM-3)
@ r9 = *(pA-4), r5 = *(pM-3)
@ r10 = *(pA-3), r6 = *(pM-2)
@ r11 = *(pA-2), r7 = *(pM-1)
@ r12 = *(pA-1), r8 = *(pM-0)
@ lr = *(pA-0)
mov r4, #1
orr r5, r4, r9, asr #30
orr r6, r4, r10, asr #30
orr r7, r4, r11, asr #30
orr r8, r4, r12, asr #30
mov r6, r6, lsl #1
mov r7, r7, lsl #1
mov r8, r8, lsl #2
@ change *(pA-1), *(pA-2), *(pA-3)
sub r12, lr, r12
sub r11, r12, r11
sub r10, r11, r10
@ check fs->index is zero
beq .hf_memshl
@ set to the memory: *pA, *(pA-1), *(pA-2), *(pA-3), *pM, *(pM-1), *(pM-2), *(pM-3)
stmda r2, {r10, r11, r12, lr}
stmda r3, {r5, r6, r7, r8}
ldmfd sp!, {r4-r12, pc} @ hybrid_filter end (when fs->index != 0)
.hf_memshl:
@ memshl (fs->dl)
@ r9 = fs->dl[16 + 3]
@ r10 = fs->dl[16 + 4]
@ r11 = fs->dl[16 + 5]
@ r12 = fs->dl[16 + 6]
@ lr = fs->dl[16 + 7]
add r2, r0, #212 @ r2 = fs->dl + 16
ldmia r2, {r1, r3, r4}
sub r2, r2, #64 @ r2 = fs->dl
stmia r2, {r1, r3, r4, r9 - r12, lr}
@ memshl (fs->dx)
@ r5 = fs->dx[16 + 4]
@ r6 = fs->dx[16 + 5]
@ r7 = fs->dx[16 + 6]
@ r8 = fs->dx[16 + 7]
add r9, r0, #116 @ r9 = fs->dx + 16
ldmia r9, {r1, r2, r3, r4}
sub r9, r9, #64 @ r9 = fs->dx
stmia r9, {r1 - r8}
ldmfd sp!, {r4 - r12, pc} @ hybrid_filter end (when fs->index == 0)
hybrid_filter_end:
.size hybrid_filter, hybrid_filter_end - hybrid_filter

View file

@ -0,0 +1,29 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
# libtta
TTALIB := $(CODECDIR)/libtta.a
TTALIB_SRC := $(call preprocess, $(APPSDIR)/codecs/libtta/SOURCES)
TTALIB_OBJ := $(call c2obj, $(TTALIB_SRC))
OTHER_SRC += $(TTALIB_SRC)
$(TTALIB): $(TTALIB_OBJ)
$(SILENT)$(shell rm -f $@)
$(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
TTAFLAGS = $(filter-out -O%,$(CODECFLAGS))
TTAFLAGS += -O3 -funroll-loops -fomit-frame-pointer
$(CODECDIR)/libtta/%.o: $(ROOTDIR)/apps/codecs/libtta/%.c
$(SILENT)mkdir -p $(dir $@)
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(TTAFLAGS) -c $< -o $@
$(CODECDIR)/libtta/%.o: $(ROOTDIR)/apps/codecs/libtta/%.S
$(SILENT)mkdir -p $(dir $@)
$(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(TTAFLAGS) -c $< -o $@

576
apps/codecs/libtta/ttadec.c Normal file
View file

@ -0,0 +1,576 @@
/*
* ttadec.c
*
* Description: TTAv1 decoder library for HW players
* Developed by: Alexander Djourik <ald@true-audio.com>
* Pavel Zhilin <pzh@true-audio.com>
*
* Copyright (c) 2004 True Audio Software. All rights reserved.
*
*/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the True Audio Software nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "codeclib.h"
#include "ttalib.h"
#include "ttadec.h"
#include "filter.h"
/******************* static variables and structures *******************/
static unsigned char isobuffers[ISO_BUFFERS_SIZE + 4] IBSS_ATTR;
static unsigned char *iso_buffers_end = isobuffers + ISO_BUFFERS_SIZE;
static unsigned int pcm_buffer_size;
static decoder tta[MAX_NCH]; /* decoder state */
/* Rockbox speciffic: cache is defined in get_samples() (non static value) */
/* static int cache[MAX_NCH]; // decoder cache */
tta_info *ttainfo; /* currently playing file info */
static unsigned int fframes; /* number of frames in file */
static unsigned int framelen; /* the frame length in samples */
static unsigned int lastlen; /* the length of the last frame in samples */
static unsigned int data_pos; /* currently playing frame index */
static unsigned int data_cur; /* the playing position in frame */
static int maxvalue; /* output data max value */
/* Rockbox speciffic: seek_table is static size */
static unsigned int seek_table[MAX_SEEK_TABLE_SIZE]; /* the playing position table */
static unsigned int st_state; /* seek table status */
static unsigned int frame_crc32;
static unsigned int bit_count;
static unsigned int bit_cache;
static unsigned char *bitpos;
/* Rockbox speciffic: deletes read_id3_tags(). */
/* static int read_id3_tags (tta_info *info); */
/********************* rockbox helper functions *************************/
/* emulate stdio functions */
static int fread(void *ptr, size_t size, size_t nobj)
{
size_t read_size;
unsigned char *buffer = ci->request_buffer(&read_size, size * nobj);
if (read_size > 0)
{
ci->memcpy(ptr, buffer, read_size);
ci->advance_buffer(read_size);
}
return read_size;
}
static int fseek(long offset, int origin)
{
switch (origin)
{
case SEEK_CUR:
ci->advance_buffer(offset);
break;
case SEEK_SET:
ci->seek_buffer(offset);
break;
case SEEK_END:
ci->seek_buffer(offset + ci->id3->filesize);
break;
default:
return -1;
}
return 0;
}
/************************* crc32 functions *****************************/
#define UPDATE_CRC32(x, crc) crc = \
(((crc>>8) & 0x00FFFFFF) ^ crc32_table[(crc^x) & 0xFF])
static unsigned int
crc32 (unsigned char *buffer, unsigned int len) {
unsigned int i;
unsigned int crc = 0xFFFFFFFF;
for (i = 0; i < len; i++) UPDATE_CRC32(buffer[i], crc);
return (crc ^ 0xFFFFFFFF);
}
/************************* bit operations ******************************/
#define GET_BINARY(value, bits) \
while (bit_count < bits) { \
if (bitpos == iso_buffers_end) { \
if (!fread(isobuffers, 1, ISO_BUFFERS_SIZE)) { \
ttainfo->STATE = READ_ERROR; \
return -1; \
} \
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];
#define GET_UNARY(value) \
value = 0; \
while (!(bit_cache ^ bit_mask[bit_count])) { \
if (bitpos == iso_buffers_end) { \
if (!fread(isobuffers, 1, ISO_BUFFERS_SIZE)) { \
ttainfo->STATE = READ_ERROR; \
return -1; \
} \
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--;
/************************* rice operations ******************************/
static inline int update_rice(int value, adapt *rice, int depth,
const unsigned int *shift_table)
{
if (depth > 0)
{
rice->sum1 += value - (rice->sum1 >> 4);
if (rice->k1 > 0 && rice->sum1 < shift_table[rice->k1])
rice->k1--;
else if (rice->sum1 > shift_table[rice->k1 + 1])
rice->k1++;
value += *(shift_table + rice->k0 - 4);
}
rice->sum0 += value - (rice->sum0 >> 4);
if (rice->k0 > 0 && rice->sum0 < shift_table[rice->k0])
rice->k0--;
else if (rice->sum0 > shift_table[rice->k0 + 1])
rice->k0++;
return DEC(value);
}
/************************* buffer functions ******************************/
static void init_buffer_read(void) {
frame_crc32 = 0xFFFFFFFFUL;
bit_count = bit_cache = 0;
bitpos = iso_buffers_end;
}
static int done_buffer_read(void) {
unsigned int crc32, rbytes;
frame_crc32 ^= 0xFFFFFFFFUL;
rbytes = iso_buffers_end - bitpos;
if (rbytes < sizeof(int)) {
ci->memcpy(isobuffers, bitpos, 4);
if (!fread(isobuffers + rbytes, 1, ISO_BUFFERS_SIZE - rbytes))
return -1;
bitpos = isobuffers;
}
ci->memcpy(&crc32, bitpos, 4);
crc32 = ENDSWAP_INT32(crc32);
bitpos += sizeof(int);
if (crc32 != frame_crc32) return -1;
bit_cache = bit_count = 0;
frame_crc32 = 0xFFFFFFFFUL;
return 0;
}
/************************* decoder functions ****************************/
const char *get_error_str (int error) {
switch (error) {
case NO_ERROR: return "No errors found";
case OPEN_ERROR: return "Can't open file";
case FORMAT_ERROR: return "Not supported file format";
case FILE_ERROR: return "File is corrupted";
case READ_ERROR: return "Can't read from file";
case MEMORY_ERROR: return "Insufficient memory available";
default: return "Unknown error code";
}
}
int set_tta_info (tta_info *info)
{
unsigned int checksum;
unsigned int datasize;
unsigned int origsize;
tta_hdr ttahdr;
/* clear the memory */
ci->memset (info, 0, sizeof(tta_info));
/* skip id3v2 tags */
fseek(ci->id3->id3v2len, SEEK_SET);
/* read TTA header */
if (fread (&ttahdr, 1, sizeof (ttahdr)) == 0) {
info->STATE = READ_ERROR;
return -1;
}
/* check for TTA3 signature */
if (ENDSWAP_INT32(ttahdr.TTAid) != TTA1_SIGN) {
DEBUGF("ID error: %x\n", ENDSWAP_INT32(ttahdr.TTAid));
info->STATE = FORMAT_ERROR;
return -1;
}
ttahdr.CRC32 = ENDSWAP_INT32(ttahdr.CRC32);
checksum = crc32((unsigned char *) &ttahdr,
sizeof(tta_hdr) - sizeof(int));
if (checksum != ttahdr.CRC32) {
DEBUGF("CRC error: %x != %x\n", ttahdr.CRC32, checksum);
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)) {
info->STATE = FORMAT_ERROR;
DEBUGF("illegal audio format: %d channels: %d samplerate: %d\n",
ttahdr.AudioFormat, ttahdr.NumChannels, ttahdr.SampleRate);
return -1;
}
/* fill the File Info */
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 = (int) MULTIPLY_FRAME_TIME(ttahdr.SampleRate);
info->LENGTH = ttahdr.DataLength / ttahdr.SampleRate;
info->DATAPOS = ci->id3->id3v2len;
info->FILESIZE = ci->id3->filesize;
datasize = info->FILESIZE - info->DATAPOS;
origsize = info->DATALENGTH * info->BSIZE * info->NCH;
/* info->COMPRESS = (double) datasize / origsize; */
info->BITRATE = (int) ((uint64_t) datasize * info->SAMPLERATE * info->NCH * info->BPS
/ (origsize * 1000LL));
return 0;
}
static void rice_init(adapt *rice, unsigned int k0, unsigned int k1) {
rice->k0 = k0;
rice->k1 = k1;
rice->sum0 = shift_16[k0];
rice->sum1 = shift_16[k1];
}
static void decoder_init(decoder *tta, int nch, int byte_size) {
int shift = flt_set[byte_size - 1];
int 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 int *seek_table,
unsigned int len, unsigned int data_offset) {
unsigned int *st, frame_len;
for (st = seek_table; st < (seek_table + len); st++) {
frame_len = ENDSWAP_INT32(*st);
*st = data_offset;
data_offset += frame_len;
}
}
int set_position (unsigned int pos, enum tta_seek_type type)
{
unsigned int i;
unsigned int seek_pos;
if (type == TTA_SEEK_TIME)
{
if (pos >= fframes)
pos = fframes -1;
}
else
{
pos -= ttainfo->DATAPOS;
for (i = 1; i < fframes; i++)
{
if (seek_table[i] > pos)
break;
}
pos = i - 1;
}
if (!st_state) {
ttainfo->STATE = FILE_ERROR;
return -1;
}
seek_pos = ttainfo->DATAPOS + seek_table[data_pos = pos];
if (fseek(seek_pos, SEEK_SET) < 0) {
ttainfo->STATE = READ_ERROR;
return -1;
}
data_cur = 0;
framelen = 0;
/* init bit reader */
init_buffer_read();
return data_pos * ttainfo->FRAMELEN;
}
int player_init (tta_info *info) {
unsigned int checksum;
unsigned int data_offset;
unsigned int st_size;
ttainfo = info;
framelen = 0;
data_pos = 0;
data_cur = 0;
lastlen = ttainfo->DATALENGTH % ttainfo->FRAMELEN;
fframes = ttainfo->DATALENGTH / ttainfo->FRAMELEN + (lastlen ? 1 : 0);
st_size = (fframes + 1) * sizeof(int);
/*
* Rockbox speciffic
* playable tta file is to MAX_SEEK_TABLE_SIZE frames
* about 1:08:15 (frequency 44.1 kHz)
*/
if (fframes > MAX_SEEK_TABLE_SIZE)
{
LOGF("frame is too many: %d > %d", fframes, MAX_SEEK_TABLE_SIZE);
return -1;
}
/* read seek table */
if (!fread(seek_table, st_size, 1)) {
ttainfo->STATE = READ_ERROR;
return -1;
}
checksum = crc32((unsigned char *) seek_table, st_size - sizeof(int));
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();
/*
* Rockbox speciffic
* because pcm data is int32_t, does not multiply ttainfo->BSIZE.
*/
pcm_buffer_size = PCM_BUFFER_LENGTH * ttainfo->NCH;
maxvalue = (1UL << ttainfo->BPS) - 1;
return 0;
}
/*
* Rockbox specffic
* because the seek table is static size buffer, player_stop() is nooperation function.
*/
void player_stop (void) {
/*
if (seek_table) {
free(seek_table);
seek_table = NULL;
}
*/
}
/*
* Rockbox speciffic
* with the optimization, the decoding logic is modify a little.
*/
int get_samples (int32_t *buffer) {
unsigned int k, depth, unary, binary;
int32_t *p = buffer;
decoder *dec = tta;
int value, res;
int cur_pos = pcm_buffer_size;
int pcm_shift_bits = TTA_OUTPUT_DEPTH - ttainfo->BPS;
int pr_bits = (ttainfo->BSIZE == 1)? 4 : 5;
int cache = 0; /* decoder cache */
fltst *fst;
adapt *rice;
for (res = 0; --cur_pos >= 0;) {
fst = &dec->fst;
rice = &dec->rice;
if (data_cur == framelen) {
if (data_pos == fframes) break;
if (framelen && done_buffer_read()) {
if (set_position(data_pos, TTA_SEEK_TIME) < 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;
value = update_rice(value, rice, depth, shift_16);
/* Rockbox specific: the following logic move to update_rice() */
#if 0
if (depth > 0)
{
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];
}
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);
#endif
/* decompress stage 1: adaptive hybrid filter */
hybrid_filter(fst, &value);
/* decompress stage 2: fixed order 1 prediction */
value += PREDICTOR1(dec->last, pr_bits);
dec->last = value;
/* check for errors */
if (abs(value) > maxvalue) {
unsigned int tail =
pcm_buffer_size / (ttainfo->BSIZE * ttainfo->NCH) - res;
ci->memset(buffer, 0, pcm_buffer_size * sizeof(int32_t));
data_cur += tail; res += tail;
break;
}
/* Rockbox speciffic: Rockbox supports max 2channels */
if (ttainfo->NCH == 1)
{
*p++ = value << pcm_shift_bits;
data_cur++;
res++;
}
else
{
if (dec == tta)
{
cache = value;
dec++;
}
else
{
value += cache / 2;
cache = value - cache;
dec = tta;
*p++ = cache << pcm_shift_bits;
*p++ = value << pcm_shift_bits;
data_cur++;
res++;
}
}
}
return res;
}
/* Rockbox speciffic: id3 tags functions delete. */
/* eof */

203
apps/codecs/libtta/ttadec.h Normal file
View file

@ -0,0 +1,203 @@
/*
* ttadec.h
*
* Description: TTAv1 decoder definitions and prototypes
* Developed by: Alexander Djourik <ald@true-audio.com>
* Pavel Zhilin <pzh@true-audio.com>
*
* Copyright (c) 2004 True Audio Software. All rights reserved.
*
*/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the True Audio Software nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TTADEC_H_
#define TTADEC_H_
#define __ATTRIBUTE_PACKED__ __attribute__((packed))
#define TTA1_SIGN 0x31415454
#define MAX_ORDER 8
#ifndef WAVE_FORMAT_PCM
#define WAVE_FORMAT_PCM 1
#endif
typedef unsigned long long uint64;
static const unsigned int crc32_table[256] ICONST_ATTR = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
static const unsigned int bit_mask[] ICONST_ATTR = {
0x00000000, 0x00000001, 0x00000003, 0x00000007,
0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
0xffffffff
};
static const unsigned int bit_shift[] ICONST_ATTR = {
0x00000001, 0x00000002, 0x00000004, 0x00000008,
0x00000010, 0x00000020, 0x00000040, 0x00000080,
0x00000100, 0x00000200, 0x00000400, 0x00000800,
0x00001000, 0x00002000, 0x00004000, 0x00008000,
0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000,
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x80000000, 0x80000000, 0x80000000, 0x80000000,
0x80000000, 0x80000000, 0x80000000, 0x80000000
};
static const unsigned int *shift_16 = bit_shift + 4;
typedef unsigned char byte;
#ifndef ROCKBOX_LITTLE_ENDIAN
#define ENDSWAP_INT16(x) (((((x)>>8)&0xFF)|(((x)&0xFF)<<8)))
#define ENDSWAP_INT32(x) (((((x)>>24)&0xFF)|(((x)>>8)&0xFF00)|(((x)&0xFF00)<<8)|(((x)&0xFF)<<24)))
#define WRITE_BUFFER(x, bsize, out) { \
if (bsize > 2) *out++ = (byte)(*x >> 16)); \
if (bsize > 1) *out++ = (byte)(*x >> 8); \
*out++ = (byte) *x; }
#else
#define ENDSWAP_INT16(x) (x)
#define ENDSWAP_INT32(x) (x)
#define WRITE_BUFFER(x, bsize, out) { \
*out++ = (byte) *x; \
if (bsize > 1) *out++ = (byte)(*x >> 8); \
if (bsize > 2) *out++ = (byte)(*x >> 16); }
#endif
#define PREDICTOR1(x, k) ((int)((((uint64)x << k) - x) >> k))
#define DEC(x) (((x)&1)?(((x)+1)>>1):(-(x)>>1))
typedef struct {
unsigned int TTAid;
unsigned short AudioFormat;
unsigned short NumChannels;
unsigned short BitsPerSample;
unsigned int SampleRate;
unsigned int DataLength;
unsigned int CRC32;
} __ATTRIBUTE_PACKED__ tta_hdr;
typedef struct {
unsigned int k0;
unsigned int k1;
unsigned int sum0;
unsigned int sum1;
} adapt;
typedef struct {
int index; /* Rockbox speciffic */
int error;
int round;
int shift;
int mutex;
int qm[MAX_ORDER];
int dx[MAX_ORDER * 3]; /* original: dx[MAX_ORDER + 1] */
int dl[MAX_ORDER * 3]; /* original: dx[MAX_ORDER + 1] */
} fltst;
typedef struct {
fltst fst;
adapt rice;
int last;
} decoder;
/* Rockbox speciffic: about id3 tags definitions delete. */
#endif /* TTADEC_H_ */

157
apps/codecs/libtta/ttalib.h Normal file
View file

@ -0,0 +1,157 @@
/*
* ttalib.h
*
* Description: TTAv1 player library prototypes
* Developed by: Alexander Djourik <ald@true-audio.com>
* Pavel Zhilin <pzh@true-audio.com>
*
* Copyright (c) 2004 True Audio Software. All rights reserved.
*
*/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the True Audio Software nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TTALIB_H_
#define TTALIB_H_
#define MAX_BPS 24 /* Max supported Bit resolution */
#define MAX_NCH 2 /* Max supported number of channels (Rockbox changes: 8 -> 2) */
#ifndef MAXLINE
#define MAX_LINE 1024
#endif
/* decoded pcm sample depth (sample 28bit + sign 1bit) */
#define TTA_OUTPUT_DEPTH 29
/* return codes */
#define NO_ERROR 0 /* No errors found */
#define OPEN_ERROR 1 /* Can't open file */
#define FORMAT_ERROR 2 /* Unknown TTA format version */
#define PLAYER_ERROR 3 /* Not supported file format */
#define FILE_ERROR 4 /* File is corrupted */
#define READ_ERROR 5 /* Can't read from file */
#define MEMORY_ERROR 6 /* Insufficient memory available */
/* Rockbox speciffic: does not use FRAME_TIME */
/* #define FRAME_TIME 1.04489795918367346939 */
#define MULTIPLY_FRAME_TIME(x) (256 * (x) / 245) /* = FRAME_TIME * x */
#define SEEK_STEP (int)MULTIPLY_FRAME_TIME(1000) /* (FRAME_TIME * 1000) */
#define ISO_BUFFER_LENGTH (1024*32)
#define ISO_NBUFFERS (8)
#define ISO_BUFFERS_SIZE (4096) /* (ISO_BUFFER_LENGTH*ISO_NBUFFERS) */
#define PCM_BUFFER_LENGTH (4608)
#define MAX_SEEK_TABLE_SIZE (4096)
typedef struct {
/* FILE *HANDLE; // file handle (Rockbox does not use) */
unsigned int FILESIZE; /* compressed size */
unsigned short NCH; /* number of channels */
unsigned short BPS; /* bits per sample */
unsigned short BSIZE; /* byte size */
unsigned short FORMAT; /* audio format */
unsigned int SAMPLERATE; /* samplerate (sps) */
unsigned int DATALENGTH; /* data length in samples */
unsigned int FRAMELEN; /* frame length */
unsigned int LENGTH; /* playback time (sec) */
unsigned int STATE; /* return code */
unsigned int DATAPOS; /* size of ID3v2 header */
unsigned int BITRATE; /* average bitrate (kbps) */
/* double COMPRESS; // compression ratio (Rockbox does not use) */
/* id3_info ID3; // ID3 information (Rockbox does not use) */
} tta_info;
enum tta_seek_type
{
TTA_SEEK_TIME,
TTA_SEEK_POS,
};
/*********************** Library functions *************************/
/* Rockbox speciffic: open_tta_file() does not use */
/* Rockbox speciffic: It is used in place of open_tta_file(). */
int set_tta_info( // FUNCTION: set tta file info structure
tta_info *info); // file info structure
/*
* RETURN VALUE
* This function returns 0 if success. Otherwise, -1 is returned
* and the variable STATE of the currently using info structure
* is set to indicate the error.
*
*/
/* Rockbox speciffic: close_tta_file() does not use */
/* Rockbox speciffic: set_position() change arguments and return value. */
/*
* FUNCTION: sets playback position
* pos: seek position
* seek_time_ms / SEEK_STEP (when type is TTA_SEEK_TIME)
* file position (when type is TTA_SEEK_POS)
*/
int set_position (
unsigned int pos,
enum tta_seek_type type);
/*
* RETURN VALUE
* This function returns the seeked data position (>= 0) if success. Otherwise, -1 is returned
* and the variable STATE of the currently using info structure
* is set to indicate the error.
*
*/
int player_init ( // FUNCTION: initializes TTA player
tta_info *info); // file info structure
/*
* RETURN VALUE
* This function returns 0 if success. Otherwise, -1 is returned
* and the variable STATE of the currently using info structure
* is set to indicate the error.
*
*/
void player_stop (void); // FUNCTION: destroys memory pools
/* Rockbox speciffic: unsigned char -> int32_t */
int get_samples ( // FUNCTION: decode PCM_BUFFER_LENGTH samples
int32_t *buffer); // into the current PCM buffer position
/*
* RETURN VALUE
* This function returns the number of samples successfully decoded.
* Otherwise, -1 is returned and the variable STATE of the currently
* using info structure is set to indicate the error.
*
*/
const char *get_error_str (int error); // FUNCTION: get error description
#endif /* TTALIB_H_ */

132
apps/codecs/tta.c Normal file
View file

@ -0,0 +1,132 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Yoshihisa Uchida
*
* 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 "codecs/libtta/ttalib.h"
CODEC_HEADER
/*
* TTA (True Audio) codec:
*
* References
* [1] TRUE AUDIO CODEC SOFTWARE http://true-audio.com/
*/
static int32_t samples[PCM_BUFFER_LENGTH * 2] IBSS_ATTR;
/* this is the codec entry point */
enum codec_status codec_main(void)
{
tta_info info;
int status = CODEC_OK;
unsigned int decodedsamples = 0;
int endofstream;
int new_pos = 0;
int sample_count;
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, TTA_OUTPUT_DEPTH - 1);
if (codec_init())
{
DEBUGF("codec_init() error\n");
status = CODEC_ERROR;
goto exit;
}
next_track:
while (!*ci->taginfo_ready && !ci->stop_codec)
ci->sleep(1);
if (set_tta_info(&info) < 0)
{
status = CODEC_ERROR;
goto exit;
}
if (player_init(&info) < 0)
{
status = CODEC_ERROR;
goto exit;
}
codec_set_replaygain(ci->id3);
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
if (info.NCH == 2) {
ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
} else if (info.NCH == 1) {
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("CODEC_ERROR: more than 2 channels\n");
status = CODEC_ERROR;
goto done;
}
/* The main decoder loop */
endofstream = 0;
if (ci->id3->offset > 0)
{
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
new_pos = set_position(ci->id3->offset, TTA_SEEK_POS);
if (new_pos >= 0)
decodedsamples = new_pos;
ci->seek_complete();
}
while (!endofstream)
{
ci->yield();
if (ci->stop_codec || ci->new_track)
break;
if (ci->seek_time)
{
new_pos = set_position(ci->seek_time / SEEK_STEP, TTA_SEEK_TIME);
if (new_pos >= 0)
{
decodedsamples = new_pos;
ci->seek_complete();
}
}
sample_count = get_samples(samples);
if (sample_count < 0)
{
status = CODEC_ERROR;
break;
}
ci->pcmbuf_insert(samples, NULL, sample_count);
decodedsamples += sample_count;
if (decodedsamples >= info.DATALENGTH)
endofstream = 1;
ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH);
}
status = CODEC_OK;
done:
player_stop();
if (ci->request_next_track())
goto next_track;
exit:
return status;
}

View file

@ -105,6 +105,7 @@ static const struct filetype inbuilt_filetypes[] = {
{ "snd", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "vox", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "w64", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "tta", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
#endif
{ "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
{ "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },

View file

@ -179,6 +179,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] =
/* Wave64 */
[AFMT_WAVE64] =
AFMT_ENTRY("WAVE64", "wav64", NULL, "w64\0" ),
/* True Audio */
[AFMT_TTA] =
AFMT_ENTRY("TTA", "tta", NULL, "tta\0" ),
#endif
};
@ -494,6 +497,14 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
}
break;
case AFMT_TTA:
if (!get_tta_metadata(fd, id3))
{
DEBUGF("get_tta_metadata error\n");
return false;
}
break;
#endif /* CONFIG_CODEC == SWCODEC */
default:

View file

@ -83,6 +83,7 @@ enum
AFMT_AU, /* Sun Audio file */
AFMT_VOX, /* VOX */
AFMT_WAVE64, /* Wave64 */
AFMT_TTA, /* True Audio */
#endif
/* add new formats at any index above this line to have a sensible order -

View file

@ -22,6 +22,7 @@
char* id3_get_num_genre(unsigned int genre_num);
int getid3v2len(int fd);
bool setid3v1title(int fd, struct mp3entry *entry);
void setid3v2title(int fd, struct mp3entry *entry);
bool get_mp3_metadata(int fd, struct mp3entry* id3, const char *filename);
bool get_adx_metadata(int fd, struct mp3entry* id3);
@ -46,3 +47,4 @@ bool get_smaf_metadata(int fd, struct mp3entry* id3);
bool get_au_metadata(int fd, struct mp3entry* id3);
bool get_vox_metadata(int fd, struct mp3entry* id3);
bool get_wave64_metadata(int fd, struct mp3entry* id3);
bool get_tta_metadata(int fd, struct mp3entry* id3);

View file

@ -640,7 +640,7 @@ bool setid3v1title(int fd, struct mp3entry *entry)
*
* Returns: true if a title was found and created, else false
*/
static void setid3v2title(int fd, struct mp3entry *entry)
void setid3v2title(int fd, struct mp3entry *entry)
{
int minframesize;
int size;

123
apps/metadata/tta.c Normal file
View file

@ -0,0 +1,123 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Yoshihisa Uchida
*
* 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <inttypes.h>
#include "system.h"
#include "metadata.h"
#include "metadata_common.h"
#include "metadata_parsers.h"
#include "logf.h"
#define TTA1_SIGN 0x31415454
#define TTA_HEADER_ID 0
#define TTA_HEADER_AUDIO_FORMAT (TTA_HEADER_ID + sizeof(unsigned int))
#define TTA_HEADER_NUM_CHANNELS (TTA_HEADER_AUDIO_FORMAT + sizeof(unsigned short))
#define TTA_HEADER_BITS_PER_SAMPLE (TTA_HEADER_NUM_CHANNELS + sizeof(unsigned short))
#define TTA_HEADER_SAMPLE_RATE (TTA_HEADER_BITS_PER_SAMPLE + sizeof(unsigned short))
#define TTA_HEADER_DATA_LENGTH (TTA_HEADER_SAMPLE_RATE + sizeof(unsigned int))
#define TTA_HEADER_CRC32 (TTA_HEADER_DATA_LENGTH + sizeof(unsigned int))
#define TTA_HEADER_SIZE (TTA_HEADER_CRC32 + sizeof(unsigned int))
#define TTA_HEADER_GETTER_ID(x) get_long_le(x)
#define TTA_HEADER_GETTER_AUDIO_FORMAT(x) get_short_le(x)
#define TTA_HEADER_GETTER_NUM_CHANNELS(x) get_short_le(x)
#define TTA_HEADER_GETTER_BITS_PER_SAMPLE(x) get_short_le(x)
#define TTA_HEADER_GETTER_SAMPLE_RATE(x) get_long_le(x)
#define TTA_HEADER_GETTER_DATA_LENGTH(x) get_long_le(x)
#define TTA_HEADER_GETTER_CRC32(x) get_long_le(x)
#define GET_HEADER(x, tag) TTA_HEADER_GETTER_ ## tag((x) + TTA_HEADER_ ## tag)
static void read_id3_tags(int fd, struct mp3entry* id3)
{
id3->title = NULL;
id3->filesize = filesize(fd);
id3->id3v2len = getid3v2len(fd);
id3->tracknum = 0;
id3->discnum = 0;
id3->vbr = false; /* All TTA files are CBR */
/* first get id3v2 tags. if no id3v2 tags ware found, get id3v1 tags */
if (id3->id3v2len)
{
setid3v2title(fd, id3);
id3->first_frame_offset = id3->id3v2len;
return;
}
setid3v1title(fd, id3);
}
bool get_tta_metadata(int fd, struct mp3entry* id3)
{
unsigned char ttahdr[TTA_HEADER_SIZE];
unsigned int datasize;
unsigned int origsize;
int bps;
lseek(fd, 0, SEEK_SET);
/* read id3 tags */
read_id3_tags(fd, id3);
lseek(fd, id3->id3v2len, SEEK_SET);
/* read TTA header */
if (read(fd, ttahdr, TTA_HEADER_SIZE) < 0)
return false;
/* check for TTA3 signature */
if ((GET_HEADER(ttahdr, ID)) != TTA1_SIGN)
return false;
/* skip check CRC */
id3->channels = (GET_HEADER(ttahdr, NUM_CHANNELS));
id3->frequency = (GET_HEADER(ttahdr, SAMPLE_RATE));
id3->length = ((GET_HEADER(ttahdr, DATA_LENGTH)) / id3->frequency) * 1000LL;
bps = (GET_HEADER(ttahdr, BITS_PER_SAMPLE));
datasize = id3->filesize - id3->first_frame_offset;
origsize = (GET_HEADER(ttahdr, DATA_LENGTH)) * ((bps + 7) / 8) * id3->channels;
id3->bitrate = (int) ((uint64_t) datasize * id3->frequency * id3->channels * bps
/ (origsize * 1000LL));
/* output header info (for debug) */
DEBUGF("TTA header info ----\n");
DEBUGF("id: %x\n", (unsigned int)(GET_HEADER(ttahdr, ID)));
DEBUGF("channels: %d\n", id3->channels);
DEBUGF("frequency: %ld\n", id3->frequency);
DEBUGF("length: %ld\n", id3->length);
DEBUGF("bitrate: %d\n", id3->bitrate);
DEBUGF("bits per sample: %d\n", bps);
DEBUGF("compressed size: %d\n", datasize);
DEBUGF("original size: %d\n", origsize);
DEBUGF("id3----\n");
DEBUGF("artist: %s\n", id3->artist);
DEBUGF("title: %s\n", id3->title);
DEBUGF("genre: %s\n", id3->genre_string);
return true;
}