added .mod file support

This commit is contained in:
Mathias Panzenböck
2011-06-14 03:47:08 +02:00
parent 812826fe3a
commit f75f5ac9bb
17 changed files with 374 additions and 123 deletions

164
taglib/mod/modfile.cpp Normal file
View File

@ -0,0 +1,164 @@
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library 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 Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301 USA *
***************************************************************************/
#include "modfile.h"
#include "tstringlist.h"
#include "modfileprivate.h"
using namespace TagLib;
using namespace Mod;
class Mod::File::FilePrivate
{
public:
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
: properties(propertiesStyle)
{
}
Mod::Tag tag;
Mod::Properties properties;
};
Mod::File::File(FileName file, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) :
Mod::FileBase(file),
d(new FilePrivate(propertiesStyle))
{
read(readProperties);
}
Mod::File::File(IOStream *stream, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) :
Mod::FileBase(stream),
d(new FilePrivate(propertiesStyle))
{
read(readProperties);
}
Mod::File::~File()
{
delete d;
}
Mod::Tag *Mod::File::tag() const
{
return &d->tag;
}
Mod::Properties *Mod::File::audioProperties() const
{
return &d->properties;
}
bool Mod::File::save()
{
// note: if title starts with "Extended Module: "
// the file would look like an .xm file
seek(0);
writeString(d->tag.title(), 20, ' ');
// TODO: write comment as sample names
return true;
}
void Mod::File::read(bool)
{
if(!isOpen())
return;
seek(1080);
ByteVector modId = readBlock(4);
READ_ASSERT(modId.size() == 4);
int channels = 4;
int instruments = 31;
if(modId == "M.K." || modId == "M!K!" || modId == "M&K!" || modId == "N.T.")
{
d->tag.setTrackerName("ProTracker");
channels = 4;
}
else if(modId.startsWith("FLT") || modId.startsWith("TDZ"))
{
d->tag.setTrackerName("StarTrekker");
char digit = modId[3];
READ_ASSERT(digit >= '0' && digit <= '9');
channels = digit - '0';
}
else if(modId.endsWith("CHN"))
{
d->tag.setTrackerName("StarTrekker");
char digit = modId[0];
READ_ASSERT(digit >= '0' && digit <= '9');
channels = digit - '0';
}
else if(modId == "CD81" || modId == "OKTA")
{
d->tag.setTrackerName("Atari Oktalyzer");
channels = 8;
}
else if(modId.endsWith("CH") || modId.endsWith("CN"))
{
d->tag.setTrackerName("TakeTracker");
char digit = modId[0];
READ_ASSERT(digit >= '0' && digit <= '9');
channels = (digit - '0') * 10;
digit = modId[1];
READ_ASSERT(digit >= '0' && digit <= '9');
channels += digit - '0';
}
else
{
d->tag.setTrackerName("NoiseTracker"); // probably
channels = 4;
instruments = 15;
}
d->properties.setChannels(channels);
d->properties.setInstrumentCount(instruments);
seek(0);
READ_STRING(d->tag.setTitle, 20);
StringList comment;
for(int i = 0; i < instruments; ++ i)
{
READ_STRING_AS(instrumentName, 22);
READ_U16B_AS(instrumentLength);
READ_BYTE_AS(fineTuneByte);
int fineTune = fineTuneByte & 0xF;
// > 7 means nagative value
if(fineTune > 7) fineTune -= 16;
READ_BYTE_AS(volume);
if(volume > 64) volume = 64;
READ_U16B_AS(repeatStart);
// (int)repatStart << 1;
READ_U16B_AS(repatLength);
// (int)repatLength << 1;
comment.append(instrumentName);
}
READ_BYTE(d->properties.setPatternCount);
d->tag.setComment(comment.toString("\n"));
}

89
taglib/mod/modfile.h Normal file
View File

@ -0,0 +1,89 @@
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library 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 Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301 USA *
***************************************************************************/
#ifndef TAGLIB_MODFILE_H
#define TAGLIB_MODFILE_H
#include "tfile.h"
#include "audioproperties.h"
#include "taglib_export.h"
#include "modfilebase.h"
#include "modtag.h"
#include "modproperties.h"
namespace TagLib {
namespace Mod {
class TAGLIB_EXPORT File : public TagLib::Mod::FileBase {
public:
/*!
* Contructs a Protracker file from \a file. If \a readProperties
* is true the file's audio properties will also be read using
* \a propertiesStyle. If false, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*!
* Contructs a Protracker file from \a stream. If \a readProperties
* is true the file's audio properties will also be read using
* \a propertiesStyle. If false, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
Mod::Tag *tag() const;
/*!
* Returns the Mod::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Mod::Properties *audioProperties() const;
/*!
* Save the file.
* This is the same as calling save(AllTags);
*
* \note Saving Protracker tags is not supported.
*/
bool save();
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties);
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

View File

@ -32,10 +32,10 @@ Mod::FileBase::FileBase(IOStream *stream) : TagLib::File(stream)
{
}
void Mod::FileBase::writeString(const String &s, ulong size)
void Mod::FileBase::writeString(const String &s, ulong size, char padding)
{
ByteVector data(s.data(String::Latin1));
data.resize(size, 0);
data.resize(size, padding);
writeBlock(data);
}
@ -76,3 +76,18 @@ bool Mod::FileBase::readU32L(ulong &number) {
number = data.toUInt(false);
return true;
}
bool Mod::FileBase::readU16B(ushort &number)
{
ByteVector data(readBlock(2));
if(data.size() < 2) return false;
number = data.toUShort(true);
return true;
}
bool Mod::FileBase::readU32B(ulong &number) {
ByteVector data(readBlock(4));
if(data.size() < 4) return false;
number = data.toUInt(true);
return true;
}

View File

@ -19,8 +19,8 @@
* MA 02110-1301 USA *
***************************************************************************/
#ifndef TAGLIB_MODFILE_H
#define TAGLIB_MODFILE_H
#ifndef TAGLIB_MODFILEBASE_H
#define TAGLIB_MODFILEBASE_H
#include "taglib.h"
#include "tfile.h"
@ -34,11 +34,13 @@ namespace TagLib {
FileBase(FileName file);
FileBase(IOStream *stream);
void writeString(const String &s, ulong size);
void writeString(const String &s, ulong size, char padding = 0);
bool readString(String &s, ulong size);
bool readByte(uchar &byte);
bool readU16L(ushort &number);
bool readU32L(ulong &number);
bool readU16B(ushort &number);
bool readU32B(ulong &number);
};
}
}

