summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorGravatar waker <wakeroid@gmail.com>2009-09-01 23:29:49 +0200
committerGravatar waker <wakeroid@gmail.com>2009-09-01 23:29:49 +0200
commit2a4e13a9eb85a79d08a0ed7e31de97d760bdf2cd (patch)
tree2b8936aac2804da29fd0aa8cd4653985045b134c /plugins
parentb701992cd0904ade135c376a61fba4315860a210 (diff)
ape decoding updates
Diffstat (limited to 'plugins')
-rw-r--r--plugins/ape/ape.c1
-rw-r--r--plugins/demac/Makefile.am30
-rw-r--r--plugins/demac/demac.c482
3 files changed, 506 insertions, 7 deletions
diff --git a/plugins/ape/ape.c b/plugins/ape/ape.c
index 66e7af17..43ed001f 100644
--- a/plugins/ape/ape.c
+++ b/plugins/ape/ape.c
@@ -130,6 +130,7 @@ ape_insert (DB_playItem_t *after, const char *fname) {
float duration = ape_decompress_get_info_int (dec, APE_DECOMPRESS_TOTAL_BLOCKS) / (float)wfe.nSamplesPerSec;
DB_playItem_t *it = deadbeef->pl_insert_cue (after, fname, &plugin, "APE");
if (it) {
+ ape_decompress_destroy (dec);
it->timeend = duration;
it->duration = it->timeend - it->timestart;
return it;
diff --git a/plugins/demac/Makefile.am b/plugins/demac/Makefile.am
index e1296c5e..62cf42cc 100644
--- a/plugins/demac/Makefile.am
+++ b/plugins/demac/Makefile.am
@@ -1,6 +1,34 @@
demacdir = $(libdir)/$(PACKAGE)
pkglib_LTLIBRARIES = demac.la
-demac_la_SOURCES = demac.c
+demac_la_SOURCES = demac.c\
+libdemac/crc.c\
+libdemac/decoder.c\
+libdemac/decoder.h\
+libdemac/demac_config.h\
+libdemac/demac.h\
+libdemac/entropy.c\
+libdemac/entropy.h\
+libdemac/filter_1280_15.c\
+libdemac/filter_16_11.c\
+libdemac/filter_256_13.c\
+libdemac/filter_32_10.c\
+libdemac/filter_64_11.c\
+libdemac/filter.h\
+libdemac/parser.c\
+libdemac/parser.h\
+libdemac/predictor.c\
+libdemac/predictor.h\
+libdemac/vector_math16_armv5te.h\
+libdemac/vector_math16_armv6.h\
+libdemac/vector_math16_cf.h\
+libdemac/vector_math32_armv4.h\
+libdemac/vector_math_generic.h
+
+EXTRA_demac_la_SOURCES = libdemac/filter.c
+
demac_la_LDFLAGS = -module
#demac_la_LIBADD = $(LDADD) $(demac_LIBS)
#AM_CFLAGS = $(demac_DEPS_CFLAGS) -std=c99
+
+
+
diff --git a/plugins/demac/demac.c b/plugins/demac/demac.c
index a757ebfb..6c3de09d 100644
--- a/plugins/demac/demac.c
+++ b/plugins/demac/demac.c
@@ -1,6 +1,7 @@
/*
DeaDBeeF - ultimate music player for GNU/Linux systems with X11
Copyright (C) 2009 Alexey Yakovenko
+ This plugin is based on code from demac and libdemac (C) Dave Chapman 2007
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@@ -18,8 +19,11 @@
*/
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <time.h>
+#include <assert.h>
#include "../../deadbeef.h"
+#include "libdemac/demac.h"
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
@@ -27,6 +31,472 @@
static DB_decoder_t plugin;
static DB_functions_t *deadbeef;
+#define CALC_CRC 1
+
+#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];
+static int32_t decoded1[BLOCKS_PER_LOOP];
+
+/* We assume that 32KB of compressed data is enough to extract up to
+ 27648 bytes of decompressed data. */
+
+static unsigned char inbuffer[INPUT_CHUNKSIZE];
+
+static int currentframe;
+static uint32_t frame_crc;
+static int crc_errors;
+static FILE *fp;
+static int firstbyte;
+static int bytesinbuffer;
+static struct ape_ctx_t ape_ctx;
+static int bytesconsumed;
+static int timestart;
+static int timeend;
+static int nblocks;
+
+/* 4608*2*3 = 27648 bytes */
+#define WAVBUFFER_SIZE (BLOCKS_PER_LOOP*MAX_CHANNELS*MAX_BYTESPERSAMPLE * 5)
+static uint8_t wavbuffer[WAVBUFFER_SIZE];
+static int bufferfill;
+
+inline static int
+read_uint16(FILE *fp, uint16_t* x)
+{
+ unsigned char tmp[2];
+ int n;
+
+ n = fread(tmp, 1, 2, fp);
+
+ if (n != 2)
+ return -1;
+
+ *x = tmp[0] | (tmp[1] << 8);
+
+ return 0;
+}
+
+
+inline static int
+read_int16(FILE *fp, int16_t* x)
+{
+ return read_uint16(fp, (uint16_t*)x);
+}
+
+inline static int
+read_uint32(FILE *fp, uint32_t* x)
+{
+ unsigned char tmp[4];
+ int n;
+
+ n = fread(tmp, 1, 4, fp);
+
+ if (n != 4)
+ return -1;
+
+ *x = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24);
+
+ return 0;
+}
+
+int
+demac_ape_parseheader(FILE *fp, struct ape_ctx_t* ape_ctx)
+{
+ int i,n;
+
+ /* TODO: Skip any leading junk such as id3v2 tags */
+ ape_ctx->junklength = 0;
+
+ fseek(fp,ape_ctx->junklength,SEEK_SET);
+
+ n = fread (&ape_ctx->magic, 1, 4, fp);
+ if (n != 4) {
+ return -1;
+ }
+
+ if (memcmp(ape_ctx->magic,"MAC ",4)!=0)
+ {
+ return -1;
+ }
+
+ if (read_int16(fp,&ape_ctx->fileversion) < 0) {
+ return -1;
+ }
+
+ if (ape_ctx->fileversion >= 3980)
+ {
+ if (read_int16(fp,&ape_ctx->padding1) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->descriptorlength) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->headerlength) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->seektablelength) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->wavheaderlength) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->audiodatalength) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->audiodatalength_high) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->wavtaillength) < 0)
+ return -1;
+ if (fread(&ape_ctx->md5, 1, 16, fp) != 16)
+ return -1;
+
+ /* Skip any unknown bytes at the end of the descriptor. This is for future
+ compatibility */
+ if (ape_ctx->descriptorlength > 52)
+ fseek(fp,ape_ctx->descriptorlength - 52, SEEK_CUR);
+
+ /* Read header data */
+ if (read_uint16(fp,&ape_ctx->compressiontype) < 0)
+ return -1;
+ if (read_uint16(fp,&ape_ctx->formatflags) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->blocksperframe) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->finalframeblocks) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->totalframes) < 0)
+ return -1;
+ if (read_uint16(fp,&ape_ctx->bps) < 0)
+ return -1;
+ if (read_uint16(fp,&ape_ctx->channels) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->samplerate) < 0)
+ return -1;
+ } else {
+ ape_ctx->descriptorlength = 0;
+ ape_ctx->headerlength = 32;
+
+ if (read_uint16(fp,&ape_ctx->compressiontype) < 0)
+ return -1;
+ if (read_uint16(fp,&ape_ctx->formatflags) < 0)
+ return -1;
+ if (read_uint16(fp,&ape_ctx->channels) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->samplerate) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->wavheaderlength) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->wavtaillength) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->totalframes) < 0)
+ return -1;
+ if (read_uint32(fp,&ape_ctx->finalframeblocks) < 0)
+ return -1;
+
+ if (ape_ctx->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL)
+ {
+ fseek(fp, 4, SEEK_CUR); /* Skip the peak level */
+ ape_ctx->headerlength += 4;
+ }
+
+ if (ape_ctx->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS)
+ {
+ if (read_uint32(fp,&ape_ctx->seektablelength) < 0)
+ return -1;
+ ape_ctx->headerlength += 4;
+ ape_ctx->seektablelength *= sizeof(int32_t);
+ } else {
+ ape_ctx->seektablelength = ape_ctx->totalframes * sizeof(int32_t);
+ }
+
+ if (ape_ctx->formatflags & MAC_FORMAT_FLAG_8_BIT)
+ ape_ctx->bps = 8;
+ else if (ape_ctx->formatflags & MAC_FORMAT_FLAG_24_BIT)
+ ape_ctx->bps = 24;
+ else
+ ape_ctx->bps = 16;
+
+ if (ape_ctx->fileversion >= 3950)
+ ape_ctx->blocksperframe = 73728 * 4;
+ else if ((ape_ctx->fileversion >= 3900) || (ape_ctx->fileversion >= 3800 && ape_ctx->compressiontype >= 4000))
+ ape_ctx->blocksperframe = 73728;
+ else
+ ape_ctx->blocksperframe = 9216;
+
+ /* Skip any stored wav header */
+ if (!(ape_ctx->formatflags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER))
+ {
+ fseek(fp, ape_ctx->wavheaderlength, SEEK_CUR);
+ }
+ }
+
+ ape_ctx->totalsamples = ape_ctx->finalframeblocks;
+ if (ape_ctx->totalframes > 1)
+ ape_ctx->totalsamples += ape_ctx->blocksperframe * (ape_ctx->totalframes-1);
+
+ if (ape_ctx->seektablelength > 0)
+ {
+ ape_ctx->seektable = malloc(ape_ctx->seektablelength);
+ if (ape_ctx->seektable == NULL)
+ return -1;
+ for (i=0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++)
+ {
+ if (read_uint32(fp,&ape_ctx->seektable[i]) < 0)
+ {
+ free(ape_ctx->seektable);
+ return -1;
+ }
+ }
+ }
+
+ ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->descriptorlength +
+ ape_ctx->headerlength + ape_ctx->seektablelength +
+ ape_ctx->wavheaderlength;
+
+ return 0;
+}
+
+FILE *fw;
+
+static int
+demac_init (DB_playItem_t *it) {
+ crc_errors = 0;
+ fw = fopen ("out.raw", "w+b");
+ fp = fopen (it->fname, "rb");
+ if (!fp) {
+ return -1;
+ }
+ if (demac_ape_parseheader (fp, &ape_ctx) < 0) {
+ fprintf (stderr, "demac: failed to read ape header\n");
+ fclose (fp);
+ return -1;
+ }
+ if ((ape_ctx.fileversion < APE_MIN_VERSION) || (ape_ctx.fileversion > APE_MAX_VERSION)) {
+ fprintf(stderr, "demac: unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0);
+ fclose (fp);
+ return -1;
+ }
+ fprintf(stderr, "demac: decoding file - v%.2f, compression level %d\n", ape_ctx.fileversion/1000.0, ape_ctx.compressiontype);
+
+ currentframe = 0;
+ fseek (fp, ape_ctx.firstframe, SEEK_SET);
+ bytesinbuffer = fread (inbuffer, 1, INPUT_CHUNKSIZE, fp);
+ firstbyte = 3;
+
+ plugin.info.bps = ape_ctx.bps;
+ plugin.info.samplerate = ape_ctx.samplerate;
+ plugin.info.channels = ape_ctx.channels;
+ plugin.info.readpos = 0;
+ if (it->timeend > 0) {
+ timestart = it->timestart;
+ timeend = it->timeend;
+ }
+ else {
+ timestart = 0;
+ timeend = it->duration;
+ }
+ nblocks = 0;
+
+ return 0;
+}
+
+static void
+demac_free (void) {
+ if (fp) {
+ fclose (fp);
+ fp = NULL;
+ }
+}
+
+static int
+demac_read (char *buffer, int size) {
+ /* The main decoding loop - we decode the frames a small chunk at a time */
+// fprintf (stderr, "starting read size=%d bufferfill=%d!\n", size, bufferfill);
+ while (currentframe < ape_ctx.totalframes && bufferfill < size)
+ {
+ int n, i;
+ assert (bufferfill < WAVBUFFER_SIZE-(size-bufferfill));
+ if (nblocks <= 0) {
+ /* 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);
+
+ /* Update buffer */
+ memmove(inbuffer,inbuffer + bytesconsumed, bytesinbuffer - bytesconsumed);
+ bytesinbuffer -= bytesconsumed;
+
+ n = fread(inbuffer + bytesinbuffer, 1, INPUT_CHUNKSIZE - bytesinbuffer, fp);
+ bytesinbuffer += n;
+
+#if CALC_CRC
+ frame_crc = ape_initcrc();
+#endif
+ }
+
+ /* Decode the frame a chunk at a time */
+ while (nblocks > 0 && bufferfill < size)
+ {
+ int blockstodecode = min (BLOCKS_PER_LOOP, nblocks);
+ int res;
+ int16_t sample16;
+ int32_t sample32;
+
+ if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte,
+ &bytesconsumed,
+ decoded0, decoded1,
+ blockstodecode)) < 0)
+ {
+ /* Frame decoding error, abort */
+ return 0;
+ }
+
+ /* Convert the output samples to WAV format and write to output file */
+ uint8_t *pp = wavbuffer + bufferfill;
+ uint8_t *p = wavbuffer + bufferfill;
+ if (ape_ctx.bps == 8) {
+ assert (0);
+ for (i = 0 ; i < blockstodecode ; i++)
+ {
+ /* 8 bit WAV uses unsigned samples */
+ *(p++) = (decoded0[i] + 0x80) & 0xff;
+
+ if (ape_ctx.channels == 2) {
+ *(p++) = (decoded1[i] + 0x80) & 0xff;
+ }
+ }
+ } else if (ape_ctx.bps == 16) {
+ for (i = 0 ; i < blockstodecode ; i++)
+ {
+ sample16 = decoded0[i];
+ *(p++) = sample16 & 0xff;
+ *(p++) = (sample16 >> 8) & 0xff;
+ bufferfill += 2;
+
+ if (ape_ctx.channels == 2) {
+ sample16 = decoded1[i];
+ *(p++) = sample16 & 0xff;
+ *(p++) = (sample16 >> 8) & 0xff;
+ bufferfill += 2;
+ }
+ }
+ } else if (ape_ctx.bps == 24) {
+ assert (0);
+ for (i = 0 ; i < blockstodecode ; i++)
+ {
+ sample32 = decoded0[i];
+ *(p++) = sample32 & 0xff;
+ *(p++) = (sample32 >> 8) & 0xff;
+ *(p++) = (sample32 >> 16) & 0xff;
+
+ if (ape_ctx.channels == 2) {
+ sample32 = decoded1[i];
+ *(p++) = sample32 & 0xff;
+ *(p++) = (sample32 >> 8) & 0xff;
+ *(p++) = (sample32 >> 16) & 0xff;
+ }
+ }
+ }
+
+ assert (bufferfill <= WAVBUFFER_SIZE);
+
+#if CALC_CRC
+ frame_crc = ape_updatecrc(pp, p - pp, frame_crc);
+#endif
+ //write(fdwav,wavbuffer,p - wavbuffer);
+
+ /* Update the buffer */
+// fprintf (stderr, "size=%d, nblocks=%d, currframe=%d, bufferfill=%d(%d), bytesconsumed=%d, bytesinbuffer=%d\n", size, nblocks, currentframe, bufferfill, startbfill, bytesconsumed, bytesinbuffer);
+ memmove(inbuffer,inbuffer + bytesconsumed, bytesinbuffer - bytesconsumed);
+ bytesinbuffer -= bytesconsumed;
+
+ n = fread(inbuffer + bytesinbuffer, 1, INPUT_CHUNKSIZE - bytesinbuffer, fp);
+ bytesinbuffer += n;
+
+ /* Decrement the block count */
+ nblocks -= blockstodecode;
+ }
+
+ if (nblocks <= 0) {
+#if CALC_CRC
+ frame_crc = ape_finishcrc(frame_crc);
+
+ if (ape_ctx.CRC != frame_crc)
+ {
+ fprintf(stderr,"CRC error in frame %d\n",currentframe);
+ crc_errors++;
+ }
+#endif
+ currentframe++;
+ }
+ }
+
+ // copy from wavbuffer to buffer
+ int sz = min (bufferfill, size);
+ if (sz) {
+ memcpy (buffer, wavbuffer, sz);
+ if (sz == bufferfill) {
+ bufferfill = 0;
+ }
+ else if (bufferfill > sz) {
+ memmove (wavbuffer, wavbuffer+sz, bufferfill-sz);
+ bufferfill -= sz;
+ }
+ }
+
+ return sz;
+}
+
+static int
+demac_seek (float seconds) {
+ return 0;
+}
+
+static DB_playItem_t *
+demac_insert (DB_playItem_t *after, const char *fname) {
+ struct ape_ctx_t ape_ctx;
+ FILE *fp = fopen (fname, "rb");
+ if (!fp) {
+ return NULL;
+ }
+ if (demac_ape_parseheader (fp, &ape_ctx) < 0) {
+ fprintf (stderr, "demac: failed to read ape header\n");
+ fclose (fp);
+ return NULL;
+ }
+ if ((ape_ctx.fileversion < APE_MIN_VERSION) || (ape_ctx.fileversion > APE_MAX_VERSION)) {
+ fprintf(stderr, "demac: unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0);
+ fclose (fp);
+ return NULL;
+ }
+
+ float duration = ape_ctx.totalsamples / (float)ape_ctx.samplerate;
+ DB_playItem_t *it = deadbeef->pl_insert_cue (after, fname, &plugin, "APE");
+ if (it) {
+ fclose (fp);
+ it->timeend = duration;
+ it->duration = it->timeend - it->timestart;
+ return it;
+ }
+
+ it = deadbeef->pl_item_alloc ();
+ it->decoder = &plugin;
+ it->fname = strdup (fname);
+ it->filetype = "APE";
+ it->duration = duration;
+
+ deadbeef->pl_add_meta (it, "title", NULL);
+ after = deadbeef->pl_insert_item (after, it);
+
+ fclose (fp);
+ return after;
+}
+
static const char *exts[] = { "ape", NULL };
static const char *filetypes[] = { "APE", NULL };
@@ -36,15 +506,15 @@ static DB_decoder_t plugin = {
.plugin.version_minor = 1,
.plugin.type = DB_PLUGIN_DECODER,
.plugin.name = "Monkey's Audio decoder",
- .plugin.descr = "Based on demac",
+ .plugin.descr = "Based on libdemac",
.plugin.author = "Alexey Yakovenko",
.plugin.email = "waker@users.sourceforge.net",
.plugin.website = "http://deadbeef.sf.net",
-/// .init = demac_init,
-/// .free = demac_free,
-/// .read_int16 = demac_read,
-/// .seek = demac_seek,
-/// .insert = demac_insert,
+ .init = demac_init,
+ .free = demac_free,
+ .read_int16 = demac_read,
+ .seek = demac_seek,
+ .insert = demac_insert,
.exts = exts,
.id = "stddemac",
.filetypes = filetypes