Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 447 lines (348 sloc) 9.83 KB
/* --------------------------------------------------------------------------
flactag -- A tagger for single album FLAC files with embedded CUE sheets
using data retrieved from the MusicBrainz service
Copyright (C) 2006-2012 Andrew Hawkins
Copyright (C) 2011-2012 Daniel Pocock
This file is part of flactag.
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 3 of the License, or
(at your option) any later version.
Flactag 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
Lesser General Public License for more details.
You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
$Id$
----------------------------------------------------------------------------*/
#include "FlacInfo.h"
#include "TagName.h"
#include "ErrorLog.h"
#include <sstream>
CFlacInfo::CFlacInfo()
: m_TagBlock(0),
m_PictureBlock(0),
m_CuesheetFound(false)
{
}
CFlacInfo::~CFlacInfo()
{
if (m_TagBlock)
delete m_TagBlock;
if (m_PictureBlock)
delete m_PictureBlock;
}
bool CFlacInfo::CuesheetFound() const
{
return m_CuesheetFound;
}
void CFlacInfo::SetFileName(const std::string& FileName)
{
m_Tags.clear();
m_Cuesheet.Clear();
m_CoverArt.Clear();
m_FileName=FileName;
if (m_TagBlock)
delete m_TagBlock;
m_TagBlock=0;
if (m_PictureBlock)
delete m_PictureBlock;
m_PictureBlock=0;
m_CuesheetFound=false;
}
bool CFlacInfo::Read()
{
bool RetVal=false;
m_Tags.clear();
m_Cuesheet.Clear();
m_CoverArt.Clear();
if (m_TagBlock)
delete m_TagBlock;
m_TagBlock=0;
if (m_PictureBlock)
delete m_PictureBlock;
m_PictureBlock=0;
m_CuesheetFound=false;
if (!m_FileName.empty())
{
if (m_Chain.read(m_FileName.c_str()))
{
if (m_Chain.is_valid())
{
FLAC::Metadata::Iterator Iterator;
Iterator.init(m_Chain);
if (Iterator.is_valid())
{
do
{
switch (Iterator.get_block_type())
{
case FLAC__METADATA_TYPE_STREAMINFO:
break;
case FLAC__METADATA_TYPE_PADDING:
break;
case FLAC__METADATA_TYPE_APPLICATION:
break;
case FLAC__METADATA_TYPE_SEEKTABLE:
break;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
m_TagBlock=(FLAC::Metadata::VorbisComment *)Iterator.get_block();
if (m_TagBlock->is_valid())
{
for (unsigned count=0;count<m_TagBlock->get_num_comments();count++)
{
FLAC::Metadata::VorbisComment::Entry Entry=m_TagBlock->get_comment(count);
std::string Name(Entry.get_field_name(),Entry.get_field_name_length());
std::string Value(Entry.get_field_value(),Entry.get_field_value_length());
m_Tags[CTagName(Name)]=CUTF8Tag(Value);
}
}
break;
case FLAC__METADATA_TYPE_CUESHEET:
{
m_CuesheetFound=true;
FLAC::Metadata::CueSheet *Cuesheet=(FLAC::Metadata::CueSheet *)Iterator.get_block();
for (unsigned count=0;count<Cuesheet->get_num_tracks();count++)
{
FLAC::Metadata::CueSheet::Track Track=Cuesheet->get_track(count);
if (Track.get_number()==170)
m_Cuesheet.SetLeadout(CalculateOffset(Track));
else
m_Cuesheet.AddTrack(CCuesheetTrack(Track.get_number(),CalculateOffset(Track)));
}
delete Cuesheet;
break;
}
case FLAC__METADATA_TYPE_UNDEFINED:
break;
#ifdef FLAC_API_VERSION_CURRENT
case FLAC__METADATA_TYPE_PICTURE:
m_PictureBlock=(FLAC::Metadata::Picture *)Iterator.get_block();
if (m_PictureBlock->is_valid())
m_CoverArt.SetArt(m_PictureBlock->get_data(),m_PictureBlock->get_data_length(),true);
break;
#endif
}
} while (Iterator.next());
}
}
}
}
if(m_CuesheetFound)
UpdateCuesheet();
return RetVal;
}
bool CFlacInfo::UpdateCuesheet()
{
std::map<int, std::string> Titles;
std::map<int, std::string> Artists;
std::map<int, int> trackMappings;
tTagMap::iterator iterator;
std::map<int, int>::iterator it2;
for(iterator=m_Tags.begin(); iterator!=m_Tags.end(); iterator++)
{
const CTagName& tagName = iterator->first;
const CUTF8Tag& tagValue = iterator->second;
if(tagName == CTagName("ALBUM"))
m_Cuesheet.setTitle(tagValue.UTF8Value());
else if(tagName == CTagName("ARTIST"))
m_Cuesheet.setPerformer(tagValue.UTF8Value());
if(tagName.Number() > -1)
{
if(tagName.Name() == "TRACKNUMBER")
trackMappings[tagName.Number()] = atoi(tagValue.DisplayValue().c_str());
else if(tagName.Name() == "ARTIST")
Artists[tagName.Number()] = tagValue.DisplayValue();
else if(tagName.Name() == "TITLE")
Titles[tagName.Number()] = tagValue.DisplayValue();
}
}
for(it2=trackMappings.begin(); it2!=trackMappings.end(); it2++)
{
int trackNum = it2->second;
m_Cuesheet.setTrackPerformer(trackNum, Artists[it2->first]);
m_Cuesheet.setTrackTitle(trackNum, Titles[it2->first]);
}
return true;
}
tTagMap CFlacInfo::Tags() const
{
return m_Tags;
}
CCoverArt CFlacInfo::CoverArt() const
{
return m_CoverArt;
}
CCuesheet CFlacInfo::Cuesheet() const
{
return m_Cuesheet;
}
std::string CFlacInfo::WriteError() const
{
return m_WriteError;
}
int CFlacInfo::CalculateOffset(const FLAC::Metadata::CueSheet::Track& Track) const
{
FLAC__uint64 Offset=Track.get_offset();
FLAC__uint64 MaxIndexOffset=0;
for (unsigned count=0;count<Track.get_num_indices();count++)
{
FLAC__StreamMetadata_CueSheet_Index Index=Track.get_index(count);
if (Index.number==1)
MaxIndexOffset=Index.offset;
}
Offset+=MaxIndexOffset;
Offset/=588;
Offset+=150;
return Offset;
}
bool CFlacInfo::WriteInfo(const CWriteInfo& WriteInfo)
{
bool RetVal=true;
if (m_TagBlock)
{
while (m_TagBlock->get_num_comments())
m_TagBlock->delete_comment(0);
tTagMap Tags=WriteInfo.Tags();
tTagMapConstIterator ThisTag=Tags.begin();
while (Tags.end()!=ThisTag)
{
CTagName Name=(*ThisTag).first;
CUTF8Tag Value=(*ThisTag).second;
if (!Value.empty())
{
FLAC::Metadata::VorbisComment::Entry NewEntry;
if (!NewEntry.set_field_name(Name.String().c_str()))
{
std::stringstream os;
os << "Error setting field name: '" << Name.String() << "'";
CErrorLog::Log(os.str());
}
if (!NewEntry.set_field_value(Value.UTF8Value().c_str(),Value.UTF8Value().length()))
{
std::stringstream os;
os << "Error setting field value: '" << Value.DisplayValue() << "' for '" << Name.String() << "'";
CErrorLog::Log(os.str());
}
if (!m_TagBlock->insert_comment(m_TagBlock->get_num_comments(),NewEntry))
{
std::stringstream os;
os << "Error inserting comment: '" << Value.DisplayValue() << "' for '" << Name.String() << "'";
CErrorLog::Log(os.str());
}
}
++ThisTag;
}
#ifdef FLAC_API_VERSION_CURRENT
if (WriteInfo.CoverArt())
{
if (m_PictureBlock)
SetPictureBlock(WriteInfo.CoverArt());
else
{
FLAC::Metadata::Iterator Iterator;
Iterator.init(m_Chain);
if (Iterator.is_valid())
{
//Move to the end
while (Iterator.next())
;
m_PictureBlock = new FLAC::Metadata::Picture;
SetPictureBlock(WriteInfo.CoverArt());
//insert_block_after takes ownership of the block
//we need to get it back out again so we have ownership
if (Iterator.insert_block_after(m_PictureBlock))
{
Iterator.next();
if (Iterator.get_block_type()==FLAC__METADATA_TYPE_PICTURE)
{
m_PictureBlock=(FLAC::Metadata::Picture *)Iterator.get_block();
}
}
}
}
}
else
{
if (m_PictureBlock)
{
FLAC::Metadata::Iterator Iterator;
Iterator.init(m_Chain);
if (Iterator.is_valid())
{
bool Found=false;
do
{
switch (Iterator.get_block_type())
{
case FLAC__METADATA_TYPE_PICTURE:
{
Found=true;
RetVal=Iterator.delete_block(true);
break;
}
default:
break;
}
} while (!Found && Iterator.next());
}
}
}
#endif
if (RetVal)
{
RetVal=m_Chain.write();
if (!RetVal)
{
FLAC::Metadata::Chain::Status Status=m_Chain.status();
m_WriteError=Status.as_cstring();
}
}
}
else
{
m_WriteError.assign("no tag block exists in the FLAC file, create one with metaflac --set-tag=ARTIST=unset <filename.flac>");
RetVal=false;
}
return RetVal;
}
void CFlacInfo::SetTag(const CTagName& Name, const std::string& Value)
{
bool Found=false;
for (unsigned count=0;count<m_TagBlock->get_num_comments();count++)
{
FLAC::Metadata::VorbisComment::Entry Entry=m_TagBlock->get_comment(count);
std::string ThisField=Entry.get_field_name();
if (ThisField==Name.String())
Found=true;
if (Found)
{
Entry.set_field_name(Name.String().c_str());
Entry.set_field_value(Value.c_str(),Value.length());
m_TagBlock->set_comment(count,Entry);
}
}
if (!Found)
{
FLAC::Metadata::VorbisComment::Entry NewEntry;
NewEntry.set_field_name(Name.String().c_str());
NewEntry.set_field_value(Value.c_str(),Value.length());
m_TagBlock->insert_comment(m_TagBlock->get_num_comments(),NewEntry);
}
}
void CFlacInfo::SetPictureBlock(const CCoverArt& CoverArt)
{
if (m_PictureBlock)
{
m_PictureBlock->set_type(FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER);
unsigned char *TmpData=new unsigned char[CoverArt.Length()];
memcpy(TmpData,CoverArt.Data(),CoverArt.Length());
m_PictureBlock->set_data(TmpData,CoverArt.Length());
delete[] TmpData;
m_PictureBlock->set_width(CoverArt.Width());
m_PictureBlock->set_height(CoverArt.Height());
m_PictureBlock->set_mime_type("image/jpeg");
}
}
Something went wrong with that request. Please try again.