View File

@ -40,6 +40,8 @@
#define READ_BYTE(setter) READ(setter,uchar,readByte)
#define READ_U16L(setter) READ(setter,ushort,readU16L)
#define READ_U32L(setter) READ(setter,ulong,readU32L)
#define READ_U16B(setter) READ(setter,ushort,readU16B)
#define READ_U32B(setter) READ(setter,ulong,readU32B)
#define READ_STRING(setter,size) \
{ \
@ -55,6 +57,8 @@
#define READ_BYTE_AS(name) READ_AS(uchar,name,readByte)
#define READ_U16L_AS(name) READ_AS(ushort,name,readU16L)
#define READ_U32L_AS(name) READ_AS(ulong,name,readU32L)
#define READ_U16B_AS(name) READ_AS(ushort,name,readU16B)
#define READ_U32B_AS(name) READ_AS(ulong,name,readU32B)
#define READ_STRING_AS(name,size) \
String name; \

View File

@ -0,0 +1,96 @@
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library 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 Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301 USA *
***************************************************************************/
#include "modproperties.h"
using namespace TagLib;
using namespace Mod;
class Mod::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() :
channels(0),
instrumentCount(0),
patternCount(0)
{
}
int channels;
uint instrumentCount;
uint patternCount;
};
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
AudioProperties(propertiesStyle),
d(new PropertiesPrivate)
{
}
Mod::Properties::~Properties()
{
delete d;
}
int Mod::Properties::length() const
{
return 0;
}
int Mod::Properties::bitrate() const
{
return 0;
}
int Mod::Properties::sampleRate() const
{
return 0;
}
int Mod::Properties::channels() const
{
return d->channels;
}
uint Mod::Properties::instrumentCount() const
{
return d->instrumentCount;
}
uint Mod::Properties::patternCount() const
{
return d->patternCount;
}
void Mod::Properties::setChannels(int channels)
{
d->channels = channels;
}
void Mod::Properties::setInstrumentCount(uint instrumentCount)
{
d->instrumentCount = instrumentCount;
}
void Mod::Properties::setPatternCount(uint patternCount)
{
d->patternCount = patternCount;
}

View File

@ -0,0 +1,60 @@
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library 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 Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301 USA *
***************************************************************************/
#ifndef TAGLIB_MODPROPERTIES_H
#define TAGLIB_MODPROPERTIES_H
#include "taglib.h"
#include "audioproperties.h"
namespace TagLib {
namespace Mod {
class TAGLIB_EXPORT Properties : public AudioProperties {
friend class File;
public:
Properties(AudioProperties::ReadStyle propertiesStyle);
virtual ~Properties();
int length() const;
int bitrate() const;
int sampleRate() const;
int channels() const;
uint instrumentCount() const;
uint patternCount() const;
protected:
void setChannels(int channels);
void setInstrumentCount(uint sampleCount);
void setPatternCount(uint patternCount);
private:
Properties(const Properties&);
Properties &operator=(const Properties&);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
#endif

View File

@ -31,6 +31,7 @@ public:
String title;
String comment;
String trackerName;
};
Mod::Tag::Tag() : TagLib::Tag()
@ -78,6 +79,11 @@ uint Mod::Tag::track() const
return 0;
}
String Mod::Tag::trackerName() const
{
return d->trackerName;
}
void Mod::Tag::setTitle(const String &title)
{
d->title = title;
@ -107,3 +113,8 @@ void Mod::Tag::setYear(uint)
void Mod::Tag::setTrack(uint)
{
}
void Mod::Tag::setTrackerName(const String &trackerName)
{
d->trackerName = trackerName;
}

View File

@ -38,6 +38,7 @@ namespace TagLib {
String genre() const;
uint year() const;
uint track() const;
String trackerName() const;
void setTitle (const String &title);
void setArtist (const String &artist);
@ -46,6 +47,7 @@ namespace TagLib {
void setGenre (const String &genre);
void setYear (uint year);
void setTrack(uint track);
void setTrackerName(const String &trackerName);
private:
Tag(const Tag &);