File indexing completed on 2024-05-26 04:58:00
0001 /** 0002 * \file genres.cpp 0003 * Alphabetical list of genres. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 9 Jan 2003 0008 * 0009 * Copyright (C) 2003-2024 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "genres.h" 0028 #include "frame.h" 0029 #include <QString> 0030 #include <QVector> 0031 #include <QMap> 0032 0033 /** 0034 * Alphabetic list of genres, starts with unknown (empty) entry. 0035 * 0036 * 125: Last ID3v1, 142: WinAmp 1.91, 145: WinAmp 1.92, 148: WinAmp 5.6, 255: unknown 0037 */ 0038 const char* Genres::s_genre[Genres::count + 3] = { 0039 "", // 255, 0040 "A Cappella", // 123, 0041 "Abstract", // 148, 0042 "Acid", // 34, 0043 "Acid Jazz", // 74, 0044 "Acid Punk", // 73, 0045 "Acoustic", // 99, 0046 "Alternative", // 20, 0047 "Alternative Rock", // 40, 0048 "Ambient", // 26, 0049 "Anime", // 145, 0050 "Art Rock", // 149, 0051 "Audio Theatre", // 184, 0052 "Audiobook", // 183, 0053 "Avant-Garde", // 90, 0054 "Ballad", // 116, 0055 "Baroque", // 150, 0056 "Bass", // 41, 0057 "Beat Music", // 135, 0058 "Bebop", // 85, 0059 "Bhangra", // 151, 0060 "Big Band", // 96, 0061 "Big Beat", // 152, 0062 "Black Metal", // 138, 0063 "Bluegrass", // 89, 0064 "Blues", // 0, 0065 "Booty Bass", // 107, 0066 "Breakbeat", // 153, 0067 "Britpop", // 132, 0068 "Cabaret", // 65, 0069 "Celtic", // 88, 0070 "Chamber Music", // 104, 0071 "Chanson", // 102, 0072 "Chillout", // 154, 0073 "Chorus", // 97, 0074 "Christian Gangsta Rap", // 136, 0075 "Christian Rap", // 61, 0076 "Christian Rock", // 141, 0077 "Classic Rock", // 1, 0078 "Classical", // 32, 0079 "Club", // 112, 0080 "Club-House", // 128, 0081 "Comedy", // 57, 0082 "Contemporary Christian", // 140, 0083 "Country", // 2, 0084 "Crossover", // 139, 0085 "Cult", // 58, 0086 "Dance", // 3, 0087 "Dancehall", // 125, 0088 "Dark Wave", // 50, 0089 "Death Metal", // 22, 0090 "Disco", // 4, 0091 "Downtempo", // 155, 0092 "Dream", // 55, 0093 "Drum & Bass", // 127, 0094 "Drum Solo", // 122, 0095 "Dub", // 156, 0096 "Dubstep", // 189, 0097 "Duet", // 120, 0098 "EBM", // 157, 0099 "Easy Listening", // 98, 0100 "Eclectic", // 158, 0101 "Electro", // 159, 0102 "Electroclash", // 160, 0103 "Electronic", // 52, 0104 "Emo", // 161, 0105 "Ethnic", // 48, 0106 "Euro House", // 124, 0107 "Eurodance", // 54, 0108 "Eurotechno", // 25, 0109 "Experimental", // 162, 0110 "Fast Fusion", // 84, 0111 "Folk", // 80, 0112 "Folk Rock", // 81, 0113 "Folklore", // 115, 0114 "Freestyle", // 119, 0115 "Funk", // 5, 0116 "Fusion", // 30, 0117 "G-Funk", // 188, 0118 "Game", // 36, 0119 "Gangsta", // 59, 0120 "Garage", // 163, 0121 "Garage Rock", // 190, 0122 "Global", // 164, 0123 "Goa", // 126, 0124 "Gospel", // 38, 0125 "Gothic", // 49, 0126 "Gothic Rock", // 91, 0127 "Grunge", // 6, 0128 "Hard Rock", // 79, 0129 "Hardcore", // 129, 0130 "Heavy Metal", // 137, 0131 "Hip Hop", // 7, 0132 "House", // 35, 0133 "Humour", // 100, 0134 "IDM", // 165, 0135 "Illbient", // 166, 0136 "Indie", // 131, 0137 "Indie Rock", // 187, 0138 "Industrial", // 19, 0139 "Industro-Goth", // 167, 0140 "Instrumental", // 33, 0141 "Instrumental Pop", // 46, 0142 "Instrumental Rock", // 47, 0143 "Jam Band", // 168, 0144 "Jazz", // 8, 0145 "Jazz-Funk", // 29, 0146 "Jpop", // 146, 0147 "Jungle", // 63, 0148 "Krautrock", // 169, 0149 "Latin", // 86, 0150 "Leftfield", // 170, 0151 "Lo-Fi", // 71, 0152 "Lounge", // 171, 0153 "Math Rock", // 172, 0154 "Meditative", // 45, 0155 "Merengue", // 142, 0156 "Metal", // 9, 0157 "Musical", // 77, 0158 "National Folk", // 82, 0159 "Native American", // 64, 0160 "Neoclassical", // 182, 0161 "Neue Deutsche Welle", // 185, 0162 "New Age", // 10, 0163 "New Romantic", // 173, 0164 "New Wave", // 66, 0165 "Noise", // 39, 0166 "Nu-Breakz", // 174, 0167 "Oldies", // 11, 0168 "Opera", // 103, 0169 "Other", // 12, 0170 "Podcast", // 186, 0171 "Polka", // 75, 0172 "Polsk Punk", // 134, 0173 "Pop", // 13, 0174 "Pop-Folk", // 53, 0175 "Pop-Funk", // 62, 0176 "Porn Groove", // 109, 0177 "Post-Punk", // 175, 0178 "Post-Rock", // 176, 0179 "Power Ballad", // 117, 0180 "Pranks", // 23, 0181 "Primus", // 108, 0182 "Progressive Rock", // 92, 0183 "Psybient", // 191, 0184 "Psychedelic", // 67, 0185 "Psychedelic Rock", // 93, 0186 "Psytrance", // 177, 0187 "Punk", // 43, 0188 "Punk Rock", // 121, 0189 "R&B", // 14, 0190 "Rap", // 15, 0191 "Rave", // 68, 0192 "Reggae", // 16, 0193 "Retro", // 76, 0194 "Revival", // 87, 0195 "Rhythmic Soul", // 118, 0196 "Rock", // 17, 0197 "Rock & Roll", // 78, 0198 "Salsa", // 143, 0199 "Samba", // 114, 0200 "Satire", // 110, 0201 "Shoegaze", // 178, 0202 "Showtunes", // 69, 0203 "Ska", // 21, 0204 "Slow Jam", // 111, 0205 "Slow Rock", // 95, 0206 "Sonata", // 105, 0207 "Soul", // 42, 0208 "Sound Clip", // 37, 0209 "Soundtrack", // 24, 0210 "Southern Rock", // 56, 0211 "Space", // 44, 0212 "Space Rock", // 179, 0213 "Speech", // 101, 0214 "Swing", // 83, 0215 "Symphonic Rock", // 94, 0216 "Symphony", // 106, 0217 "Synth-Pop", // 147, 0218 "Tango", // 113, 0219 "Techno", // 18, 0220 "Techno-Industrial", // 51, 0221 "Terror", // 130, 0222 "Thrash Metal", // 144, 0223 "Top 40", // 60, 0224 "Trailer", // 70, 0225 "Trance", // 31, 0226 "Tribal", // 72, 0227 "Trip-Hop", // 27, 0228 "Trop Rock", // 180, 0229 "Vocal", // 28, 0230 "World Music", // 181, 0231 "Worldbeat", // 133, 0232 "Custom", // place for temporary custom genres 0233 nullptr // end of StrList 0234 }; 0235 0236 /** 0237 * s_genreNum[n] gives the number of the n-th genre 0238 * in the alphabetically sorted list. 0239 */ 0240 const unsigned char Genres::s_genreNum[Genres::count + 1] = { 0241 255, 0242 123, 0243 148, 0244 34, 0245 74, 0246 73, 0247 99, 0248 20, 0249 40, 0250 26, 0251 145, 0252 149, 0253 184, 0254 183, 0255 90, 0256 116, 0257 150, 0258 41, 0259 135, 0260 85, 0261 151, 0262 96, 0263 152, 0264 138, 0265 89, 0266 0, 0267 107, 0268 153, 0269 132, 0270 65, 0271 88, 0272 104, 0273 102, 0274 154, 0275 97, 0276 136, 0277 61, 0278 141, 0279 1, 0280 32, 0281 112, 0282 128, 0283 57, 0284 140, 0285 2, 0286 139, 0287 58, 0288 3, 0289 125, 0290 50, 0291 22, 0292 4, 0293 155, 0294 55, 0295 127, 0296 122, 0297 156, 0298 189, 0299 120, 0300 157, 0301 98, 0302 158, 0303 159, 0304 160, 0305 52, 0306 161, 0307 48, 0308 124, 0309 54, 0310 25, 0311 162, 0312 84, 0313 80, 0314 81, 0315 115, 0316 119, 0317 5, 0318 30, 0319 188, 0320 36, 0321 59, 0322 163, 0323 190, 0324 164, 0325 126, 0326 38, 0327 49, 0328 91, 0329 6, 0330 79, 0331 129, 0332 137, 0333 7, 0334 35, 0335 100, 0336 165, 0337 166, 0338 131, 0339 187, 0340 19, 0341 167, 0342 33, 0343 46, 0344 47, 0345 168, 0346 8, 0347 29, 0348 146, 0349 63, 0350 169, 0351 86, 0352 170, 0353 71, 0354 171, 0355 172, 0356 45, 0357 142, 0358 9, 0359 77, 0360 82, 0361 64, 0362 182, 0363 185, 0364 10, 0365 173, 0366 66, 0367 39, 0368 174, 0369 11, 0370 103, 0371 12, 0372 186, 0373 75, 0374 134, 0375 13, 0376 53, 0377 62, 0378 109, 0379 175, 0380 176, 0381 117, 0382 23, 0383 108, 0384 92, 0385 191, 0386 67, 0387 93, 0388 177, 0389 43, 0390 121, 0391 14, 0392 15, 0393 68, 0394 16, 0395 76, 0396 87, 0397 118, 0398 17, 0399 78, 0400 143, 0401 114, 0402 110, 0403 178, 0404 69, 0405 21, 0406 111, 0407 95, 0408 105, 0409 42, 0410 37, 0411 24, 0412 56, 0413 44, 0414 179, 0415 101, 0416 83, 0417 94, 0418 106, 0419 147, 0420 113, 0421 18, 0422 51, 0423 130, 0424 144, 0425 60, 0426 70, 0427 31, 0428 72, 0429 27, 0430 180, 0431 28, 0432 181, 0433 133 0434 }; 0435 0436 const char** Genres::s_strList = &s_genre[0]; 0437 0438 /** 0439 * Get name assigned to genre number. 0440 * 0441 * @param num genre number 0442 * 0443 * @return name, empty string for unknown number. 0444 */ 0445 const char* Genres::getName(int num) 0446 { 0447 return s_genre[getIndex(num)]; 0448 } 0449 0450 /** 0451 * Get the index in the alphabetically sorted list from the genre number. 0452 * 0453 * @param num genre number 0454 * 0455 * @return index, 0 for unknown number. 0456 */ 0457 int Genres::getIndex(int num) 0458 { 0459 for (int i = 0; i < Genres::count + 1; i++) { 0460 if (s_genreNum[i] == num) { 0461 return i; 0462 } 0463 } 0464 return 0; // 0 for unknown entry 0465 } 0466 0467 /** 0468 * Get the genre number from a string containing a genre text. 0469 * 0470 * @param str string with genre 0471 * 0472 * @return genre number, 255 for unknown index. 0473 */ 0474 int Genres::getNumber(const QString& str) 0475 { 0476 static QMap<QString, int> strNumMap; 0477 if (strNumMap.empty()) { 0478 // first time initialization 0479 for (int i = 0; i < Genres::count + 1; i++) { 0480 strNumMap.insert(QString::fromLatin1(s_genre[i]), s_genreNum[i]); 0481 } 0482 } 0483 if (auto it = strNumMap.constFind(str); it != strNumMap.constEnd()) { 0484 return *it; 0485 } 0486 return 255; // 255 for unknown 0487 } 0488 0489 /** 0490 * Get a name string from a string with a number or a name. 0491 * ID3v2 genres can be stored as "9", "(9)", "(9)Metal" or "Metal". 0492 * 0493 * @param str genre string, it can also reference multiple ID3v1 genres 0494 * and have a refinement such as "(9)(138)Viking Metal". 0495 * Multiple genres can be separated by Frame::stringListSeparator(). 0496 * 0497 * @return genre name or multiple genre names separated by 0498 * Frame::stringListSeparator(). 0499 */ 0500 QString Genres::getNameString(const QString& str) 0501 { 0502 if (!str.isEmpty()) { 0503 QStringList genres; 0504 const auto parts = Frame::splitStringList(str); 0505 for (const auto& part : parts) { 0506 auto s = part.trimmed(); 0507 // First extract all genre codes which are in parentheses 0508 int offset = 0; 0509 int end = 0; 0510 while (s.length() > offset && s.at(offset) == QLatin1Char('(') && 0511 (end = s.indexOf(QLatin1Char(')'), offset + 1)) > offset) { 0512 const auto genreCode = s.mid(offset + 1, end - 1); 0513 s = s.mid(end + 1); 0514 bool ok; 0515 int n = genreCode.toInt(&ok); 0516 if (genreCode == QLatin1String("RX") || 0517 genreCode == QLatin1String("CR")) { 0518 genres.append(genreCode); 0519 } else if (ok && n >= 0 && n <= 0xff) { 0520 if (QString genreText = QString::fromLatin1(getName(n)); 0521 !genreText.isEmpty()) { 0522 genres.append(genreText); 0523 } 0524 } 0525 } 0526 // Process the rest as a genre code or text 0527 s = s.trimmed(); 0528 if (!s.isEmpty()) { 0529 bool ok; 0530 if (int n = s.toInt(&ok); ok && n >= 0 && n <= 0xff) { 0531 if (QString genreText = QString::fromLatin1(getName(n)); 0532 !genreText.isEmpty()) { 0533 genres.append(genreText); 0534 } 0535 } else { 0536 genres.append(s); 0537 } 0538 } 0539 } 0540 genres.removeDuplicates(); 0541 return Frame::joinStringList(genres); 0542 } 0543 return str; 0544 } 0545 0546 /** 0547 * Get a number representation of a genre name if possible. 0548 * 0549 * @param str string with genre name, can also contain multiple genres 0550 * separated by Frame::stringListSeparator() 0551 * @param parentheses true to put the numbers in parentheses, this will 0552 * result in an ID3v2.3.0 genre string, which can containing multiple 0553 * references to ID3v1 genres and optionally a refinement as a genre text 0554 * 0555 * @return genre string using numbers where possible. If @a parentheses 0556 * is true, an ID3v2.3.0 genre string such as "(9)(138)Viking Metal" is 0557 * returned, else if @a str contains multiple genres, they are returned 0558 * as numbers (where possible) separated by Frame::stringListSeparator(). 0559 */ 0560 QString Genres::getNumberString(const QString& str, bool parentheses) 0561 { 0562 QStringList genres; 0563 QString genreText; 0564 0565 const auto parts = Frame::splitStringList(str); 0566 for (const auto& part : parts) { 0567 auto s = part.trimmed(); 0568 bool ok; 0569 int n = s.toInt(&ok); 0570 if (s == QLatin1String("RX") || s == QLatin1String("CR")) { 0571 genres.append(s); 0572 } else if ((ok && n >= 0 && n <= 255) || 0573 (n = getNumber(s)) < 0xff) { 0574 genres.append(QString::number(n)); 0575 } else if (!parentheses) { 0576 genres.append(s); 0577 } else if (genreText.isEmpty()) { 0578 // For ID3v2.3.0, we can append only one genre text as a refinement 0579 genreText = s; 0580 } 0581 } 0582 if (!parentheses) { 0583 return Frame::joinStringList(genres); 0584 } 0585 if (!genres.isEmpty()) { 0586 genreText.prepend(QLatin1Char('(') + genres.join(QLatin1String(")(")) + 0587 QLatin1Char(')')); 0588 } 0589 return genreText; 0590 }