diff options
Diffstat (limited to 'apps/codecs/ape.c')
-rw-r--r-- | apps/codecs/ape.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/apps/codecs/ape.c b/apps/codecs/ape.c new file mode 100644 index 0000000000..b77abc0c74 --- /dev/null +++ b/apps/codecs/ape.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 Dave Chapman | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "codeclib.h" | ||
21 | #define ROCKBOX | ||
22 | #include <codecs/demac/libdemac/demac.h> | ||
23 | |||
24 | CODEC_HEADER | ||
25 | |||
26 | #define BLOCKS_PER_LOOP 4608 | ||
27 | #define MAX_CHANNELS 2 | ||
28 | #define MAX_BYTESPERSAMPLE 3 | ||
29 | |||
30 | #define INPUT_CHUNKSIZE (32*1024) | ||
31 | |||
32 | /* 4608*4 = 18432 bytes per channel */ | ||
33 | static int32_t decoded0[BLOCKS_PER_LOOP] IBSS_ATTR; | ||
34 | static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR; | ||
35 | |||
36 | #define MAX_SUPPORTED_SEEKTABLE_SIZE 5000 | ||
37 | |||
38 | /* this is the codec entry point */ | ||
39 | enum codec_status codec_main(void) | ||
40 | { | ||
41 | struct ape_ctx_t ape_ctx; | ||
42 | uint32_t samplesdone; | ||
43 | uint32_t elapsedtime; | ||
44 | size_t bytesleft; | ||
45 | int retval; | ||
46 | |||
47 | uint32_t currentframe; | ||
48 | int nblocks; | ||
49 | int bytesconsumed; | ||
50 | unsigned char* inbuffer; | ||
51 | int blockstodecode; | ||
52 | int res; | ||
53 | int firstbyte; | ||
54 | |||
55 | /* Generic codec initialisation */ | ||
56 | ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); | ||
57 | ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, 1024*128); | ||
58 | |||
59 | ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1); | ||
60 | |||
61 | next_track: | ||
62 | |||
63 | if (codec_init()) { | ||
64 | LOGF("APE: Error initialising codec\n"); | ||
65 | retval = CODEC_ERROR; | ||
66 | goto exit; | ||
67 | } | ||
68 | |||
69 | inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); | ||
70 | |||
71 | /* Read the file headers to populate the ape_ctx struct */ | ||
72 | if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) { | ||
73 | LOGF("APE: Error reading header\n"); | ||
74 | retval = CODEC_ERROR; | ||
75 | goto exit; | ||
76 | } | ||
77 | ci->advance_buffer(ape_ctx.firstframe); | ||
78 | |||
79 | while (!*ci->taginfo_ready && !ci->stop_codec) | ||
80 | ci->sleep(1); | ||
81 | |||
82 | ci->configure(DSP_SWITCH_FREQUENCY, ape_ctx.samplerate); | ||
83 | ci->configure(DSP_SET_STEREO_MODE, ape_ctx.channels == 1 ? | ||
84 | STEREO_MONO : STEREO_NONINTERLEAVED); | ||
85 | codec_set_replaygain(ci->id3); | ||
86 | |||
87 | /* The main decoding loop */ | ||
88 | |||
89 | currentframe = 0; | ||
90 | samplesdone = 0; | ||
91 | |||
92 | /* Initialise the buffer */ | ||
93 | inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); | ||
94 | firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ | ||
95 | |||
96 | /* The main decoding loop - we decode the frames a small chunk at a time */ | ||
97 | while (currentframe < ape_ctx.totalframes) | ||
98 | { | ||
99 | /* Calculate how many blocks there are in this frame */ | ||
100 | if (currentframe == (ape_ctx.totalframes - 1)) | ||
101 | nblocks = ape_ctx.finalframeblocks; | ||
102 | else | ||
103 | nblocks = ape_ctx.blocksperframe; | ||
104 | |||
105 | ape_ctx.currentframeblocks = nblocks; | ||
106 | |||
107 | /* Initialise the frame decoder */ | ||
108 | init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed); | ||
109 | |||
110 | ci->advance_buffer(bytesconsumed); | ||
111 | inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); | ||
112 | |||
113 | /* Decode the frame a chunk at a time */ | ||
114 | while (nblocks > 0) | ||
115 | { | ||
116 | ci->yield(); | ||
117 | if (ci->stop_codec || ci->new_track) { | ||
118 | break; | ||
119 | } | ||
120 | |||
121 | blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); | ||
122 | |||
123 | if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte, | ||
124 | &bytesconsumed, | ||
125 | decoded0, decoded1, | ||
126 | blockstodecode)) < 0) | ||
127 | { | ||
128 | /* Frame decoding error, abort */ | ||
129 | LOGF("APE: Frame %d, error %d\n",currentframe,res); | ||
130 | retval = CODEC_ERROR; | ||
131 | goto done; | ||
132 | } | ||
133 | |||
134 | ci->yield(); | ||
135 | ci->pcmbuf_insert(decoded0, decoded1, blockstodecode); | ||
136 | |||
137 | /* Update the elapsed-time indicator */ | ||
138 | samplesdone += blockstodecode; | ||
139 | elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); | ||
140 | ci->set_elapsed(elapsedtime); | ||
141 | |||
142 | ci->advance_buffer(bytesconsumed); | ||
143 | inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); | ||
144 | |||
145 | /* Decrement the block count */ | ||
146 | nblocks -= blockstodecode; | ||
147 | } | ||
148 | |||
149 | currentframe++; | ||
150 | } | ||
151 | |||
152 | retval = CODEC_OK; | ||
153 | |||
154 | done: | ||
155 | LOGF("APE: Decoded %ld samples\n",samplesdone); | ||
156 | |||
157 | if (ci->request_next_track()) | ||
158 | goto next_track; | ||
159 | |||
160 | exit: | ||
161 | return retval; | ||
162 | } | ||