improved parsing ID3 genres
This commit is contained in:
parent
19593d4c24
commit
617679e001
|
@ -16,8 +16,9 @@ using namespace std;
|
||||||
using namespace IoUtilities;
|
using namespace IoUtilities;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \remarks Nothing of this code has been tested yet. These classes are
|
* \file aacframe.cpp
|
||||||
* not used by the rest of the library (currently).
|
* \remarks Nothing of this code has been tested yet. It is currently not used
|
||||||
|
* in the rest of the library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
|
|
|
@ -32,7 +32,16 @@ const char **Id3Genres::genreNames()
|
||||||
"Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music",
|
"Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", "Chamber Music",
|
||||||
"Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam",
|
"Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam",
|
||||||
"Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
|
"Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
|
||||||
"Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall"
|
"Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
|
||||||
|
"Goa", "Drum & Bass", "Club-House", "Hardcore Techno", "Terror", "Indie", "BritPop",
|
||||||
|
"Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta Rap", "Heavy Metal", "Black Metal",
|
||||||
|
"Crossover", "Contemporary Christian", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
|
||||||
|
"Anime", "Jpop", "Synthpop", "Abstract", "Art Rock", "Baroque", "Bhangra", "Big Beat", "Breakbeat",
|
||||||
|
"Chillout", "Downtempo", "Dub", "EBM", "Eclectic", "Electro", "Electroclash", "Emo", "Experimental",
|
||||||
|
"Garage", "Global", "IDM", "Illbient", "Industro-Goth", "Jam Band", "Krautrock", "Leftfield", "Lounge",
|
||||||
|
"Math Rock", "New Romantic", "Nu-Breakz", "Post-Punk", "Post-Rock", "Psytrance", "Shoegaze", "Space Rock",
|
||||||
|
"Trop Rock", "World Music", "Neoclassical", "Audiobook", "Audio Theatre", "Neue Deutsche Welle", "Podcast",
|
||||||
|
"Indie Rock", "G-Funk", "Dubstep", "Garage Rock", "Psybient"
|
||||||
};
|
};
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
@ -43,13 +52,9 @@ const char **Id3Genres::genreNames()
|
||||||
int Id3Genres::indexFromString(const string &genre)
|
int Id3Genres::indexFromString(const string &genre)
|
||||||
{
|
{
|
||||||
const char **ptr = genreNames();
|
const char **ptr = genreNames();
|
||||||
int index = 0;
|
for(int index = 0; index < genreCount(); ++ptr, ++index) {
|
||||||
while(index < genreCount()) {
|
|
||||||
if(genre == *ptr) {
|
if(genre == *ptr) {
|
||||||
return index;
|
return index;
|
||||||
} else {
|
|
||||||
++ptr;
|
|
||||||
++index;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -14,8 +14,8 @@ class LIB_EXPORT Id3Genres
|
||||||
public:
|
public:
|
||||||
static const char *stringFromIndex(int index);
|
static const char *stringFromIndex(int index);
|
||||||
static int indexFromString(const std::string &genre);
|
static int indexFromString(const std::string &genre);
|
||||||
static bool isIndexSupported(int index);
|
static constexpr int genreCount();
|
||||||
static int genreCount();
|
static constexpr bool isIndexSupported(int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const char **genreNames();
|
static const char **genreNames();
|
||||||
|
@ -30,20 +30,20 @@ inline const char *Id3Genres::stringFromIndex(int index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns an indication whether the specified numerical denotation is
|
* \brief Returns the number of supported genres.
|
||||||
* supported by this class.
|
|
||||||
*/
|
*/
|
||||||
inline bool Id3Genres::isIndexSupported(int index)
|
constexpr int Id3Genres::genreCount()
|
||||||
{
|
{
|
||||||
return index >= 0 && index < genreCount();
|
return 192;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the number of supported genres.
|
* \brief Returns an indication whether the specified numerical denotation is
|
||||||
|
* supported by this class.
|
||||||
*/
|
*/
|
||||||
inline int Id3Genres::genreCount()
|
constexpr bool Id3Genres::isIndexSupported(int index)
|
||||||
{
|
{
|
||||||
return 126;
|
return index >= 0 && index < genreCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,52 @@ Id3v2Frame::Id3v2Frame(const identifierType &id, const TagValue &value, const by
|
||||||
m_padding(false)
|
m_padding(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Helper function to parse the genre index.
|
||||||
|
* \returns Returns the genre index or -1 if the specified string does not denote a genre index.
|
||||||
|
*/
|
||||||
|
template<class stringtype>
|
||||||
|
int parseGenreIndex(const stringtype &denotation, bool isBigEndian = false)
|
||||||
|
{
|
||||||
|
int index = -1;
|
||||||
|
for(auto c : denotation) {
|
||||||
|
if(sizeof(typename stringtype::value_type) == 2 && isBigEndian != CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN) {
|
||||||
|
c = swapOrder(static_cast<uint16>(c));
|
||||||
|
}
|
||||||
|
if(index == -1) {
|
||||||
|
switch(c) {
|
||||||
|
case ' ':
|
||||||
|
break;
|
||||||
|
case '(':
|
||||||
|
index = 0;
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
if(c >= '0' && c <= '9') {
|
||||||
|
index = c - '0';
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch(c) {
|
||||||
|
case ')':
|
||||||
|
return index;
|
||||||
|
case '\0':
|
||||||
|
return index;
|
||||||
|
default:
|
||||||
|
if(c >= '0' && c <= '9') {
|
||||||
|
index = index * 10 + c - '0';
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses a frame from the stream read using the specified \a reader.
|
* \brief Parses a frame from the stream read using the specified \a reader.
|
||||||
*
|
*
|
||||||
|
@ -195,8 +241,7 @@ void Id3v2Frame::parse(BinaryReader &reader, const uint32 version, const uint32
|
||||||
double milliseconds;
|
double milliseconds;
|
||||||
try {
|
try {
|
||||||
if(characterSize(dataEncoding) > 1) {
|
if(characterSize(dataEncoding) > 1) {
|
||||||
wstring millisecondsStr = parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
milliseconds = ConversionUtilities::stringToNumber<double>(parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding), 10);
|
||||||
milliseconds = ConversionUtilities::stringToNumber<double, wstring>(millisecondsStr, 10);
|
|
||||||
} else {
|
} else {
|
||||||
milliseconds = ConversionUtilities::stringToNumber<double>(parseString(buffer.get() + 1, m_dataSize - 1, dataEncoding), 10);
|
milliseconds = ConversionUtilities::stringToNumber<double>(parseString(buffer.get() + 1, m_dataSize - 1, dataEncoding), 10);
|
||||||
}
|
}
|
||||||
|
@ -208,22 +253,17 @@ void Id3v2Frame::parse(BinaryReader &reader, const uint32 version, const uint32
|
||||||
} else if((version >= 3 && id() == Id3v2FrameIds::lGenre) || (version < 3 && id() == Id3v2FrameIds::sGenre)) {
|
} else if((version >= 3 && id() == Id3v2FrameIds::lGenre) || (version < 3 && id() == Id3v2FrameIds::sGenre)) {
|
||||||
// genre/content type
|
// genre/content type
|
||||||
int genreIndex;
|
int genreIndex;
|
||||||
try {
|
if(characterSize(dataEncoding) > 1) {
|
||||||
if(characterSize(dataEncoding) > 1) {
|
auto genreDenotation = parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||||
wstring indexStr = parseWideString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
genreIndex = parseGenreIndex(genreDenotation, dataEncoding == TagTextEncoding::Utf16BigEndian);
|
||||||
if(indexStr.front() == L'(' && indexStr.back() == L')') {
|
} else {
|
||||||
indexStr = indexStr.substr(1, indexStr.length() - 2);
|
auto genreDenotation = parseString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||||
}
|
genreIndex = parseGenreIndex(genreDenotation);
|
||||||
genreIndex = ConversionUtilities::stringToNumber<int, wstring>(indexStr, 10);
|
}
|
||||||
} else {
|
if(genreIndex != -1) {
|
||||||
string indexStr = parseString(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
// genre is specified as ID3 genre number
|
||||||
if(indexStr.front() == '(' && indexStr.back() == ')') {
|
value().assignStandardGenreIndex(genreIndex);
|
||||||
indexStr = indexStr.substr(1, indexStr.length() - 2);
|
} else {
|
||||||
}
|
|
||||||
genreIndex = ConversionUtilities::stringToNumber<int>(indexStr, 10);
|
|
||||||
}
|
|
||||||
value().assignStandardGenreIndex(genreIndex); // genre is specified as ID3 genre number
|
|
||||||
} catch(ConversionException &) {
|
|
||||||
// genre is specified as string
|
// genre is specified as string
|
||||||
// string might be null terminated
|
// string might be null terminated
|
||||||
auto substr = parseSubstring(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
auto substr = parseSubstring(buffer.get() + 1, m_dataSize - 1, dataEncoding);
|
||||||
|
@ -600,12 +640,12 @@ string Id3v2Frame::parseString(const char *buffer, size_t dataSize, TagTextEncod
|
||||||
/*!
|
/*!
|
||||||
* \brief Parses a substring in the specified \a buffer.
|
* \brief Parses a substring in the specified \a buffer.
|
||||||
*
|
*
|
||||||
* Same as Id3v2Frame::parseSubstring() but returns the substring as wstring object.
|
* Same as Id3v2Frame::parseSubstring() but returns the substring as u16string object.
|
||||||
*/
|
*/
|
||||||
wstring Id3v2Frame::parseWideString(const char *buffer, size_t dataSize, TagTextEncoding &encoding, bool addWarnings)
|
u16string Id3v2Frame::parseWideString(const char *buffer, size_t dataSize, TagTextEncoding &encoding, bool addWarnings)
|
||||||
{
|
{
|
||||||
auto substr = parseSubstring(buffer, dataSize, encoding, addWarnings);
|
auto substr = parseSubstring(buffer, dataSize, encoding, addWarnings);
|
||||||
return wstring(reinterpret_cast<wstring::const_pointer>(get<0>(substr)), get<1>(substr) / 2);
|
return u16string(reinterpret_cast<u16string::const_pointer>(get<0>(substr)), get<1>(substr) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -137,7 +137,7 @@ public:
|
||||||
TagTextEncoding parseTextEncodingByte(byte textEncodingByte);
|
TagTextEncoding parseTextEncodingByte(byte textEncodingByte);
|
||||||
std::tuple<const char *, size_t, const char *> parseSubstring(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings = false);
|
std::tuple<const char *, size_t, const char *> parseSubstring(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings = false);
|
||||||
std::string parseString(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings = false);
|
std::string parseString(const char *buffer, std::size_t maxSize, TagTextEncoding &encoding, bool addWarnings = false);
|
||||||
std::wstring parseWideString(const char *buffer, std::size_t dataSize, TagTextEncoding &encoding, bool addWarnings = false);
|
std::u16string parseWideString(const char *buffer, std::size_t dataSize, TagTextEncoding &encoding, bool addWarnings = false);
|
||||||
void parseLegacyPicture(const char *buffer, size_t maxSize, TagValue &tagValue, byte &typeInfo);
|
void parseLegacyPicture(const char *buffer, size_t maxSize, TagValue &tagValue, byte &typeInfo);
|
||||||
void parsePicture(const char *buffer, size_t maxSize, TagValue &tagValue, byte &typeInfo);
|
void parsePicture(const char *buffer, size_t maxSize, TagValue &tagValue, byte &typeInfo);
|
||||||
void parseComment(const char *buffer, size_t maxSize, TagValue &tagValue);
|
void parseComment(const char *buffer, size_t maxSize, TagValue &tagValue);
|
||||||
|
|
Loading…
Reference in New Issue