summaryrefslogtreecommitdiff
path: root/plugins/demac/demac.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/demac/demac.c')
-rw-r--r--plugins/demac/demac.c656
1 files changed, 0 insertions, 656 deletions
diff --git a/plugins/demac/demac.c b/plugins/demac/demac.c
deleted file mode 100644
index 508b0ac1..00000000
--- a/plugins/demac/demac.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- DeaDBeeF - ultimate music player for GNU/Linux systems with X11
- Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
- 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
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*/
-#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))
-
-static DB_decoder_t plugin;
-static DB_functions_t *deadbeef;
-
-#define CALC_CRC 0
-
-#define BLOCKS_PER_LOOP 4608
-#define MAX_CHANNELS 2
-#define MAX_BYTESPERSAMPLE 4
-
-#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;
-static int samplestoskip;
-static int samplesdecoded;
-
-static float ape_duration;
-
-// 5x big to fit extra data while streaming
-#define WAVBUFFER_SIZE (BLOCKS_PER_LOOP*MAX_CHANNELS*MAX_BYTESPERSAMPLE * 5)
-static uint8_t wavbuffer[WAVBUFFER_SIZE];
-static int bufferfill;
-
-// precalc for converting samples from internal format to float32
-static int32_t mask;
-static float scaler;
-static int32_t neg;
-static int32_t sign;
-static int32_t signshift;
-
-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;
- memset (ape_ctx, 0, sizeof (struct ape_ctx_t));
-
- /* 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);
- ape_ctx->seektable = NULL;
- return -1;
- }
- }
- ape_ctx->numseekpoints = ape_ctx->seektablelength/sizeof (int32_t);
- }
-
- ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->descriptorlength +
- ape_ctx->headerlength + ape_ctx->seektablelength +
- ape_ctx->wavheaderlength;
-
- return 0;
-}
-
-static int
-demac_seek (float seconds);
-
-static int
-demac_init (DB_playItem_t *it) {
- crc_errors = 0;
- 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);
- fp = NULL;
- if (ape_ctx.seektable) {
- free (ape_ctx.seektable);
- ape_ctx.seektable = NULL;
- }
- 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);
- fp = NULL;
- if (ape_ctx.seektable) {
- free (ape_ctx.seektable);
- ape_ctx.seektable = NULL;
- }
- 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;
- bufferfill = 0;
- bytesconsumed = 0;
- nblocks = 0;
- samplestoskip = 0;
- samplesdecoded = 0;
-
- plugin.info.bps = ape_ctx.bps;
- plugin.info.samplerate = ape_ctx.samplerate;
- plugin.info.channels = ape_ctx.channels;
- plugin.info.readpos = 0;
- ape_duration = it->duration;
- if (it->timeend > 0) {
- timestart = it->timestart;
- timeend = it->timeend;
- demac_seek (0);
- }
- else {
- timestart = 0;
- timeend = it->duration;
- }
-
- mask = (1<<(ape_ctx.bps-1))-1;
- scaler = 1.f / ((1<<(ape_ctx.bps-1))-1);
- neg = 1<<ape_ctx.bps;
- sign = (1<<31);
- signshift = ape_ctx.bps-1;
- return 0;
-}
-
-static void
-demac_free (void) {
- if (fp) {
- fclose (fp);
- fp = NULL;
- if (ape_ctx.seektable) {
- free (ape_ctx.seektable);
- ape_ctx.seektable = NULL;
- }
- }
-}
-
-static int
-demac_decode (int size) {
- /* The main decoding loop - we decode the frames a small chunk at a time */
- int32_t mask = (1<<(ape_ctx.bps-1))-1;
- float scaler = 1.f / ((1<<(ape_ctx.bps-1))-1);
- int32_t neg = 1<<ape_ctx.bps;
- int32_t sign = (1<<31);
- int32_t signshift = ape_ctx.bps-1;
- 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;
- if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte,
- &bytesconsumed,
- decoded0, decoded1,
- blockstodecode)) < 0)
- {
- /* Frame decoding error, abort */
- return -1;
- }
-
-#if CALC_CRC
- uint8_t *pp = wavbuffer + bufferfill;
-#endif
- uint8_t *p = wavbuffer + bufferfill;
- int i = 0;
- // skip if needed
- int n = min (samplestoskip, blockstodecode);
- i += n;
- samplestoskip -= n;
- samplesdecoded += n;
-
- for (; i < blockstodecode ; i++)
- {
- int32_t sample;
- sample = decoded0[i];
- *((float *)p) = (sample - ((sample&sign)>>signshift)*neg) * scaler;
- p += sizeof (float);
- bufferfill += sizeof (float);
- if (ape_ctx.channels == 2) {
- sample = decoded1[i];
- *((float *)p) = (sample - ((sample&sign)>>signshift)*neg) * scaler;
- p += sizeof (float);
- bufferfill += sizeof (float);
- }
- samplesdecoded++;
- }
-
- assert (bufferfill <= WAVBUFFER_SIZE);
-
-#if CALC_CRC
- frame_crc = ape_updatecrc(pp, p - pp, frame_crc);
-#endif
- 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++;
- }
- }
- return 0;
-}
-
-static int
-demac_read_int16 (char *buffer, int size) {
- if (demac_decode (size*2) < 0) {
- return -1;
- }
- // float->int16
- int avail = bufferfill / sizeof (float);
- int s = size/2;
- int sz = min (avail, s);
- if (sz) {
- float *p = (float *)wavbuffer;
- for (int i = 0; i < sz; i++) {
- *((int16_t *)buffer) = (int16_t)(*p * 0x7fff);
- buffer += 2;
- p++;
- }
-// memcpy (buffer, wavbuffer, sz);
- if (bufferfill > sz * sizeof (float)) {
- memmove (wavbuffer, wavbuffer + (sz * sizeof (float)), bufferfill - (sz * sizeof (float)));
- }
- bufferfill -= sz * sizeof (float);
- assert (bufferfill >= 0);
- }
- plugin.info.readpos = samplesdecoded / (float)plugin.info.samplerate - timestart;
- if (plugin.info.readpos >= (timeend - timestart)) {
- return 0;
- }
- return sz * 2;
-}
-
-static int
-demac_read_float32 (char *buffer, int size) {
- if (demac_decode (size) < 0) {
- return -1;
- }
- int sz = min (bufferfill, size);
- if (sz) {
- memcpy (buffer, wavbuffer, sz);
- if (bufferfill > sz) {
- memmove (wavbuffer, wavbuffer + sz, bufferfill - sz);
- }
- bufferfill -= sz;
- assert (bufferfill >= 0);
- }
- plugin.info.readpos = samplesdecoded / (float)plugin.info.samplerate - timestart;
- if (plugin.info.readpos >= (timeend - timestart)) {
- return 0;
- }
- return sz;
-}
-
-/* Given an ape_ctx and a sample to seek to, return the file position
- to the frame containing that sample, and the number of samples to
- skip in that frame.
- */
-
-static int ape_calc_seekpos(struct ape_ctx_t* ape_ctx,
- uint32_t new_sample,
- uint32_t* newframe,
- uint32_t* filepos,
- uint32_t* samplestoskip)
-{
- uint32_t n;
-
- n = new_sample / ape_ctx->blocksperframe;
- if (n >= ape_ctx->numseekpoints)
- {
- /* We don't have a seekpoint for that frame */
- return 0;
- }
-
- *newframe = n;
- *filepos = ape_ctx->seektable[n];
- *samplestoskip = new_sample - (n * ape_ctx->blocksperframe);
-
- return 1;
-}
-
-
-static int
-demac_seek (float seconds) {
- seconds += timestart;
- uint32_t newsample = seconds * plugin.info.samplerate;
- if (newsample > ape_ctx.totalsamples) {
- return -1;
- }
- uint32_t nf, fpos;
- if (ape_calc_seekpos (&ape_ctx, newsample, &nf, &fpos, &samplestoskip)) {
- firstbyte = 3 - (fpos & 3);
- fpos &= ~3;
- fseek (fp, fpos, SEEK_SET);
- bytesinbuffer = fread (inbuffer, 1, INPUT_CHUNKSIZE, fp);
- bufferfill = 0;
- bytesconsumed = 0;
- nblocks = 0;
- samplesdecoded = newsample-samplestoskip;
- plugin.info.readpos = seconds;
- currentframe = nf;
- }
- else {
- // no seektable
- if (newsample > samplesdecoded) {
- samplestoskip = newsample - samplesdecoded;
- }
- else {
- fpos = ape_ctx.firstframe;
- samplestoskip = newsample;
- firstbyte = 3 - (fpos & 3);
- fpos &= ~3;
- fseek (fp, fpos, SEEK_SET);
- bytesinbuffer = fread (inbuffer, 1, INPUT_CHUNKSIZE, fp);
- bufferfill = 0;
- bytesconsumed = 0;
- nblocks = 0;
- samplesdecoded = 0;
- }
- }
- plugin.info.readpos = seconds - timestart;
- 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;
- }
-// ape_dumpinfo (&ape_ctx);
- 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;
- it = deadbeef->pl_insert_cue (after, fname, &plugin, "APE", duration);
- if (it) {
- fclose (fp);
- return it;
- }
-
- it = deadbeef->pl_item_alloc ();
- it->decoder = &plugin;
- it->fname = strdup (fname);
- it->filetype = "APE";
- it->duration = duration;
-
- int v2err = deadbeef->junk_read_id3v2 (it, fp);
- int v1err = deadbeef->junk_read_id3v1 (it, fp);
- if (v1err >= 0) {
- fseek (fp, -128, SEEK_END);
- }
- else {
- fseek (fp, 0, SEEK_END);
- }
- int apeerr = deadbeef->junk_read_ape (it, fp);
- 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 };
-
-// define plugin interface
-static DB_decoder_t plugin = {
- DB_PLUGIN_SET_API_VERSION
- .plugin.version_major = 0,
- .plugin.version_minor = 1,
- .plugin.type = DB_PLUGIN_DECODER,
- .plugin.name = "Monkey's Audio decoder",
- .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_int16,
- .read_float32 = demac_read_float32,
- .seek = demac_seek,
- .insert = demac_insert,
- .exts = exts,
- .id = "stddemac",
- .filetypes = filetypes
-};
-
-DB_plugin_t *
-demac_load (DB_functions_t *api) {
- deadbeef = api;
- return DB_PLUGIN (&plugin);
-}