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 }