summaryrefslogtreecommitdiff
path: root/apps/codecs/ape.c
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2007-06-05 16:58:29 +0000
committerDave Chapman <dave@dchapman.com>2007-06-05 16:58:29 +0000
commit520274219a0745384cb9bc6df4d7ee7905090f5d (patch)
tree8d6f4536b6758d00e72a2a9457f892ce28a591bd /apps/codecs/ape.c
parent887b31c01aebb46c0fcc6910241a4a64d9e7991e (diff)
downloadrockbox-520274219a0745384cb9bc6df4d7ee7905090f5d.zip
rockbox-520274219a0745384cb9bc6df4d7ee7905090f5d.tar.gz
rockbox-520274219a0745384cb9bc6df4d7ee7905090f5d.tar.bz2
rockbox-520274219a0745384cb9bc6df4d7ee7905090f5d.tar.xz
Initial commit of Monkey's Audio (.ape/.mac) support. Note that Monkey's is an extremely CPU-intensive codec, and that the decoding speed is directly related to the compression level (-c1000, -c2000, -c3000, -c4000 or -c5000) used when encoding the file. Current performance is: -c1000 to -c3000 are realtime on a Gigabeat, -c1000 is realtime on Coldfire targets (H100, H300 and Cowon), and nothing is realtime on PortalPlayer targets (iPods, H10, Sansa). Hopefully this can be improved. More information at FS #7256.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13562 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/ape.c')
-rw-r--r--apps/codecs/ape.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/apps/codecs/ape.c b/apps/codecs/ape.c
new file mode 100644
index 0000000..b77abc0
--- /dev/null
+++ b/apps/codecs/ape.c
@@ -0,0 +1,162 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 Dave Chapman
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "codeclib.h"
+#define ROCKBOX
+#include <codecs/demac/libdemac/demac.h>
+
+CODEC_HEADER
+
+#define BLOCKS_PER_LOOP 4608
+#define MAX_CHANNELS 2
+#define MAX_BYTESPERSAMPLE 3
+
+#define INPUT_CHUNKSIZE (32*1024)
+
+/* 4608*4 = 18432 bytes per channel */
+static int32_t decoded0[BLOCKS_PER_LOOP] IBSS_ATTR;
+static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR;
+
+#define MAX_SUPPORTED_SEEKTABLE_SIZE 5000
+
+/* this is the codec entry point */
+enum codec_status codec_main(void)
+{
+ struct ape_ctx_t ape_ctx;
+ uint32_t samplesdone;
+ uint32_t elapsedtime;
+ size_t bytesleft;
+ int retval;
+
+ uint32_t currentframe;
+ int nblocks;
+ int bytesconsumed;
+ unsigned char* inbuffer;
+ int blockstodecode;
+ int res;
+ int firstbyte;
+
+ /* Generic codec initialisation */
+ ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
+ ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, 1024*128);
+
+ ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
+
+ next_track:
+
+ if (codec_init()) {
+ LOGF("APE: Error initialising codec\n");
+ retval = CODEC_ERROR;
+ goto exit;
+ }
+
+ inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
+
+ /* Read the file headers to populate the ape_ctx struct */
+ if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) {
+ LOGF("APE: Error reading header\n");
+ retval = CODEC_ERROR;
+ goto exit;
+ }
+ ci->advance_buffer(ape_ctx.firstframe);
+
+ while (!*ci->taginfo_ready && !ci->stop_codec)
+ ci->sleep(1);
+
+ ci->configure(DSP_SWITCH_FREQUENCY, ape_ctx.samplerate);
+ ci->configure(DSP_SET_STEREO_MODE, ape_ctx.channels == 1 ?
+ STEREO_MONO : STEREO_NONINTERLEAVED);
+ codec_set_replaygain(ci->id3);
+
+ /* The main decoding loop */
+
+ currentframe = 0;
+ samplesdone = 0;
+
+ /* Initialise the buffer */
+ inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
+ firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */
+
+ /* The main decoding loop - we decode the frames a small chunk at a time */
+ while (currentframe < ape_ctx.totalframes)
+ {
+ /* Calculate how many blocks there are in this frame */
+ if (currentframe == (ape_ctx.totalframes - 1))
+ nblocks = ape_ctx.finalframeblocks;
+ else
+ nblocks = ape_ctx.blocksperframe;
+
+ ape_ctx.currentframeblocks = nblocks;
+
+ /* Initialise the frame decoder */
+ init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed);
+
+ ci->advance_buffer(bytesconsumed);
+ inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
+
+ /* Decode the frame a chunk at a time */
+ while (nblocks > 0)
+ {
+ ci->yield();
+ if (ci->stop_codec || ci->new_track) {
+ break;
+ }
+
+ blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks);
+
+ if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte,
+ &bytesconsumed,
+ decoded0, decoded1,
+ blockstodecode)) < 0)
+ {
+ /* Frame decoding error, abort */
+ LOGF("APE: Frame %d, error %d\n",currentframe,res);
+ retval = CODEC_ERROR;
+ goto done;
+ }
+
+ ci->yield();
+ ci->pcmbuf_insert(decoded0, decoded1, blockstodecode);
+
+ /* Update the elapsed-time indicator */
+ samplesdone += blockstodecode;
+ elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
+ ci->set_elapsed(elapsedtime);
+
+ ci->advance_buffer(bytesconsumed);
+ inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
+
+ /* Decrement the block count */
+ nblocks -= blockstodecode;
+ }
+
+ currentframe++;
+ }
+
+ retval = CODEC_OK;
+
+done:
+ LOGF("APE: Decoded %ld samples\n",samplesdone);
+
+ if (ci->request_next_track())
+ goto next_track;
+
+exit:
+ return retval;
+}