diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2010-05-31 22:27:19 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2010-05-31 22:27:19 +0200 |
commit | d1cf5097c00388345932d244e8170d35be46df3d (patch) | |
tree | d58fb82dbc3bf42d18ba86ecb4e72cd95e8f46bc /plugins/tta/ttaplug.c | |
parent | 5f86a54bab8190c4253a2c3254667cb77df5a800 (diff) |
WIP tta plugin
Diffstat (limited to 'plugins/tta/ttaplug.c')
-rw-r--r-- | plugins/tta/ttaplug.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/plugins/tta/ttaplug.c b/plugins/tta/ttaplug.c new file mode 100644 index 00000000..32fa3574 --- /dev/null +++ b/plugins/tta/ttaplug.c @@ -0,0 +1,315 @@ +/* + DeaDBeeF - ultimate music player for GNU/Linux systems with X11 + Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net> + + 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, see <http://www.gnu.org/licenses/>. +*/ +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <limits.h> +#include <unistd.h> +#include "ttalib.h" +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "../../deadbeef.h" + +#pragma GCC optimize("O0") + +#define min(x,y) ((x)<(y)?(x):(y)) +#define max(x,y) ((x)>(y)?(x):(y)) + +#define trace(...) { fprintf (stderr, __VA_ARGS__); } +//#define trace(fmt,...) + +static DB_decoder_t plugin; +static DB_functions_t *deadbeef; + +#define MAX_BSIZE (MAX_BPS>>3) + +typedef struct { + DB_fileinfo_t info; + tta_info tta; + int currentsample; + int startsample; + int endsample; + char buffer[PCM_BUFFER_LENGTH * MAX_BSIZE * MAX_NCH]; + int remaining; +} tta_info_t; + +static DB_fileinfo_t * +tta_open (void) { + DB_fileinfo_t *_info = malloc (sizeof (tta_info_t)); + tta_info_t *info = (tta_info_t *)_info; + memset (info, 0, sizeof (tta_info_t)); + return _info; +} + +static int +tta_init (DB_fileinfo_t *_info, DB_playItem_t *it) { + tta_info_t *info = (tta_info_t *)_info; + + if (open_tta_file (it->fname, &info->tta, 0) != 0) { + fprintf (stderr, "tta: failed to open %s\n", it->fname); + return -1; + } + + if (player_init (&info->tta) != 0) { + fprintf (stderr, "tta: failed to init player for %s\n", it->fname); + return -1; + } + + _info->bps = info->tta.BPS; + _info->channels = info->tta.NCH; + _info->samplerate = info->tta.SAMPLERATE; + _info->readpos = 0; + _info->plugin = &plugin; + + if (it->endsample > 0) { + info->startsample = it->startsample; + info->endsample = it->endsample; + plugin.seek_sample (_info, 0); + } + else { + info->startsample = 0; + info->endsample = (info->tta.DATALENGTH)-1; + } + return 0; +} + +static void +tta_free (DB_fileinfo_t *_info) { + tta_info_t *info = (tta_info_t *)_info; + if (info) { + player_stop (); + close_tta_file (&info->tta); + free (info); + } +} + +static int +tta_read_int16 (DB_fileinfo_t *_info, char *bytes, int size) { + tta_info_t *info = (tta_info_t *)_info; + if (info->currentsample + size / (2 * _info->channels) > info->endsample) { + size = (info->endsample - info->currentsample + 1) * 2 * _info->channels; + if (size <= 0) { + return 0; + } + } + + int initsize = size; + int out_channels = _info->channels; + if (out_channels > 2) { + out_channels = 2; + } + int sample_size = ((_info->bps >> 3) * out_channels); + + while (size > 0) { + if (info->remaining > 0) { + int n = size / sample_size; + n = min (n, info->remaining); + int nn = n; + char *p = info->buffer; + while (n > 0) { + memcpy (bytes, p, 2); + bytes += 2; + if (_info->channels == 2) { + memcpy (bytes, p + 2, 2); + bytes += 2; + } + n--; + size -= sample_size; + p += info->tta.NCH * info->tta.BSIZE; + } + if (info->remaining > nn) { + memmove (info->buffer, p, (info->remaining - nn) * sizeof (float) * _info->channels); + } + info->remaining -= nn; + } + + if (size > 0 && !info->remaining) { + info->remaining = get_samples (info->buffer); + if (!info->remaining) { + break; + } + } + } + return initsize-size; +} + +static int +tta_seek_sample (DB_fileinfo_t *_info, int sample) { + tta_info_t *info = (tta_info_t *)_info; + if (set_position (sample * 1000 / info->tta.SAMPLERATE / SEEK_STEP) != 0) { + fprintf (stderr, "tta: seek failed\n"); + return -1; + } + info->currentsample = sample; + _info->readpos = (sample - info->startsample) / _info->samplerate; + return 0; +} + +static int +tta_seek (DB_fileinfo_t *_info, float time) { + tta_info_t *info = (tta_info_t *)_info; + return tta_seek_sample (_info, time * _info->samplerate); +} + +static DB_playItem_t * +tta_insert (DB_playItem_t *after, const char *fname) { + tta_info tta; + if (open_tta_file (fname, &tta, 0) != 0) { + fprintf (stderr, "tta: failed to open %s\n", fname); + return NULL; + } + + if (tta.BPS != 16) { + fprintf (stderr, "tta: only 16 bit is supported yet, skipped %s\n", fname); + return NULL; + } + + int totalsamples = tta.DATALENGTH; + double dur = tta.LENGTH; + + DB_playItem_t *it = deadbeef->pl_item_alloc (); + it->decoder_id = deadbeef->plug_get_decoder_id (plugin.plugin.id); + it->fname = strdup (fname); + it->filetype = "TTA"; + deadbeef->pl_set_item_duration (it, dur); + + close_tta_file (&tta); + DB_FILE *fp = deadbeef->fopen (fname); + if (fp) { + /*int v2err = */deadbeef->junk_id3v2_read (it, fp); + /*int v1err = */deadbeef->junk_id3v1_read (it, fp); + deadbeef->fclose (fp); + } + + // embedded cue + deadbeef->pl_lock (); + const char *cuesheet = deadbeef->pl_find_meta (it, "cuesheet"); + DB_playItem_t *cue = NULL; + if (cuesheet) { + cue = deadbeef->pl_insert_cue_from_buffer (after, it, cuesheet, strlen (cuesheet), totalsamples, tta.SAMPLERATE); + if (cue) { + deadbeef->pl_item_unref (it); + deadbeef->pl_item_unref (cue); + deadbeef->pl_unlock (); + return cue; + } + } + deadbeef->pl_unlock (); + + cue = deadbeef->pl_insert_cue (after, it, totalsamples, tta.SAMPLERATE); + if (cue) { + deadbeef->pl_item_unref (it); + deadbeef->pl_item_unref (cue); + return cue; + } + + deadbeef->pl_add_meta (it, "title", NULL); + after = deadbeef->pl_insert_item (after, it); + deadbeef->pl_item_unref (it); + + return after; +} + +static int tta_read_metadata (DB_playItem_t *it) { + DB_FILE *fp = deadbeef->fopen (it->fname); + if (!fp) { + return -1; + } + deadbeef->pl_delete_all_meta (it); + /*int v2err = */deadbeef->junk_id3v2_read (it, fp); + /*int v1err = */deadbeef->junk_id3v1_read (it, fp); + deadbeef->pl_add_meta (it, "title", NULL); + deadbeef->fclose (fp); + return 0; +} + +static int tta_write_metadata (DB_playItem_t *it) { + // get options + + int strip_id3v2 = 0; + int strip_id3v1 = 0; + int write_id3v2 = 1; + int write_id3v1 = 1; + + uint32_t junk_flags = 0; + if (strip_id3v2) { + junk_flags |= JUNK_STRIP_ID3V2; + } + if (strip_id3v1) { + junk_flags |= JUNK_STRIP_ID3V1; + } + if (write_id3v2) { + junk_flags |= JUNK_WRITE_ID3V2; + } + if (write_id3v1) { + junk_flags |= JUNK_WRITE_ID3V1; + } + + int id3v2_version = 4; + const char *id3v1_encoding = deadbeef->conf_get_str ("mp3.id3v1_encoding", "iso8859-1"); + return deadbeef->junk_rewrite_tags (it, junk_flags, id3v2_version, id3v1_encoding); +} + + +static int +tta_start (void) { + return 0; +} + +static int +tta_stop (void) { + return 0; +} + +static const char * exts[] = { "tta", NULL }; +static const char *filetypes[] = { "TTA", 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.id = "tta", + .plugin.name = "tta decoder", + .plugin.descr = "tta decoder using libmppdec", + .plugin.author = "Alexey Yakovenko", + .plugin.email = "waker@users.sourceforge.net", + .plugin.website = "http://deadbeef.sf.net", + .plugin.start = tta_start, + .plugin.stop = tta_stop, + .open = tta_open, + .init = tta_init, + .free = tta_free, + .read_int16 = tta_read_int16, +// .read_float32 = tta_read_float32, + .seek = tta_seek, + .seek_sample = tta_seek_sample, + .insert = tta_insert, + .read_metadata = tta_read_metadata, + .write_metadata = tta_write_metadata, + .exts = exts, + .filetypes = filetypes +}; + +DB_plugin_t * +tta_load (DB_functions_t *api) { + deadbeef = api; + return DB_PLUGIN (&plugin); +} |