PHP - (MP3) ID3 Tag Reader


SUBMITTED BY: Guest

DATE: June 11, 2013, 11:24 p.m.

FORMAT: Text only

SIZE: 21.0 kB

HITS: 1090

  1. <?php
  2. class id3 {
  3. /*
  4. *
  5. * ####
  6. *
  7. * (sven) neawolf
  8. * NEA.php.id3
  9. *
  10. * This PHP class runs in real-time environment on my online radio "hardcast.de" / "hardcast.eu" !
  11. *
  12. * ####
  13. *
  14. * define('NEA_MP3_ID3', true);
  15. * require_once("/path/to/nea.id3.php");
  16. * $id3 = new id3("/path/to/file.mp3");
  17. *
  18. * echo "mpeg-version: $id3->mpeg_ver <br>";
  19. * echo "mpeg-layer: $id3->layer <br>";
  20. * echo "bitrate: $id3->bitrate <br>";
  21. * echo "frequency: $id3->frequency <br>";
  22. * echo "lengths (seconds): $id3->lengths <br>";
  23. * echo "length (hh:ss): $id3->length <br>";
  24. * echo "name: $id3->name <br>";
  25. * echo "artists: $id3->artists <br>";
  26. * echo "album: $id3->album <br>";
  27. * echo "year: $id3->year <br>";
  28. * echo "comment: $id3->comment <br>";
  29. * echo "track: $id3->track <br>";
  30. * echo "genre: $id3->genre <br>";
  31. * echo "genre number: $id3->genreno <br>";
  32. * echo "private bit set: $id3->private <br>";
  33. * echo "mode: $id3->mode <br>";
  34. * echo "copyright: $id3->copyright <br>";
  35. * echo "original: $id3->original <br>";
  36. *
  37. * ####
  38. *
  39. *
  40. */
  41. var $_version = 1.03; // Version of the id3 class
  42. var $file = false; // mp3/mpeg file name
  43. var $id3v1 = false; // ID3 v1 tag found? (also true if v1.1 found)
  44. var $id3v11 = false; // ID3 v1.1 tag found?
  45. var $id3v2 = false; // ID3 v2 tag found? (not used yet)
  46. // ID3v1.1 Fields:
  47. var $name = ''; // track name
  48. var $artists = ''; // artists
  49. var $album = ''; // album
  50. var $year = ''; // year
  51. var $comment = ''; // comment
  52. var $track = 0; // track number
  53. var $genre = ''; // genre name
  54. var $genreno = 255; // genre number
  55. // MP3 Frame Stuff
  56. var $mpeg_ver = false; // version of mpeg
  57. var $layer = false; // version of layer
  58. var $bitrate = false; // bitrate
  59. var $crc = false; // Frames are crc protected?
  60. var $frequency = 0; // Frequency
  61. var $padding = false; // Frames padded
  62. var $private = false; // Private bit set?
  63. var $mode = ''; // Mode (Stereo etc)
  64. var $copyright = false; // Copyrighted?
  65. var $original = false; // On Original Media? (never used)
  66. var $emphasis = ''; // Emphasis (also never used)
  67. var $filesize = -1; // Bytes in file
  68. var $frameoffset = -1; // Byte at which the first mpeg header was found.
  69. var $length = false; // length of mp3 format hh:ss
  70. var $lengths = false; // length of mp3 in seconds
  71. var $error = false; // if any errors they will be here
  72. /*
  73. * id3 constructor - creates a new id3 object and maybe loads a tag
  74. * from a file.
  75. *
  76. * $file - the path to the mp3/mpeg file. When in doubt use a full path.
  77. * You should advoid studing alot of files as it will siginficantly slow this down.
  78. */
  79. function id3($file) {
  80. $this->file = $file;
  81. $this->_read_v1();
  82. $this->study();
  83. } // id3($file)
  84. /*
  85. * write - update the id3v1 tags on the file.
  86. *
  87. * $v1 - if true update/create an id3v1 tag on the file. (defaults to true)
  88. *
  89. * Note: If/when ID3v2 is implemented this method will probably get another
  90. * parameters.
  91. */
  92. function write($v1 = true) {
  93. if ($this->debug) print($this->debugbeg . "write()<HR>\n");
  94. if ($v1) {
  95. $this->_write_v1();
  96. }
  97. if ($this->debug) print($this->debugend);
  98. } // write()
  99. /*
  100. * study() - does extra work to get the MPEG frame info.
  101. */
  102. function study() {
  103. $this->studied = true;
  104. $this->_readframe();
  105. } // study()
  106. /*
  107. * copy($from) - set's the ID3 fields to the same as the fields in $from
  108. */
  109. function copy($from) {
  110. if ($this->debug) print($this->debugbeg . "copy(\$from)<HR>\n");
  111. $this->name = $from->name;
  112. $this->artists = $from->artists;
  113. $this->album = $from->album;
  114. $this->year = $from->year;
  115. $this->comment = $from->comment;
  116. $this->track = $from->track;
  117. $this->genre = $from->genre;
  118. $this->genreno = $from->genreno;
  119. if ($this->debug) print($this->debugend);
  120. } // copy($from)
  121. /*
  122. * remove - removes the id3 tag(s) from a file.
  123. *
  124. * $id3v1 - true to remove the tag
  125. * $id3v2 - true to remove the tag (Not yet implemented)
  126. */
  127. function remove($id3v1 = true, $id3v2 = true) {
  128. if ($this->debug) print($this->debugbeg . "remove()<HR>\n");
  129. if ($id3v1) {
  130. $this->_remove_v1();
  131. }
  132. if ($id3v2) {
  133. // TODO: write ID3v2 code
  134. }
  135. if ($this->debug) print($this->debugend);
  136. } // remove
  137. /*
  138. * _read_v1 - read a ID3 v1 or v1.1 tag from a file
  139. *
  140. * $file should be the path to the mp3 to look for a tag.
  141. * When in doubt use the full path.
  142. *
  143. * if there is an error it will return false and a message will be
  144. * put in $this->error
  145. */
  146. function _read_v1() {
  147. if ($this->debug) print($this->debugbeg . "_read_v1()<HR>\n");
  148. if (! ($f = fopen($this->file, 'rb')) ) {
  149. $this->error = 'Unable to open ' . $file;
  150. return false;
  151. }
  152. if (fseek($f, -128, SEEK_END) == -1) {
  153. $this->error = 'Unable to see to end - 128 of ' . $file;
  154. return false;
  155. }
  156. $r = fread($f, 128);
  157. fclose($f);
  158. if ($this->debug) {
  159. $unp = unpack('H*raw', $r);
  160. print_r($unp);
  161. }
  162. $id3tag = $this->_decode_v1($r);
  163. if($id3tag) {
  164. $this->id3v1 = true;
  165. $tmp = explode(Chr(0), $id3tag['NAME']);
  166. $this->name = $tmp[0];
  167. $tmp = explode(Chr(0), $id3tag['ARTISTS']);
  168. $this->artists = $tmp[0];
  169. $tmp = explode(Chr(0), $id3tag['ALBUM']);
  170. $this->album = $tmp[0];
  171. $tmp = explode(Chr(0), $id3tag['YEAR']);
  172. $this->year = $tmp[0];
  173. $tmp = explode(Chr(0), $id3tag['COMMENT']);
  174. $this->comment = $tmp[0];
  175. if (isset($id3tag['TRACK'])) {
  176. $this->id3v11 = true;
  177. $this->track = $id3tag['TRACK'];
  178. }
  179. $this->genreno = $id3tag['GENRENO'];
  180. $this->genre = $id3tag['GENRE'];
  181. }
  182. if ($this->debug) print($this->debugend);
  183. } // _read_v1()
  184. /*
  185. * _decode_v1 - decodes that ID3v1 or ID3v1.1 tag
  186. *
  187. * false will be returned if there was an error decoding the tag
  188. * else an array will be returned
  189. */
  190. function _decode_v1($rawtag) {
  191. if ($this->debug) print($this->debugbeg . "_decode_v1(\$rawtag)<HR>\n");
  192. if ($rawtag[125] == Chr(0) and $rawtag[126] != Chr(0)) {
  193. // ID3 v1.1
  194. $format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a28COMMENT/x1/C1TRACK/C1GENRENO';
  195. } else {
  196. // ID3 v1
  197. $format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a30COMMENT/C1GENRENO';
  198. }
  199. $id3tag = unpack($format, $rawtag);
  200. if ($this->debug) print_r($id3tag);
  201. if ($id3tag['TAG'] == 'TAG') {
  202. $id3tag['GENRE'] = $this->getgenre($id3tag['GENRENO']);
  203. } else {
  204. $this->error = 'TAG not found';
  205. $id3tag = false;
  206. }
  207. if ($this->debug) print($this->debugend);
  208. return $id3tag;
  209. } // _decode_v1()
  210. /*
  211. * _write_v1 - writes a ID3 v1 or v1.1 tag to a file
  212. *
  213. * if there is an error it will return false and a message will be
  214. * put in $this->error
  215. */
  216. function _write_v1() {
  217. if ($this->debug) print($this->debugbeg . "_write_v1()<HR>\n");
  218. $file = $this->file;
  219. if (! ($f = fopen($file, 'r+b')) ) {
  220. $this->error = 'Unable to open ' . $file;
  221. return false;
  222. }
  223. if (fseek($f, -128, SEEK_END) == -1) {
  224. $this->error = 'Unable to see to end - 128 of ' . $file;
  225. return false;
  226. }
  227. $this->genreno = $this->getgenreno($this->genre, $this->genreno);
  228. $newtag = $this->_encode_v1();
  229. $r = fread($f, 128);
  230. if ($this->_decode_v1($r)) {
  231. if (fseek($f, -128, SEEK_END) == -1) {
  232. $this->error = 'Unable to see to end - 128 of ' . $file;
  233. return false;
  234. }
  235. fwrite($f, $newtag);
  236. } else {
  237. if (fseek($f, 0, SEEK_END) == -1) {
  238. $this->error = 'Unable to see to end of ' . $file;
  239. return false;
  240. }
  241. fwrite($f, $newtag);
  242. }
  243. fclose($f);
  244. } // _write_v1()
  245. /*
  246. * _encode_v1 - encode the ID3 tag
  247. *
  248. * the newly built tag will be returned
  249. */
  250. function _encode_v1() {
  251. if ($this->debug) print($this->debugbeg . "_encode_v1()<HR>\n");
  252. if ($this->track) {
  253. // ID3 v1.1
  254. $id3pack = 'a3a30a30a30a4a28x1C1C1';
  255. $newtag = pack($id3pack,
  256. 'TAG',
  257. $this->name,
  258. $this->artists,
  259. $this->album,
  260. $this->year,
  261. $this->comment,
  262. $this->track,
  263. $this->genreno
  264. );
  265. } else {
  266. // ID3 v1
  267. $id3pack = 'a3a30a30a30a4a30C1';
  268. $newtag = pack($id3pack,
  269. 'TAG',
  270. $this->name,
  271. $this->artists,
  272. $this->album,
  273. $this->year,
  274. $this->comment,
  275. $this->genreno
  276. );
  277. }
  278. if ($this->debug) {
  279. print('id3pack: ' . $id3pack . "\n");
  280. $unp = unpack('H*new', $newtag);
  281. print_r($unp);
  282. }
  283. if ($this->debug) print($this->debugend);
  284. return $newtag;
  285. } // _encode_v1()
  286. /*
  287. * _remove_v1 - if exists it removes an ID3v1 or v1.1 tag
  288. *
  289. * returns true if the tag was removed or none was found
  290. * else false if there was an error
  291. */
  292. function _remove_v1() {
  293. if ($this->debug) print($this->debugbeg . "_remove_v1()<HR>\n");
  294. $file = $this->file;
  295. if (! ($f = fopen($file, 'r+b')) ) {
  296. $this->error = 'Unable to open ' . $file;
  297. return false;
  298. }
  299. if (fseek($f, -128, SEEK_END) == -1) {
  300. $this->error = 'Unable to see to end - 128 of ' . $file;
  301. return false;
  302. }
  303. $r = fread($f, 128);
  304. $success = false;
  305. if ($this->_decode_v1($r)) {
  306. $size = filesize($this->file) - 128;
  307. if ($this->debug) print('size: old: ' . filesize($this->file));
  308. $success = ftruncate($f, $size);
  309. clearstatcache();
  310. if ($this->debug) print(' new: ' . filesize($this->file));
  311. }
  312. fclose($f);
  313. if ($this->debug) print($this->debugend);
  314. return $success;
  315. } // _remove_v1()
  316. function _readframe() {
  317. if ($this->debug) print($this->debugbeg . "_readframe()<HR>\n");
  318. $file = $this->file;
  319. if (! ($f = fopen($file, 'rb')) ) {
  320. $this->error = 'Unable to open ' . $file;
  321. if ($this->debug) print($this->debugend);
  322. return false;
  323. }
  324. $this->filesize = filesize($file);
  325. do {
  326. while (fread($f,1) != Chr(255)) { // Find the first frame
  327. //if ($this->debug) echo "Find...\n";
  328. if (feof($f)) {
  329. $this->error = 'No mpeg frame found';
  330. if ($this->debug) print($this->debugend);
  331. return false;
  332. }
  333. }
  334. fseek($f, ftell($f) - 1); // back up one byte
  335. $frameoffset = ftell($f);
  336. $r = fread($f, 4);
  337. // Binary to Hex to a binary sting. ugly but best I can think of.
  338. $bits = unpack('H*bits', $r);
  339. $bits = base_convert($bits['bits'],16,2);
  340. } while (!$bits[8] and !$bits[9] and !$bits[10]); // 1st 8 bits true from the while
  341. if ($this->debug) print('Bits: ' . $bits . "\n");
  342. $this->frameoffset = $frameoffset;
  343. fclose($f);
  344. if ($bits[11] == 0) {
  345. $this->mpeg_ver = "2.5";
  346. $bitrates = array(
  347. '1' => array(0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0),
  348. '2' => array(0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0),
  349. '3' => array(0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0),
  350. );
  351. } else if ($bits[12] == 0) {
  352. $this->mpeg_ver = "2";
  353. $bitrates = array(
  354. '1' => array(0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0),
  355. '2' => array(0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0),
  356. '3' => array(0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0),
  357. );
  358. } else {
  359. $this->mpeg_ver = "1";
  360. $bitrates = array(
  361. '1' => array(0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0),
  362. '2' => array(0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0),
  363. '3' => array(0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0),
  364. );
  365. }
  366. if ($this->debug) print('MPEG' . $this->mpeg_ver . "\n");
  367. $layer = array(
  368. array(0,3),
  369. array(2,1),
  370. );
  371. $this->layer = $layer[$bits[13]][$bits[14]];
  372. if ($this->debug) print('layer: ' . $this->layer . "\n");
  373. if ($bits[15] == 0) {
  374. // It's backwards, if the bit is not set then it is protected.
  375. if ($this->debug) print("protected (crc)\n");
  376. $this->crc = true;
  377. }
  378. $bitrate = 0;
  379. if ($bits[16] == 1) $bitrate += 8;
  380. if ($bits[17] == 1) $bitrate += 4;
  381. if ($bits[18] == 1) $bitrate += 2;
  382. if ($bits[19] == 1) $bitrate += 1;
  383. $this->bitrate = $bitrates[$this->layer][$bitrate];
  384. $frequency = array(
  385. '1' => array(
  386. '0' => array(44100, 48000),
  387. '1' => array(32000, 0),
  388. ),
  389. '2' => array(
  390. '0' => array(22050, 24000),
  391. '1' => array(16000, 0),
  392. ),
  393. '2.5' => array(
  394. '0' => array(11025, 12000),
  395. '1' => array(8000, 0),
  396. ),
  397. );
  398. $this->frequency = $frequency[$this->mpeg_ver][$bits[20]][$bits[21]];
  399. $this->padding = $bits[22];
  400. $this->private = $bits[23];
  401. $mode = array(
  402. array('Stereo', 'Joint Stereo'),
  403. array('Dual Channel', 'Mono'),
  404. );
  405. $this->mode = $mode[$bits[24]][$bits[25]];
  406. // XXX: I dunno what the mode extension is for bits 26,27
  407. $this->copyright = $bits[28];
  408. $this->original = $bits[29];
  409. $emphasis = array(
  410. array('none', '50/15ms'),
  411. array('', 'CCITT j.17'),
  412. );
  413. $this->emphasis = $emphasis[$bits[30]][$bits[31]];
  414. if ($this->bitrate == 0) {
  415. $s = -1;
  416. } else {
  417. $s = ((8*filesize($this->file))/1000) / $this->bitrate;
  418. }
  419. $this->length = sprintf('%02d:%02d',floor($s/60),floor($s-(floor($s/60)*60)));
  420. $this->lengths = (int)$s;
  421. if ($this->debug) print($this->debugend);
  422. } // _readframe()
  423. /*
  424. * getgenre - return the name of a genre number
  425. *
  426. * if no genre number is specified the genre number from
  427. * $this->genreno will be used.
  428. *
  429. * the genre is returned or false if an error or not found
  430. * no error message is ever returned
  431. */
  432. function getgenre($genreno) {
  433. if ($this->debug) print($this->debugbeg . "getgenre($genreno)<HR>\n");
  434. $genres = $this->genres();
  435. if (isset($genres[$genreno])) {
  436. $genre = $genres[$genreno];
  437. if ($this->debug) print($genre . "\n");
  438. } else {
  439. $genre = '';
  440. }
  441. if ($this->debug) print($this->debugend);
  442. return $genre;
  443. } // getgenre($genreno)
  444. /*
  445. * getgenreno - return the number of the genre name
  446. *
  447. * the genre number is returned or 0xff (255) if a match is not found
  448. * you can specify the default genreno to use if one is not found
  449. * no error message is ever returned
  450. */
  451. function getgenreno($genre, $default = 0xff) {
  452. if ($this->debug) print($this->debugbeg . "getgenreno('$genre',$default)<HR>\n");
  453. $genres = $this->genres();
  454. $genreno = false;
  455. if ($genre) {
  456. foreach ($genres as $no => $name) {
  457. if (strtolower($genre) == strtolower($name)) {
  458. if ($this->debug) print("$no:'$name' == '$genre'");
  459. $genreno = $no;
  460. }
  461. }
  462. }
  463. if ($genreno === false) $genreno = $default;
  464. if ($this->debug) print($this->debugend);
  465. return $genreno;
  466. } // getgenreno($genre, $default = 0xff)
  467. /*
  468. * genres - reuturns an array of the ID3v1 genres
  469. */
  470. function genres() {
  471. return array(
  472. 0 => 'Blues',
  473. 1 => 'Classic Rock',
  474. 2 => 'Country',
  475. 3 => 'Dance',
  476. 4 => 'Disco',
  477. 5 => 'Funk',
  478. 6 => 'Grunge',
  479. 7 => 'Hip-Hop',
  480. 8 => 'Jazz',
  481. 9 => 'Metal',
  482. 10 => 'New Age',
  483. 11 => 'Oldies',
  484. 12 => 'Other',
  485. 13 => 'Pop',
  486. 14 => 'R&B',
  487. 15 => 'Rap',
  488. 16 => 'Reggae',
  489. 17 => 'Rock',
  490. 18 => 'Techno',
  491. 19 => 'Industrial',
  492. 20 => 'Alternative',
  493. 21 => 'Ska',
  494. 22 => 'Death Metal',
  495. 23 => 'Pranks',
  496. 24 => 'Soundtrack',
  497. 25 => 'Euro-Techno',
  498. 26 => 'Ambient',
  499. 27 => 'Trip-Hop',
  500. 28 => 'Vocal',
  501. 29 => 'Jazz+Funk',
  502. 30 => 'Fusion',
  503. 31 => 'Trance',
  504. 32 => 'Classical',
  505. 33 => 'Instrumental',
  506. 34 => 'Acid',
  507. 35 => 'House',
  508. 36 => 'Game',
  509. 37 => 'Sound Clip',
  510. 38 => 'Gospel',
  511. 39 => 'Noise',
  512. 40 => 'Alternative Rock',
  513. 41 => 'Bass',
  514. 42 => 'Soul',
  515. 43 => 'Punk',
  516. 44 => 'Space',
  517. 45 => 'Meditative',
  518. 46 => 'Instrumental Pop',
  519. 47 => 'Instrumental Rock',
  520. 48 => 'Ethnic',
  521. 49 => 'Gothic',
  522. 50 => 'Darkwave',
  523. 51 => 'Techno-Industrial',
  524. 52 => 'Electronic',
  525. 53 => 'Pop-Folk',
  526. 54 => 'Eurodance',
  527. 55 => 'Dream',
  528. 56 => 'Southern Rock',
  529. 57 => 'Comedy',
  530. 58 => 'Cult',
  531. 59 => 'Gangsta',
  532. 60 => 'Top 40',
  533. 61 => 'Christian Rap',
  534. 62 => 'Pop/Funk',
  535. 63 => 'Jungle',
  536. 64 => 'Native US',
  537. 65 => 'Cabaret',
  538. 66 => 'New Wave',
  539. 67 => 'Psychadelic',
  540. 68 => 'Rave',
  541. 69 => 'Showtunes',
  542. 70 => 'Trailer',
  543. 71 => 'Lo-Fi',
  544. 72 => 'Tribal',
  545. 73 => 'Acid Punk',
  546. 74 => 'Acid Jazz',
  547. 75 => 'Polka',
  548. 76 => 'Retro',
  549. 77 => 'Musical',
  550. 78 => 'Rock & Roll',
  551. 79 => 'Hard Rock',
  552. 80 => 'Folk',
  553. 81 => 'Folk-Rock',
  554. 82 => 'National Folk',
  555. 83 => 'Swing',
  556. 84 => 'Fast Fusion',
  557. 85 => 'Bebob',
  558. 86 => 'Latin',
  559. 87 => 'Revival',
  560. 88 => 'Celtic',
  561. 89 => 'Bluegrass',
  562. 90 => 'Avantgarde',
  563. 91 => 'Gothic Rock',
  564. 92 => 'Progressive Rock',
  565. 93 => 'Psychedelic Rock',
  566. 94 => 'Symphonic Rock',
  567. 95 => 'Slow Rock',
  568. 96 => 'Big Band',
  569. 97 => 'Chorus',
  570. 98 => 'Easy Listening',
  571. 99 => 'Acoustic',
  572. 100 => 'Humour',
  573. 101 => 'Speech',
  574. 102 => 'Chanson',
  575. 103 => 'Opera',
  576. 104 => 'Chamber Music',
  577. 105 => 'Sonata',
  578. 106 => 'Symphony',
  579. 107 => 'Booty Bass',
  580. 108 => 'Primus',
  581. 109 => 'Porn Groove',
  582. 110 => 'Satire',
  583. 111 => 'Slow Jam',
  584. 112 => 'Club',
  585. 113 => 'Tango',
  586. 114 => 'Samba',
  587. 115 => 'Folklore',
  588. 116 => 'Ballad',
  589. 117 => 'Power Ballad',
  590. 118 => 'Rhytmic Soul',
  591. 119 => 'Freestyle',
  592. 120 => 'Duet',
  593. 121 => 'Punk Rock',
  594. 122 => 'Drum Solo',
  595. 123 => 'Acapella',
  596. 124 => 'Euro-House',
  597. 125 => 'Dance Hall',
  598. 126 => 'Goa',
  599. 127 => 'Drum & Bass',
  600. 128 => 'Club-House',
  601. 129 => 'Hardcore',
  602. 130 => 'Terror',
  603. 131 => 'Indie',
  604. 132 => 'BritPop',
  605. 133 => 'Negerpunk',
  606. 134 => 'Polsk Punk',
  607. 135 => 'Beat',
  608. 136 => 'Christian Gangsta Rap',
  609. 137 => 'Heavy Metal',
  610. 138 => 'Black Metal',
  611. 139 => 'Crossover',
  612. 140 => 'Contemporary Christian',
  613. 141 => 'Christian Rock',
  614. 142 => 'Merengue',
  615. 143 => 'Salsa',
  616. 144 => 'Trash Metal',
  617. 145 => 'Anime',
  618. 146 => 'Jpop',
  619. 147 => 'Synthpop'
  620. );
  621. } // genres
  622. } // end of id3
  623. ?>

comments powered by Disqus