aboutsummaryrefslogtreecommitdiffstats
path: root/src/inputPlugins/_flac_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/inputPlugins/_flac_common.c')
-rw-r--r--src/inputPlugins/_flac_common.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/inputPlugins/_flac_common.c b/src/inputPlugins/_flac_common.c
new file mode 100644
index 000000000..f6a470ed2
--- /dev/null
+++ b/src/inputPlugins/_flac_common.c
@@ -0,0 +1,195 @@
+/* the Music Player Daemon (MPD)
+ * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
+ * This project's homepage is: http://www.musicpd.org
+ *
+ * Common data structures and functions used by FLAC and OggFLAC
+ * (c) 2005 by Eric Wong <normalperson@yhbt.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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "../inputPlugin.h"
+
+#if defined(HAVE_FLAC) || defined(HAVE_OGGFLAC)
+
+#include "_flac_common.h"
+
+#include "../log.h"
+#include "../tag.h"
+#include "../inputStream.h"
+#include "../outputBuffer.h"
+#include "../decode.h"
+#include "../replayGain.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <FLAC/format.h>
+#include <FLAC/metadata.h>
+
+void init_FlacData (FlacData * data, OutputBuffer * cb,
+ DecoderControl * dc, InputStream * inStream)
+{
+ data->chunk_length = 0;
+ data->time = 0;
+ data->position = 0;
+ data->bitRate = 0;
+ data->cb = cb;
+ data->dc = dc;
+ data->inStream = inStream;
+ data->replayGainInfo = NULL;
+ data->tag = NULL;
+}
+
+static int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block,
+ char * cmnt, float * fl)
+{
+ int offset = FLAC__metadata_object_vorbiscomment_find_entry_from(
+ block,0,cmnt);
+
+ if(offset >= 0) {
+ size_t pos = strlen(cmnt)+1; /* 1 is for '=' */
+ int len = block->data.vorbis_comment.comments[offset].length
+ -pos;
+ if(len > 0) {
+ unsigned char tmp;
+ unsigned char * dup = &(block->data.vorbis_comment.
+ comments[offset].entry[pos]);
+ tmp = dup[len];
+ dup[len] = '\0';
+ *fl = atof((char *)dup);
+ dup[len] = tmp;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* replaygain stuff by AliasMrJones */
+static void flacParseReplayGain(const FLAC__StreamMetadata *block,
+ FlacData * data) {
+ unsigned int found = 0;
+
+ if (data->replayGainInfo)
+ freeReplayGainInfo(data->replayGainInfo);
+
+ data->replayGainInfo = newReplayGainInfo();
+
+ found &= flacFindVorbisCommentFloat(block,"replaygain_album_gain",
+ &data->replayGainInfo->albumGain);
+ found &= flacFindVorbisCommentFloat(block,"replaygain_album_peak",
+ &data->replayGainInfo->albumPeak);
+ found &= flacFindVorbisCommentFloat(block,"replaygain_track_gain",
+ &data->replayGainInfo->trackGain);
+ found &= flacFindVorbisCommentFloat(block,"replaygain_track_peak",
+ &data->replayGainInfo->trackPeak);
+
+ if (!found) {
+ freeReplayGainInfo(data->replayGainInfo);
+ data->replayGainInfo = NULL;
+ }
+}
+
+/* tracknumber is used in VCs, MPD uses "track" ..., all the other
+ * tag names match */
+static const char * VORBIS_COMMENT_TRACK_KEY = "tracknumber";
+
+static unsigned int commentMatchesAddToTag(
+ const FLAC__StreamMetadata_VorbisComment_Entry * entry,
+ unsigned int itemType,
+ MpdTag ** tag)
+{
+ const char * str = (itemType == TAG_ITEM_TRACK) ?
+ VORBIS_COMMENT_TRACK_KEY : mpdTagItemKeys[itemType];
+ size_t slen = strlen(str);
+ int vlen = entry->length - slen - 1;
+
+ if ((vlen > 0) && (0 == strncasecmp(str,(char *)entry->entry, slen))
+ && (*(entry->entry + slen) == '=')) {
+ if (!*tag)
+ *tag = newMpdTag();
+
+ addItemToMpdTagWithLen(*tag, itemType,
+ (char *)(entry->entry+slen + 1), vlen);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+MpdTag * copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
+ MpdTag * tag)
+{
+ unsigned int i, j;
+ FLAC__StreamMetadata_VorbisComment_Entry *comments;
+
+ comments = block->data.vorbis_comment.comments;
+
+ for (i = block->data.vorbis_comment.num_comments; i != 0; --i) {
+ for (j = TAG_NUM_OF_ITEM_TYPES; j--; ) {
+ if (commentMatchesAddToTag(comments, j, &tag))
+ break;
+ }
+ comments++;
+ }
+
+ return tag;
+}
+
+void flac_metadata_common_cb(const FLAC__StreamMetadata *block, FlacData *data)
+{
+ DecoderControl *dc = data->dc;
+ const FLAC__StreamMetadata_StreamInfo *si = &(block->data.stream_info);
+
+ switch(block->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ dc->audioFormat.bits = si->bits_per_sample;
+ dc->audioFormat.sampleRate = si->sample_rate;
+ dc->audioFormat.channels = si->channels;
+ dc->totalTime = ((float)si->total_samples) / (si->sample_rate);
+ getOutputAudioFormat(&(dc->audioFormat),
+ &(data->cb->audioFormat));
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ flacParseReplayGain(block,data);
+ default:
+ break;
+ }
+}
+
+void flac_error_common_cb( const char * plugin,
+ const FLAC__StreamDecoderErrorStatus status,
+ FlacData *data)
+{
+ if(data->dc->stop) return;
+
+ switch(status) {
+ case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
+ ERROR("%s lost sync\n", plugin);
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
+ ERROR("bad %s header\n", plugin);
+ break;
+ case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
+ ERROR("%s crc mismatch\n", plugin);
+ break;
+ default:
+ ERROR("unknown %s error\n",plugin);
+ }
+}
+
+#endif /* HAVE_FLAC || HAVE_OGGFLAC */