PageRenderTime 148ms CodeModel.GetById 20ms RepoModel.GetById 2ms app.codeStats 1ms

/common/libraries/plugin/getid3/demos/demo.mp3header.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 3672 lines | 2833 code | 481 blank | 358 comment | 583 complexity | 53daf93fbe080b7c0222b46fdd8b90ac MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT, GPL-2.0
  1. <?php
  2. if (! function_exists('PrintHexBytes'))
  3. {
  4. function PrintHexBytes($string)
  5. {
  6. $returnstring = '';
  7. for($i = 0; $i < strlen($string); $i ++)
  8. {
  9. $returnstring .= str_pad(dechex(ord(substr($string, $i, 1))), 2, '0', STR_PAD_LEFT) . ' ';
  10. }
  11. return $returnstring;
  12. }
  13. }
  14. if (! function_exists('PrintTextBytes'))
  15. {
  16. function PrintTextBytes($string)
  17. {
  18. $returnstring = '';
  19. for($i = 0; $i < strlen($string); $i ++)
  20. {
  21. if (ord(substr($string, $i, 1)) <= 31)
  22. {
  23. $returnstring .= ' ';
  24. }
  25. else
  26. {
  27. $returnstring .= ' ' . substr($string, $i, 1) . ' ';
  28. }
  29. }
  30. return $returnstring;
  31. }
  32. }
  33. if (! function_exists('FixDBFields'))
  34. {
  35. function FixDBFields($text)
  36. {
  37. return mysql_escape_string($text);
  38. }
  39. }
  40. if (! function_exists('FixTextFields'))
  41. {
  42. function FixTextFields($text)
  43. {
  44. $text = SafeStripSlashes($text);
  45. $text = htmlentities($text, ENT_QUOTES);
  46. return $text;
  47. }
  48. }
  49. if (! function_exists('SafeStripSlashes'))
  50. {
  51. function SafeStripSlashes($text)
  52. {
  53. if (get_magic_quotes_gpc())
  54. {
  55. return stripslashes($text);
  56. }
  57. return $text;
  58. }
  59. }
  60. if (! function_exists('table_var_dump'))
  61. {
  62. function table_var_dump($variable)
  63. {
  64. $returnstring = '';
  65. switch (gettype($variable))
  66. {
  67. case 'array' :
  68. $returnstring .= '<TABLE BORDER="1" CELLSPACING="0" CELLPADDING="2">';
  69. foreach ($variable as $key => $value)
  70. {
  71. $returnstring .= '<TR><TD VALIGN="TOP"><B>' . str_replace(chr(0), ' ', $key) . '</B></TD>';
  72. $returnstring .= '<TD VALIGN="TOP">' . gettype($value);
  73. if (is_array($value))
  74. {
  75. $returnstring .= '&nbsp;(' . count($value) . ')';
  76. }
  77. elseif (is_string($value))
  78. {
  79. $returnstring .= '&nbsp;(' . strlen($value) . ')';
  80. }
  81. if (($key == 'data') && isset($variable['image_mime']) && isset($variable['dataoffset']))
  82. {
  83. require_once (GETID3_INCLUDEPATH . 'getid3.getimagesize.php');
  84. $imageinfo = array();
  85. $imagechunkcheck = GetDataImageSize($value, $imageinfo);
  86. $DumpedImageSRC = (! empty($_REQUEST['filename']) ? $_REQUEST['filename'] : '.getid3') . '.' . $variable['dataoffset'] . '.' . ImageTypesLookup($imagechunkcheck[2]);
  87. if ($tempimagefile = fopen($DumpedImageSRC, 'wb'))
  88. {
  89. fwrite($tempimagefile, $value);
  90. fclose($tempimagefile);
  91. }
  92. $returnstring .= '</TD><TD><IMG SRC="' . $DumpedImageSRC . '" WIDTH="' . $imagechunkcheck[0] . '" HEIGHT="' . $imagechunkcheck[1] . '"></TD></TR>';
  93. }
  94. else
  95. {
  96. $returnstring .= '</TD><TD>' . table_var_dump($value) . '</TD></TR>';
  97. }
  98. }
  99. $returnstring .= '</TABLE>';
  100. break;
  101. case 'boolean' :
  102. $returnstring .= ($variable ? 'TRUE' : 'FALSE');
  103. break;
  104. case 'integer' :
  105. case 'double' :
  106. case 'float' :
  107. $returnstring .= $variable;
  108. break;
  109. case 'object' :
  110. case 'null' :
  111. $returnstring .= string_var_dump($variable);
  112. break;
  113. case 'string' :
  114. $variable = str_replace(chr(0), ' ', $variable);
  115. $varlen = strlen($variable);
  116. for($i = 0; $i < $varlen; $i ++)
  117. {
  118. if (ereg('[' . chr(0x0A) . chr(0x0D) . ' -;0-9A-Za-z]', $variable{$i}))
  119. {
  120. $returnstring .= $variable{$i};
  121. }
  122. else
  123. {
  124. $returnstring .= '&#' . str_pad(ord($variable{$i}), 3, '0', STR_PAD_LEFT) . ';';
  125. }
  126. }
  127. $returnstring = nl2br($returnstring);
  128. break;
  129. default :
  130. require_once (GETID3_INCLUDEPATH . 'getid3.getimagesize.php');
  131. $imageinfo = array();
  132. $imagechunkcheck = GetDataImageSize(substr($variable, 0, FREAD_BUFFER_SIZE), $imageinfo);
  133. if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3))
  134. {
  135. $returnstring .= '<TABLE BORDER="1" CELLSPACING="0" CELLPADDING="2">';
  136. $returnstring .= '<TR><TD><B>type</B></TD><TD>' . ImageTypesLookup($imagechunkcheck[2]) . '</TD></TR>';
  137. $returnstring .= '<TR><TD><B>width</B></TD><TD>' . number_format($imagechunkcheck[0]) . ' px</TD></TR>';
  138. $returnstring .= '<TR><TD><B>height</B></TD><TD>' . number_format($imagechunkcheck[1]) . ' px</TD></TR>';
  139. $returnstring .= '<TR><TD><B>size</B></TD><TD>' . number_format(strlen($variable)) . ' bytes</TD></TR></TABLE>';
  140. }
  141. else
  142. {
  143. $returnstring .= nl2br(htmlspecialchars(str_replace(chr(0), ' ', $variable)));
  144. }
  145. break;
  146. }
  147. return $returnstring;
  148. }
  149. }
  150. if (! function_exists('string_var_dump'))
  151. {
  152. function string_var_dump($variable)
  153. {
  154. ob_start();
  155. var_dump($variable);
  156. $dumpedvariable = ob_get_contents();
  157. ob_end_clean();
  158. return $dumpedvariable;
  159. }
  160. }
  161. if (! function_exists('fileextension'))
  162. {
  163. function fileextension($filename, $numextensions = 1)
  164. {
  165. if (strstr($filename, '.'))
  166. {
  167. $reversedfilename = strrev($filename);
  168. $offset = 0;
  169. for($i = 0; $i < $numextensions; $i ++)
  170. {
  171. $offset = strpos($reversedfilename, '.', $offset + 1);
  172. if ($offset === false)
  173. {
  174. return '';
  175. }
  176. }
  177. return strrev(substr($reversedfilename, 0, $offset));
  178. }
  179. return '';
  180. }
  181. }
  182. if (! function_exists('RemoveAccents'))
  183. {
  184. function RemoveAccents($string)
  185. {
  186. // return strtr($string, '���������������������������������������������������������������������', 'SOZsozYYuAAAAAAACEEEEIIIIDNOOOOOOUUUUYsaaaaaaaceeeeiiiionoooooouuuuyy');
  187. // Revised version by marksteward@hotmail.com
  188. return strtr(strtr($string, '������������������������������������������������������������', 'SZszYAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy'), array(
  189. '�' => 'TH', '�' => 'th', '�' => 'DH', '�' => 'dh', '�' => 'ss', '�' => 'OE', '�' => 'oe', '�' => 'AE',
  190. '�' => 'ae', '�' => 'u'));
  191. }
  192. }
  193. if (! function_exists('MoreNaturalSort'))
  194. {
  195. function MoreNaturalSort($ar1, $ar2)
  196. {
  197. if ($ar1 === $ar2)
  198. {
  199. return 0;
  200. }
  201. $len1 = strlen($ar1);
  202. $len2 = strlen($ar2);
  203. $shortest = min($len1, $len2);
  204. if (substr($ar1, 0, $shortest) === substr($ar2, 0, $shortest))
  205. {
  206. // the shorter argument is the beginning of the longer one, like "str" and "string"
  207. if ($len1 < $len2)
  208. {
  209. return - 1;
  210. }
  211. elseif ($len1 > $len2)
  212. {
  213. return 1;
  214. }
  215. return 0;
  216. }
  217. $ar1 = RemoveAccents(strtolower(trim($ar1)));
  218. $ar2 = RemoveAccents(strtolower(trim($ar2)));
  219. $translatearray = array('\'' => '', '"' => '', '_' => ' ', '(' => '', ')' => '', '-' => ' ', ' ' => ' ',
  220. '.' => '', ',' => '');
  221. foreach ($translatearray as $key => $val)
  222. {
  223. $ar1 = str_replace($key, $val, $ar1);
  224. $ar2 = str_replace($key, $val, $ar2);
  225. }
  226. if ($ar1 < $ar2)
  227. {
  228. return - 1;
  229. }
  230. elseif ($ar1 > $ar2)
  231. {
  232. return 1;
  233. }
  234. return 0;
  235. }
  236. }
  237. if (! function_exists('trunc'))
  238. {
  239. function trunc($floatnumber)
  240. {
  241. // truncates a floating-point number at the decimal point
  242. // returns int (if possible, otherwise float)
  243. if ($floatnumber >= 1)
  244. {
  245. $truncatednumber = floor($floatnumber);
  246. }
  247. elseif ($floatnumber <= - 1)
  248. {
  249. $truncatednumber = ceil($floatnumber);
  250. }
  251. else
  252. {
  253. $truncatednumber = 0;
  254. }
  255. if ($truncatednumber <= pow(2, 30))
  256. {
  257. $truncatednumber = (int) $truncatednumber;
  258. }
  259. return $truncatednumber;
  260. }
  261. }
  262. if (! function_exists('CastAsInt'))
  263. {
  264. function CastAsInt($floatnum)
  265. {
  266. // convert to float if not already
  267. $floatnum = (float) $floatnum;
  268. // convert a float to type int, only if possible
  269. if (trunc($floatnum) == $floatnum)
  270. {
  271. // it's not floating point
  272. if ($floatnum <= pow(2, 30))
  273. {
  274. // it's within int range
  275. $floatnum = (int) $floatnum;
  276. }
  277. }
  278. return $floatnum;
  279. }
  280. }
  281. if (! function_exists('getmicrotime'))
  282. {
  283. function getmicrotime()
  284. {
  285. list($usec, $sec) = explode(' ', microtime());
  286. return ((float) $usec + (float) $sec);
  287. }
  288. }
  289. if (! function_exists('DecimalBinary2Float'))
  290. {
  291. function DecimalBinary2Float($binarynumerator)
  292. {
  293. $numerator = Bin2Dec($binarynumerator);
  294. $denominator = Bin2Dec(str_repeat('1', strlen($binarynumerator)));
  295. return ($numerator / $denominator);
  296. }
  297. }
  298. if (! function_exists('NormalizeBinaryPoint'))
  299. {
  300. function NormalizeBinaryPoint($binarypointnumber, $maxbits = 52)
  301. {
  302. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
  303. if (strpos($binarypointnumber, '.') === false)
  304. {
  305. $binarypointnumber = '0.' . $binarypointnumber;
  306. }
  307. elseif ($binarypointnumber{0} == '.')
  308. {
  309. $binarypointnumber = '0' . $binarypointnumber;
  310. }
  311. $exponent = 0;
  312. while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.'))
  313. {
  314. if (substr($binarypointnumber, 1, 1) == '.')
  315. {
  316. $exponent --;
  317. $binarypointnumber = substr($binarypointnumber, 2, 1) . '.' . substr($binarypointnumber, 3);
  318. }
  319. else
  320. {
  321. $pointpos = strpos($binarypointnumber, '.');
  322. $exponent += ($pointpos - 1);
  323. $binarypointnumber = str_replace('.', '', $binarypointnumber);
  324. $binarypointnumber = $binarypointnumber{0} . '.' . substr($binarypointnumber, 1);
  325. }
  326. }
  327. $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
  328. return array('normalized' => $binarypointnumber, 'exponent' => (int) $exponent);
  329. }
  330. }
  331. if (! function_exists('Float2BinaryDecimal'))
  332. {
  333. function Float2BinaryDecimal($floatvalue)
  334. {
  335. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
  336. $maxbits = 128; // to how many bits of precision should the calculations be taken?
  337. $intpart = trunc($floatvalue);
  338. $floatpart = abs($floatvalue - $intpart);
  339. $pointbitstring = '';
  340. while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits))
  341. {
  342. $floatpart *= 2;
  343. $pointbitstring .= (string) trunc($floatpart);
  344. $floatpart -= trunc($floatpart);
  345. }
  346. $binarypointnumber = decbin($intpart) . '.' . $pointbitstring;
  347. return $binarypointnumber;
  348. }
  349. }
  350. if (! function_exists('Float2String'))
  351. {
  352. function Float2String($floatvalue, $bits)
  353. {
  354. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
  355. switch ($bits)
  356. {
  357. case 32 :
  358. $exponentbits = 8;
  359. $fractionbits = 23;
  360. break;
  361. case 64 :
  362. $exponentbits = 11;
  363. $fractionbits = 52;
  364. break;
  365. default :
  366. return false;
  367. break;
  368. }
  369. if ($floatvalue >= 0)
  370. {
  371. $signbit = '0';
  372. }
  373. else
  374. {
  375. $signbit = '1';
  376. }
  377. $normalizedbinary = NormalizeBinaryPoint(Float2BinaryDecimal($floatvalue), $fractionbits);
  378. $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent
  379. $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
  380. $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
  381. return BigEndian2String(Bin2Dec($signbit . $exponentbitstring . $fractionbitstring), $bits % 8, false);
  382. }
  383. }
  384. if (! function_exists('LittleEndian2Float'))
  385. {
  386. function LittleEndian2Float($byteword)
  387. {
  388. return BigEndian2Float(strrev($byteword));
  389. }
  390. }
  391. if (! function_exists('BigEndian2Float'))
  392. {
  393. function BigEndian2Float($byteword)
  394. {
  395. // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
  396. // http://www.psc.edu/general/software/packages/ieee/ieee.html
  397. // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
  398. $bitword = BigEndian2Bin($byteword);
  399. $signbit = $bitword{0};
  400. switch (strlen($byteword) * 8)
  401. {
  402. case 32 :
  403. $exponentbits = 8;
  404. $fractionbits = 23;
  405. break;
  406. case 64 :
  407. $exponentbits = 11;
  408. $fractionbits = 52;
  409. break;
  410. case 80 :
  411. $exponentbits = 16;
  412. $fractionbits = 64;
  413. break;
  414. default :
  415. return false;
  416. break;
  417. }
  418. $exponentstring = substr($bitword, 1, $exponentbits - 1);
  419. $fractionstring = substr($bitword, $exponentbits, $fractionbits);
  420. $exponent = Bin2Dec($exponentstring);
  421. $fraction = Bin2Dec($fractionstring);
  422. if (($exponentbits == 16) && ($fractionbits == 64))
  423. {
  424. // 80-bit
  425. // As used in Apple AIFF for sample_rate
  426. // A bit of a hack, but it works ;)
  427. return pow(2, ($exponent - 16382)) * DecimalBinary2Float($fractionstring);
  428. }
  429. if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0))
  430. {
  431. // Not a Number
  432. $floatvalue = false;
  433. }
  434. elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0))
  435. {
  436. if ($signbit == '1')
  437. {
  438. $floatvalue = '-infinity';
  439. }
  440. else
  441. {
  442. $floatvalue = '+infinity';
  443. }
  444. }
  445. elseif (($exponent == 0) && ($fraction == 0))
  446. {
  447. if ($signbit == '1')
  448. {
  449. $floatvalue = - 0;
  450. }
  451. else
  452. {
  453. $floatvalue = 0;
  454. }
  455. $floatvalue = ($signbit ? 0 : - 0);
  456. }
  457. elseif (($exponent == 0) && ($fraction != 0))
  458. {
  459. // These are 'unnormalized' values
  460. $floatvalue = pow(2, (- 1 * (pow(2, $exponentbits - 1) - 2))) * DecimalBinary2Float($fractionstring);
  461. if ($signbit == '1')
  462. {
  463. $floatvalue *= - 1;
  464. }
  465. }
  466. elseif ($exponent != 0)
  467. {
  468. $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + DecimalBinary2Float($fractionstring));
  469. if ($signbit == '1')
  470. {
  471. $floatvalue *= - 1;
  472. }
  473. }
  474. return (float) $floatvalue;
  475. }
  476. }
  477. if (! function_exists('BigEndian2Int'))
  478. {
  479. function BigEndian2Int($byteword, $synchsafe = false, $signed = false)
  480. {
  481. $intvalue = 0;
  482. $bytewordlen = strlen($byteword);
  483. for($i = 0; $i < $bytewordlen; $i ++)
  484. {
  485. if ($synchsafe)
  486. { // disregard MSB, effectively 7-bit bytes
  487. $intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7);
  488. }
  489. else
  490. {
  491. $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
  492. }
  493. }
  494. if ($signed && ! $synchsafe)
  495. {
  496. // synchsafe ints are not allowed to be signed
  497. switch ($bytewordlen)
  498. {
  499. case 1 :
  500. case 2 :
  501. case 3 :
  502. case 4 :
  503. $signmaskbit = 0x80 << (8 * ($bytewordlen - 1));
  504. if ($intvalue & $signmaskbit)
  505. {
  506. $intvalue = 0 - ($intvalue & ($signmaskbit - 1));
  507. }
  508. break;
  509. default :
  510. die('ERROR: Cannot have signed integers larger than 32-bits in BigEndian2Int()');
  511. break;
  512. }
  513. }
  514. return CastAsInt($intvalue);
  515. }
  516. }
  517. if (! function_exists('LittleEndian2Int'))
  518. {
  519. function LittleEndian2Int($byteword, $signed = false)
  520. {
  521. return BigEndian2Int(strrev($byteword), false, $signed);
  522. }
  523. }
  524. if (! function_exists('BigEndian2Bin'))
  525. {
  526. function BigEndian2Bin($byteword)
  527. {
  528. $binvalue = '';
  529. $bytewordlen = strlen($byteword);
  530. for($i = 0; $i < $bytewordlen; $i ++)
  531. {
  532. $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
  533. }
  534. return $binvalue;
  535. }
  536. }
  537. if (! function_exists('BigEndian2String'))
  538. {
  539. function BigEndian2String($number, $minbytes = 1, $synchsafe = false, $signed = false)
  540. {
  541. if ($number < 0)
  542. {
  543. return false;
  544. }
  545. $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
  546. $intstring = '';
  547. if ($signed)
  548. {
  549. if ($minbytes > 4)
  550. {
  551. die('ERROR: Cannot have signed integers larger than 32-bits in BigEndian2String()');
  552. }
  553. $number = $number & (0x80 << (8 * ($minbytes - 1)));
  554. }
  555. while ($number != 0)
  556. {
  557. $quotient = ($number / ($maskbyte + 1));
  558. $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)) . $intstring;
  559. $number = floor($quotient);
  560. }
  561. return str_pad($intstring, $minbytes, chr(0), STR_PAD_LEFT);
  562. }
  563. }
  564. if (! function_exists('Dec2Bin'))
  565. {
  566. function Dec2Bin($number)
  567. {
  568. while ($number >= 256)
  569. {
  570. $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
  571. $number = floor($number / 256);
  572. }
  573. $bytes[] = $number;
  574. $binstring = '';
  575. for($i = 0; $i < count($bytes); $i ++)
  576. {
  577. $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)) . $binstring;
  578. }
  579. return $binstring;
  580. }
  581. }
  582. if (! function_exists('Bin2Dec'))
  583. {
  584. function Bin2Dec($binstring)
  585. {
  586. $decvalue = 0;
  587. for($i = 0; $i < strlen($binstring); $i ++)
  588. {
  589. $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
  590. }
  591. return CastAsInt($decvalue);
  592. }
  593. }
  594. if (! function_exists('Bin2String'))
  595. {
  596. function Bin2String($binstring)
  597. {
  598. // return 'hi' for input of '0110100001101001'
  599. $string = '';
  600. $binstringreversed = strrev($binstring);
  601. for($i = 0; $i < strlen($binstringreversed); $i += 8)
  602. {
  603. $string = chr(Bin2Dec(strrev(substr($binstringreversed, $i, 8)))) . $string;
  604. }
  605. return $string;
  606. }
  607. }
  608. if (! function_exists('LittleEndian2String'))
  609. {
  610. function LittleEndian2String($number, $minbytes = 1, $synchsafe = false)
  611. {
  612. $intstring = '';
  613. while ($number > 0)
  614. {
  615. if ($synchsafe)
  616. {
  617. $intstring = $intstring . chr($number & 127);
  618. $number >>= 7;
  619. }
  620. else
  621. {
  622. $intstring = $intstring . chr($number & 255);
  623. $number >>= 8;
  624. }
  625. }
  626. return str_pad($intstring, $minbytes, chr(0), STR_PAD_RIGHT);
  627. }
  628. }
  629. if (! function_exists('Bool2IntString'))
  630. {
  631. function Bool2IntString($intvalue)
  632. {
  633. return ($intvalue ? '1' : '0');
  634. }
  635. }
  636. if (! function_exists('IntString2Bool'))
  637. {
  638. function IntString2Bool($char)
  639. {
  640. if ($char == '1')
  641. {
  642. return true;
  643. }
  644. elseif ($char == '0')
  645. {
  646. return false;
  647. }
  648. return null;
  649. }
  650. }
  651. if (! function_exists('InverseBoolean'))
  652. {
  653. function InverseBoolean($value)
  654. {
  655. return ($value ? false : true);
  656. }
  657. }
  658. if (! function_exists('DeUnSynchronise'))
  659. {
  660. function DeUnSynchronise($data)
  661. {
  662. return str_replace(chr(0xFF) . chr(0x00), chr(0xFF), $data);
  663. }
  664. }
  665. if (! function_exists('Unsynchronise'))
  666. {
  667. function Unsynchronise($data)
  668. {
  669. // Whenever a false synchronisation is found within the tag, one zeroed
  670. // byte is inserted after the first false synchronisation byte. The
  671. // format of a correct sync that should be altered by ID3 encoders is as
  672. // follows:
  673. // %11111111 111xxxxx
  674. // And should be replaced with:
  675. // %11111111 00000000 111xxxxx
  676. // This has the side effect that all $FF 00 combinations have to be
  677. // altered, so they won't be affected by the decoding process. Therefore
  678. // all the $FF 00 combinations have to be replaced with the $FF 00 00
  679. // combination during the unsynchronisation.
  680. $data = str_replace(chr(0xFF) . chr(0x00), chr(0xFF) . chr(0x00) . chr(0x00), $data);
  681. $unsyncheddata = '';
  682. for($i = 0; $i < strlen($data); $i ++)
  683. {
  684. $thischar = $data{$i};
  685. $unsyncheddata .= $thischar;
  686. if ($thischar == chr(255))
  687. {
  688. $nextchar = ord(substr($data, $i + 1, 1));
  689. if (($nextchar | 0xE0) == 0xE0)
  690. {
  691. // previous byte = 11111111, this byte = 111?????
  692. $unsyncheddata .= chr(0);
  693. }
  694. }
  695. }
  696. return $unsyncheddata;
  697. }
  698. }
  699. if (! function_exists('is_hash'))
  700. {
  701. function is_hash($var)
  702. {
  703. // written by dev-null@christophe.vg
  704. // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
  705. if (is_array($var))
  706. {
  707. $keys = array_keys($var);
  708. $all_num = true;
  709. for($i = 0; $i < count($keys); $i ++)
  710. {
  711. if (is_string($keys[$i]))
  712. {
  713. return true;
  714. }
  715. }
  716. }
  717. return false;
  718. }
  719. }
  720. if (! function_exists('array_join_merge'))
  721. {
  722. function array_join_merge($arr1, $arr2)
  723. {
  724. // written by dev-null@christophe.vg
  725. // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
  726. if (is_array($arr1) && is_array($arr2))
  727. {
  728. // the same -> merge
  729. $new_array = array();
  730. if (is_hash($arr1) && is_hash($arr2))
  731. {
  732. // hashes -> merge based on keys
  733. $keys = array_merge(array_keys($arr1), array_keys($arr2));
  734. foreach ($keys as $key)
  735. {
  736. $new_array[$key] = array_join_merge(@$arr1[$key], @$arr2[$key]);
  737. }
  738. }
  739. else
  740. {
  741. // two real arrays -> merge
  742. $new_array = array_reverse(array_unique(array_reverse(array_merge($arr1, $arr2))));
  743. }
  744. return $new_array;
  745. }
  746. else
  747. {
  748. // not the same ... take new one if defined, else the old one stays
  749. return $arr2 ? $arr2 : $arr1;
  750. }
  751. }
  752. }
  753. if (! function_exists('array_merge_clobber'))
  754. {
  755. function array_merge_clobber($array1, $array2)
  756. {
  757. // written by kc@hireability.com
  758. // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
  759. if (! is_array($array1) || ! is_array($array2))
  760. {
  761. return false;
  762. }
  763. $newarray = $array1;
  764. foreach ($array2 as $key => $val)
  765. {
  766. if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key]))
  767. {
  768. $newarray[$key] = array_merge_clobber($newarray[$key], $val);
  769. }
  770. else
  771. {
  772. $newarray[$key] = $val;
  773. }
  774. }
  775. return $newarray;
  776. }
  777. }
  778. if (! function_exists('array_merge_noclobber'))
  779. {
  780. function array_merge_noclobber($array1, $array2)
  781. {
  782. if (! is_array($array1) || ! is_array($array2))
  783. {
  784. return false;
  785. }
  786. $newarray = $array1;
  787. foreach ($array2 as $key => $val)
  788. {
  789. if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key]))
  790. {
  791. $newarray[$key] = array_merge_noclobber($newarray[$key], $val);
  792. }
  793. elseif (! isset($newarray[$key]))
  794. {
  795. $newarray[$key] = $val;
  796. }
  797. }
  798. return $newarray;
  799. }
  800. }
  801. if (! function_exists('RoughTranslateUnicodeToASCII'))
  802. {
  803. function RoughTranslateUnicodeToASCII($rawdata, $frame_textencoding)
  804. {
  805. // rough translation of data for application that can't handle Unicode data
  806. $tempstring = '';
  807. switch ($frame_textencoding)
  808. {
  809. case 0 : // ISO-8859-1. Terminated with $00.
  810. $asciidata = $rawdata;
  811. break;
  812. case 1 : // UTF-16 encoded Unicode with BOM. Terminated with $00 00.
  813. $asciidata = $rawdata;
  814. if (substr($asciidata, 0, 2) == chr(0xFF) . chr(0xFE))
  815. {
  816. // remove BOM, only if present (it should be, but...)
  817. $asciidata = substr($asciidata, 2);
  818. }
  819. if (substr($asciidata, strlen($asciidata) - 2, 2) == chr(0) . chr(0))
  820. {
  821. $asciidata = substr($asciidata, 0, strlen($asciidata) - 2); // remove terminator, only if present (it should be, but...)
  822. }
  823. for($i = 0; $i < strlen($asciidata); $i += 2)
  824. {
  825. if ((ord($asciidata{$i}) <= 0x7F) || (ord($asciidata{$i}) >= 0xA0))
  826. {
  827. $tempstring .= $asciidata{$i};
  828. }
  829. else
  830. {
  831. $tempstring .= '?';
  832. }
  833. }
  834. $asciidata = $tempstring;
  835. break;
  836. case 2 : // UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
  837. $asciidata = $rawdata;
  838. if (substr($asciidata, strlen($asciidata) - 2, 2) == chr(0) . chr(0))
  839. {
  840. $asciidata = substr($asciidata, 0, strlen($asciidata) - 2); // remove terminator, only if present (it should be, but...)
  841. }
  842. for($i = 0; $i < strlen($asciidata); $i += 2)
  843. {
  844. if ((ord($asciidata{$i}) <= 0x7F) || (ord($asciidata{$i}) >= 0xA0))
  845. {
  846. $tempstring .= $asciidata{$i};
  847. }
  848. else
  849. {
  850. $tempstring .= '?';
  851. }
  852. }
  853. $asciidata = $tempstring;
  854. break;
  855. case 3 : // UTF-8 encoded Unicode. Terminated with $00.
  856. $asciidata = utf8_decode($rawdata);
  857. break;
  858. case 255 : // Unicode, Big-Endian. Terminated with $00 00.
  859. $asciidata = $rawdata;
  860. if (substr($asciidata, strlen($asciidata) - 2, 2) == chr(0) . chr(0))
  861. {
  862. $asciidata = substr($asciidata, 0, strlen($asciidata) - 2); // remove terminator, only if present (it should be, but...)
  863. }
  864. for($i = 0; ($i + 1) < strlen($asciidata); $i += 2)
  865. {
  866. if ((ord($asciidata{($i + 1)}) <= 0x7F) || (ord($asciidata{($i + 1)}) >= 0xA0))
  867. {
  868. $tempstring .= $asciidata{($i + 1)};
  869. }
  870. else
  871. {
  872. $tempstring .= '?';
  873. }
  874. }
  875. $asciidata = $tempstring;
  876. break;
  877. default :
  878. // shouldn't happen, but in case $frame_textencoding is not 1 <= $frame_textencoding <= 4
  879. // just pass the data through unchanged.
  880. $asciidata = $rawdata;
  881. break;
  882. }
  883. if (substr($asciidata, strlen($asciidata) - 1, 1) == chr(0))
  884. {
  885. // remove null terminator, if present
  886. $asciidata = NoNullString($asciidata);
  887. }
  888. return $asciidata;
  889. // return str_replace(chr(0), '', $asciidata); // just in case any nulls slipped through
  890. }
  891. }
  892. if (! function_exists('PlaytimeString'))
  893. {
  894. function PlaytimeString($playtimeseconds)
  895. {
  896. $contentseconds = round((($playtimeseconds / 60) - floor($playtimeseconds / 60)) * 60);
  897. $contentminutes = floor($playtimeseconds / 60);
  898. if ($contentseconds >= 60)
  899. {
  900. $contentseconds -= 60;
  901. $contentminutes ++;
  902. }
  903. return number_format($contentminutes) . ':' . str_pad($contentseconds, 2, 0, STR_PAD_LEFT);
  904. }
  905. }
  906. if (! function_exists('CloseMatch'))
  907. {
  908. function CloseMatch($value1, $value2, $tolerance)
  909. {
  910. return (abs($value1 - $value2) <= $tolerance);
  911. }
  912. }
  913. if (! function_exists('ID3v1matchesID3v2'))
  914. {
  915. function ID3v1matchesID3v2($id3v1, $id3v2)
  916. {
  917. $requiredindices = array('title', 'artist', 'album', 'year', 'genre', 'comment');
  918. foreach ($requiredindices as $requiredindex)
  919. {
  920. if (! isset($id3v1["$requiredindex"]))
  921. {
  922. $id3v1["$requiredindex"] = '';
  923. }
  924. if (! isset($id3v2["$requiredindex"]))
  925. {
  926. $id3v2["$requiredindex"] = '';
  927. }
  928. }
  929. if (trim($id3v1['title']) != trim(substr($id3v2['title'], 0, 30)))
  930. {
  931. return false;
  932. }
  933. if (trim($id3v1['artist']) != trim(substr($id3v2['artist'], 0, 30)))
  934. {
  935. return false;
  936. }
  937. if (trim($id3v1['album']) != trim(substr($id3v2['album'], 0, 30)))
  938. {
  939. return false;
  940. }
  941. if (trim($id3v1['year']) != trim(substr($id3v2['year'], 0, 4)))
  942. {
  943. return false;
  944. }
  945. if (trim($id3v1['genre']) != trim($id3v2['genre']))
  946. {
  947. return false;
  948. }
  949. if (isset($id3v1['track']))
  950. {
  951. if (! isset($id3v1['track']) || (trim($id3v1['track']) != trim($id3v2['track'])))
  952. {
  953. return false;
  954. }
  955. if (trim($id3v1['comment']) != trim(substr($id3v2['comment'], 0, 28)))
  956. {
  957. return false;
  958. }
  959. }
  960. else
  961. {
  962. if (trim($id3v1['comment']) != trim(substr($id3v2['comment'], 0, 30)))
  963. {
  964. return false;
  965. }
  966. }
  967. return true;
  968. }
  969. }
  970. if (! function_exists('FILETIMEtoUNIXtime'))
  971. {
  972. function FILETIMEtoUNIXtime($FILETIME, $round = true)
  973. {
  974. // FILETIME is a 64-bit unsigned integer representing
  975. // the number of 100-nanosecond intervals since January 1, 1601
  976. // UNIX timestamp is number of seconds since January 1, 1970
  977. // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days
  978. if ($round)
  979. {
  980. return round(($FILETIME - 116444736000000000) / 10000000);
  981. }
  982. return ($FILETIME - 116444736000000000) / 10000000;
  983. }
  984. }
  985. if (! function_exists('GUIDtoBytestring'))
  986. {
  987. function GUIDtoBytestring($GUIDstring)
  988. {
  989. // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way:
  990. // first 4 bytes are in little-endian order
  991. // next 2 bytes are appended in little-endian order
  992. // next 2 bytes are appended in little-endian order
  993. // next 2 bytes are appended in big-endian order
  994. // next 6 bytes are appended in big-endian order
  995. // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string:
  996. // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp
  997. $hexbytecharstring = chr(hexdec(substr($GUIDstring, 6, 2)));
  998. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 4, 2)));
  999. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 2, 2)));
  1000. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 0, 2)));
  1001. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2)));
  1002. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 9, 2)));
  1003. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2)));
  1004. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2)));
  1005. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2)));
  1006. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2)));
  1007. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2)));
  1008. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2)));
  1009. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2)));
  1010. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2)));
  1011. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2)));
  1012. $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2)));
  1013. return $hexbytecharstring;
  1014. }
  1015. }
  1016. if (! function_exists('BytestringToGUID'))
  1017. {
  1018. function BytestringToGUID($Bytestring)
  1019. {
  1020. $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT);
  1021. $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT);
  1022. $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT);
  1023. $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT);
  1024. $GUIDstring .= '-';
  1025. $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT);
  1026. $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT);
  1027. $GUIDstring .= '-';
  1028. $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT);
  1029. $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT);
  1030. $GUIDstring .= '-';
  1031. $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT);
  1032. $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT);
  1033. $GUIDstring .= '-';
  1034. $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT);
  1035. $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT);
  1036. $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT);
  1037. $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT);
  1038. $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT);
  1039. $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT);
  1040. return strtoupper($GUIDstring);
  1041. }
  1042. }
  1043. if (! function_exists('BitrateColor'))
  1044. {
  1045. function BitrateColor($bitrate)
  1046. {
  1047. $bitrate /= 3; // scale from 1-768kbps to 1-256kbps
  1048. $bitrate --; // scale from 1-256kbps to 0-255kbps
  1049. $bitrate = max($bitrate, 0);
  1050. $bitrate = min($bitrate, 255);
  1051. //$bitrate = max($bitrate, 32);
  1052. //$bitrate = min($bitrate, 143);
  1053. //$bitrate = ($bitrate * 2) - 32;
  1054. $Rcomponent = max(255 - ($bitrate * 2), 0);
  1055. $Gcomponent = max(($bitrate * 2) - 255, 0);
  1056. if ($bitrate > 127)
  1057. {
  1058. $Bcomponent = max((255 - $bitrate) * 2, 0);
  1059. }
  1060. else
  1061. {
  1062. $Bcomponent = max($bitrate * 2, 0);
  1063. }
  1064. return str_pad(dechex($Rcomponent), 2, '0', STR_PAD_LEFT) . str_pad(dechex($Gcomponent), 2, '0', STR_PAD_LEFT) . str_pad(dechex($Bcomponent), 2, '0', STR_PAD_LEFT);
  1065. }
  1066. }
  1067. if (! function_exists('BitrateText'))
  1068. {
  1069. function BitrateText($bitrate)
  1070. {
  1071. return '<SPAN STYLE="color: #' . BitrateColor($bitrate) . '">' . round($bitrate) . ' kbps</SPAN>';
  1072. }
  1073. }
  1074. if (! function_exists('image_type_to_mime_type'))
  1075. {
  1076. function image_type_to_mime_type($imagetypeid)
  1077. {
  1078. // only available in PHP v4.3.0+
  1079. static $image_type_to_mime_type = array();
  1080. if (empty($image_type_to_mime_type))
  1081. {
  1082. $image_type_to_mime_type[1] = 'image/gif'; // GIF
  1083. $image_type_to_mime_type[2] = 'image/jpeg'; // JPEG
  1084. $image_type_to_mime_type[3] = 'image/png'; // PNG
  1085. $image_type_to_mime_type[4] = 'application/x-shockwave-flash'; // Flash
  1086. $image_type_to_mime_type[5] = 'image/psd'; // PSD
  1087. $image_type_to_mime_type[6] = 'image/bmp'; // BMP
  1088. $image_type_to_mime_type[7] = 'image/tiff'; // TIFF: little-endian (Intel)
  1089. $image_type_to_mime_type[8] = 'image/tiff'; // TIFF: big-endian (Motorola)
  1090. //$image_type_to_mime_type[9] = 'image/jpc'; // JPC
  1091. //$image_type_to_mime_type[10] = 'image/jp2'; // JPC
  1092. //$image_type_to_mime_type[11] = 'image/jpx'; // JPC
  1093. //$image_type_to_mime_type[12] = 'image/jb2'; // JPC
  1094. $image_type_to_mime_type[13] = 'application/x-shockwave-flash'; // Shockwave
  1095. $image_type_to_mime_type[14] = 'image/iff'; // IFF
  1096. }
  1097. return (isset($image_type_to_mime_type[$imagetypeid]) ? $image_type_to_mime_type[$imagetypeid] : 'application/octet-stream');
  1098. }
  1099. }
  1100. if (! function_exists('utf8_decode'))
  1101. {
  1102. // PHP has this function built-in if it's configured with the --with-xml option
  1103. // This version of the function is only provided in case XML isn't installed
  1104. function utf8_decode($utf8text)
  1105. {
  1106. // http://www.php.net/manual/en/function.utf8-encode.php
  1107. // bytes bits representation
  1108. // 1 7 0bbbbbbb
  1109. // 2 11 110bbbbb 10bbbbbb
  1110. // 3 16 1110bbbb 10bbbbbb 10bbbbbb
  1111. // 4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
  1112. $utf8length = strlen($utf8text);
  1113. $decodedtext = '';
  1114. for($i = 0; $i < $utf8length; $i ++)
  1115. {
  1116. if ((ord($utf8text{$i}) & 0x80) == 0)
  1117. {
  1118. $decodedtext .= $utf8text{$i};
  1119. }
  1120. elseif ((ord($utf8text{$i}) & 0xF0) == 0xF0)
  1121. {
  1122. $decodedtext .= '?';
  1123. $i += 3;
  1124. }
  1125. elseif ((ord($utf8text{$i}) & 0xE0) == 0xE0)
  1126. {
  1127. $decodedtext .= '?';
  1128. $i += 2;
  1129. }
  1130. elseif ((ord($utf8text{$i}) & 0xC0) == 0xC0)
  1131. {
  1132. // 2 11 110bbbbb 10bbbbbb
  1133. $decodedchar = Bin2Dec(substr(Dec2Bin(ord($utf8text{$i})), 3, 5) . substr(Dec2Bin(ord($utf8text{($i + 1)})), 2, 6));
  1134. if ($decodedchar <= 255)
  1135. {
  1136. $decodedtext .= chr($decodedchar);
  1137. }
  1138. else
  1139. {
  1140. $decodedtext .= '?';
  1141. }
  1142. $i += 1;
  1143. }
  1144. }
  1145. return $decodedtext;
  1146. }
  1147. }
  1148. if (! function_exists('DateMac2Unix'))
  1149. {
  1150. function DateMac2Unix($macdate)
  1151. {
  1152. // Macintosh timestamp: seconds since 00:00h January 1, 1904
  1153. // UNIX timestamp: seconds since 00:00h January 1, 1970
  1154. return CastAsInt($macdate - 2082844800);
  1155. }
  1156. }
  1157. if (! function_exists('FixedPoint8_8'))
  1158. {
  1159. function FixedPoint8_8($rawdata)
  1160. {
  1161. return BigEndian2Int(substr($rawdata, 0, 1)) + (float) (BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
  1162. }
  1163. }
  1164. if (! function_exists('FixedPoint16_16'))
  1165. {
  1166. function FixedPoint16_16($rawdata)
  1167. {
  1168. return BigEndian2Int(substr($rawdata, 0, 2)) + (float) (BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
  1169. }
  1170. }
  1171. if (! function_exists('FixedPoint2_30'))
  1172. {
  1173. function FixedPoint2_30($rawdata)
  1174. {
  1175. $binarystring = BigEndian2Bin($rawdata);
  1176. return Bin2Dec(substr($binarystring, 0, 2)) + (float) (Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
  1177. }
  1178. }
  1179. if (! function_exists('Pascal2String'))
  1180. {
  1181. function Pascal2String($pascalstring)
  1182. {
  1183. // Pascal strings have 1 byte at the beginning saying how many chars are in the string
  1184. return substr($pascalstring, 1);
  1185. }
  1186. }
  1187. if (! function_exists('NoNullString'))
  1188. {
  1189. function NoNullString($nullterminatedstring)
  1190. {
  1191. // remove the single null terminator on null terminated strings
  1192. if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === chr(0))
  1193. {
  1194. return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
  1195. }
  1196. return $nullterminatedstring;
  1197. }
  1198. }
  1199. if (! function_exists('FileSizeNiceDisplay'))
  1200. {
  1201. function FileSizeNiceDisplay($filesize, $precision = 2)
  1202. {
  1203. if ($filesize < 1000)
  1204. {
  1205. $sizeunit = 'bytes';
  1206. $precision = 0;
  1207. }
  1208. else
  1209. {
  1210. $filesize /= 1024;
  1211. $sizeunit = 'kB';
  1212. }
  1213. if ($filesize >= 1000)
  1214. {
  1215. $filesize /= 1024;
  1216. $sizeunit = 'MB';
  1217. }
  1218. if ($filesize >= 1000)
  1219. {
  1220. $filesize /= 1024;
  1221. $sizeunit = 'GB';
  1222. }
  1223. return number_format($filesize, $precision) . ' ' . $sizeunit;
  1224. }
  1225. }
  1226. if (! function_exists('DOStime2UNIXtime'))
  1227. {
  1228. function DOStime2UNIXtime($DOSdate, $DOStime)
  1229. {
  1230. // wFatDate
  1231. // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format:
  1232. // Bits Contents
  1233. // 0-4 Day of the month (1-31)
  1234. // 5-8 Month (1 = January, 2 = February, and so on)
  1235. // 9-15 Year offset from 1980 (add 1980 to get actual year)
  1236. $UNIXday = ($DOSdate & 0x001F);
  1237. $UNIXmonth = (($DOSdate & 0x01E0) >> 5);
  1238. $UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980;
  1239. // wFatTime
  1240. // Specifies the MS-DOS time. The time is a packed 16-bit value with the following format:
  1241. // Bits Contents
  1242. // 0-4 Second divided by 2
  1243. // 5-10 Minute (0-59)
  1244. // 11-15 Hour (0-23 on a 24-hour clock)
  1245. $UNIXsecond = ($DOStime & 0x001F) * 2;
  1246. $UNIXminute = (($DOStime & 0x07E0) >> 5);
  1247. $UNIXhour = (($DOStime & 0xF800) >> 11);
  1248. return mktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear);
  1249. }
  1250. }
  1251. if (! function_exists('CreateDeepArray'))
  1252. {
  1253. function CreateDeepArray($ArrayPath, $Separator, $Value)
  1254. {
  1255. // assigns $Value to a nested array path:
  1256. // $foo = CreateDeepArray('/path/to/my', '/', 'file.txt')
  1257. // is the same as:
  1258. // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
  1259. // or
  1260. // $foo['path']['to']['my'] = 'file.txt';
  1261. while ($ArrayPath{0} == $Separator)
  1262. {
  1263. $ArrayPath = substr($ArrayPath, 1);
  1264. }
  1265. if (($pos = strpos($ArrayPath, $Separator)) !== false)
  1266. {
  1267. $ReturnedArray[substr($ArrayPath, 0, $pos)] = CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
  1268. }
  1269. else
  1270. {
  1271. $ReturnedArray["$ArrayPath"] = $Value;
  1272. }
  1273. return $ReturnedArray;
  1274. }
  1275. }
  1276. if (! function_exists('md5_file'))
  1277. {
  1278. // Allan Hansen <ah@artemis.dk>
  1279. // md5_file() exists in PHP 4.2.0.
  1280. // The following works under UNIX only, but dies on windows
  1281. function md5_file($file)
  1282. {
  1283. if (substr(php_uname(), 0, 7) == 'Windows')
  1284. {
  1285. die('PHP 4.2.0 or newer required for md5_file()');
  1286. }
  1287. $file = str_replace('`', '\\`', $file);
  1288. if (ereg("^([0-9a-f]{32})[ \t\n\r]", `md5sum "$file"`, $r))
  1289. {
  1290. return $r[1];
  1291. }
  1292. return false;
  1293. }
  1294. }
  1295. if (! function_exists('md5_data'))
  1296. {
  1297. // Allan Hansen <ah@artemis.dk>
  1298. // md5_data() - returns md5sum for a file from startuing position to absolute end position
  1299. function md5_data($file, $offset, $end, $invertsign = false)
  1300. {
  1301. // first try and create a temporary file in the same directory as the file being scanned
  1302. if (($dataMD5filename = tempnam(dirname($file), eregi_replace('[^[:alnum:]]', '', basename($file)))) === false)
  1303. {
  1304. // if that fails, create a temporary file in the system temp directory
  1305. if (($dataMD5filename = tempnam('/tmp', 'getID3')) === false)
  1306. {
  1307. // if that fails, create a temporary file in the current directory
  1308. if (($dataMD5filename = tempnam('.', eregi_replace('[^[:alnum:]]', '', basename($file)))) === false)
  1309. {
  1310. // can't find anywhere to create a temp file, just die
  1311. return false;
  1312. }
  1313. }
  1314. }
  1315. $md5 = false;
  1316. set_time_limit(max(filesize($file) / 1000000, 30));
  1317. // copy parts of file
  1318. if ($fp = @fopen($file, 'rb'))
  1319. {
  1320. if ($MD5fp = @fopen($dataMD5filename, 'wb'))
  1321. {
  1322. if ($invertsign)
  1323. {
  1324. // Load conversion lookup strings for 8-bit unsigned->signed conversion below
  1325. $from = '';
  1326. $to = '';
  1327. for($i = 0; $i < 128; $i ++)
  1328. {
  1329. $from .= chr($i);
  1330. $to .= chr($i + 128);
  1331. }
  1332. for($i = 128; $i < 256; $i ++)
  1333. {
  1334. $from .= chr($i);
  1335. $to .= chr($i - 128);
  1336. }
  1337. }
  1338. fseek($fp, $offset, SEEK_SET);
  1339. $byteslefttowrite = $end - $offset;
  1340. while (($byteslefttowrite > 0) && ($buffer = fread($fp, FREAD_BUFFER_SIZE)))
  1341. {
  1342. if ($invertsign)
  1343. {
  1344. // Possibly FLAC-specific (?)
  1345. // FLAC calculates the MD5sum of the source data of 8-bit files
  1346. // not on the actual byte values in the source file, but of those
  1347. // values converted from unsigned to signed, or more specifcally,
  1348. // with the MSB inverted. ex: 01 -> 81; F5 -> 75; etc
  1349. // Therefore, 8-bit WAV data has to be converted before getting the
  1350. // md5_data value so as to match the FLAC value
  1351. // Flip the MSB for each byte in the buffer before copying
  1352. $buffer = strtr($buffer, $from, $to);
  1353. }
  1354. $byteswritten = fwrite($MD5fp, $buffer, $byteslefttowrite);
  1355. $byteslefttowrite -= $byteswritten;
  1356. }
  1357. fclose($MD5fp);
  1358. $md5 = md5_file($dataMD5filename);
  1359. }
  1360. fclose($fp);
  1361. }
  1362. unlink($dataMD5filename);
  1363. return $md5;
  1364. }
  1365. }
  1366. if (! function_exists('TwosCompliment2Decimal'))
  1367. {
  1368. function TwosCompliment2Decimal($BinaryValue)
  1369. {
  1370. // http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html
  1371. // First check if the number is negative or positive by looking at the sign bit.
  1372. // If it is positive, simply convert it to decimal.
  1373. // If it is negative, make it positive by inverting the bits and adding one.
  1374. // Then, convert the result to decimal.
  1375. // The negative of this number is the value of the original binary.
  1376. if ($BinaryValue & 0x80)
  1377. {
  1378. // negative number
  1379. return (0 - ((~ $BinaryValue & 0xFF) + 1));
  1380. }
  1381. else
  1382. {
  1383. // positive number
  1384. return $BinaryValue;
  1385. }
  1386. }
  1387. }
  1388. if (! function_exists('LastArrayElement'))
  1389. {
  1390. function LastArrayElement($MyArray)
  1391. {
  1392. if (! is_array($MyArray))
  1393. {
  1394. return false;
  1395. }
  1396. if (empty($MyArray))
  1397. {
  1398. return null;
  1399. }
  1400. foreach ($MyArray as $key => $value)
  1401. {
  1402. }
  1403. return $value;
  1404. }
  1405. }
  1406. if (! function_exists('safe_inc'))
  1407. {
  1408. function safe_inc(&$variable, $increment = 1)
  1409. {
  1410. if (isset($variable))
  1411. {
  1412. $variable += $increment;
  1413. }
  1414. else
  1415. {
  1416. $variable = $increment;
  1417. }
  1418. return true;
  1419. }
  1420. }
  1421. if (! function_exists('CalculateCompressionRatioVideo'))
  1422. {
  1423. function CalculateCompressionRatioVideo(&$ThisFileInfo)
  1424. {
  1425. if (empty($ThisFileInfo['video']))
  1426. {
  1427. return false;
  1428. }
  1429. if (empty($ThisFileInfo['video']['resolution_x']) || empty($ThisFileInfo['video']['resolution_y']))
  1430. {
  1431. return false;
  1432. }
  1433. if (empty($ThisFileInfo['video']['bits_per_sample']))
  1434. {
  1435. return false;
  1436. }
  1437. switch ($ThisFileInfo['video']['dataformat'])
  1438. {
  1439. case 'bmp' :
  1440. case 'gif' :
  1441. case 'jpeg' :
  1442. case 'jpg' :
  1443. case 'png' :
  1444. case 'tiff' :
  1445. $FrameRate = 1;
  1446. $PlaytimeSeconds = 1;
  1447. $BitrateCompressed = $ThisFileInfo['filesize'] * 8;
  1448. break;
  1449. default :
  1450. if (! empty($ThisFileInfo['video']['frame_rate']))
  1451. {
  1452. $FrameRate = $ThisFileInfo['video']['frame_rate'];
  1453. }
  1454. else
  1455. {
  1456. return false;
  1457. }
  1458. if (! empty($ThisFileInfo['playtime_seconds']))
  1459. {
  1460. $PlaytimeSeconds = $ThisFileInfo['playtime_seconds'];
  1461. }
  1462. else
  1463. {
  1464. return false;
  1465. }
  1466. if (! empty($ThisFileInfo['video']['bitrate']))
  1467. {
  1468. $BitrateCompressed = $ThisFileInfo['video']['bitrate'];
  1469. }
  1470. else
  1471. {
  1472. return false;
  1473. }
  1474. break;
  1475. }
  1476. $BitrateUncompressed = $ThisFileInfo['video']['resolution_x'] * $ThisFileInfo['video']['resolution_y'] * $ThisFileInfo['video']['bits_per_sample'] * $FrameRate;
  1477. $ThisFileInfo['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
  1478. return true;
  1479. }
  1480. }
  1481. if (! function_exists('CalculateCompressionRatioAudio'))
  1482. {
  1483. function CalculateCompressionRatioAudio(&$ThisFileInfo)
  1484. {
  1485. if (empty($ThisFileInfo['audio']['bitrate']) || empty($ThisFileInfo['audio']['channels']) || empty($ThisFileInfo['audio']['sample_rate']) || empty($ThisFileInfo['audio']['bits_per_sample']))
  1486. {
  1487. return false;
  1488. }
  1489. $ThisFileInfo['audio']['compression_ratio'] = $ThisFileInfo['audio']['bitrate'] / ($ThisFileInfo['audio']['channels'] * $ThisFileInfo['audio']['sample_rate'] * $ThisFileInfo['audio']['bits_per_sample']);
  1490. return true;
  1491. }
  1492. }
  1493. if (! function_exists('IsValidMIMEstring'))
  1494. {
  1495. function IsValidMIMEstring($mimestring)
  1496. {
  1497. if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1)))
  1498. {
  1499. return true;
  1500. }
  1501. return false;
  1502. }
  1503. }
  1504. if (! function_exists('IsWithinBitRange'))
  1505. {
  1506. function IsWithinBitRange($number, $maxbits, $signed = false)
  1507. {
  1508. if ($signed)
  1509. {
  1510. if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1)))
  1511. {
  1512. return true;
  1513. }
  1514. }
  1515. else
  1516. {
  1517. if (($number >= 0) && ($number <= pow(2, $maxbits)))
  1518. {
  1519. return true;
  1520. }
  1521. }
  1522. return false;
  1523. }
  1524. }
  1525. if (! function_exists('safe_parse_url'))
  1526. {
  1527. function safe_parse_url($url)
  1528. {
  1529. $parts = @parse_url($url);
  1530. $parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : '');
  1531. $parts['host'] = (isset($parts['host']) ? $parts['host'] : '');
  1532. $parts['user'] = (isset($parts['user']) ? $parts['user'] : '');
  1533. $parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : '');
  1534. $parts['path'] = (isset($parts['path']) ? $parts['path'] : '');
  1535. $parts['query'] = (isset($parts['query']) ? $parts['query'] : '');
  1536. return $parts;
  1537. }
  1538. }
  1539. if (! function_exists('IsValidURL'))
  1540. {
  1541. function IsValidURL($url, $allowUserPass = false)
  1542. {
  1543. if ($url == '')
  1544. {
  1545. return false;
  1546. }
  1547. if ($allowUserPass !== true)
  1548. {
  1549. if (strstr($url, '@'))
  1550. {
  1551. // in the format http://user:pass@example.com or http://user@example.com
  1552. // but could easily be somebody incorrectly entering an email address in place of a URL
  1553. return false;
  1554. }
  1555. }
  1556. if ($parts = safe_parse_url($url))
  1557. {
  1558. if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher'))
  1559. {
  1560. return false;
  1561. }
  1562. elseif (! eregi("^[[:alnum:]]([-.]?[0-9a-z])*\.[a-z]{2,3}$", $parts['host'], $regs) && ! IsValidDottedIP($parts['host']))
  1563. {
  1564. return false;
  1565. }
  1566. elseif (! eregi("^([[:alnum:]-]|[\_])*$", $parts['user'], $regs))
  1567. {
  1568. return false;
  1569. }
  1570. elseif (! eregi("^([[:alnum:]-]|[\_])*$", $parts['pass'], $regs))
  1571. {
  1572. return false;
  1573. }
  1574. elseif (! eregi("^[[:alnum:]/_\.@~-]*$", $parts['path'], $regs))
  1575. {
  1576. return false;
  1577. }
  1578. elseif (! eregi("^[[:alnum:]?&=+:;_()%#/,\.-]*$", $parts['query'], $regs))
  1579. {
  1580. return false;
  1581. }
  1582. else
  1583. {
  1584. return true;
  1585. }
  1586. }
  1587. return false;
  1588. }
  1589. }
  1590. echo '<FORM ACTION="' . $_SERVER['PHP_SELF'] . '" METHOD="POST">';
  1591. echo 'Enter 4 hex bytes of MPEG-audio header (ie <I>FF FA 92 44</I>)<BR>';
  1592. echo '<INPUT TYPE="TEXT" NAME="HeaderHexBytes" VALUE="' . (isset($_POST['HeaderHexBytes']) ? strtoupper($_POST['HeaderHexBytes']) : '') . '" SIZE="11" MAXLENGTH="11">';
  1593. echo '<INPUT TYPE="SUBMIT" NAME="Analyze" VALUE="Analyze"></FORM>';
  1594. echo '<HR>';
  1595. echo '<FORM ACTION="' . $_SERVER['PHP_SELF'] . '" METHOD="POST">';
  1596. echo 'Generate a MPEG-audio 4-byte header from these values:<BR>';
  1597. echo '<TABLE BORDER="0">';
  1598. $MPEGgenerateValues = array('version' => array('1', '2', '2.5'), 'layer' => array('I', 'II', 'III'),
  1599. 'protection' => array('Y', 'N'),
  1600. 'bitrate' => array('free', '8', '16', '24', '32', '40', '48', '56', '64', '80', '96', '112', '128', '144',
  1601. '160', '176', '192', '224', '256', '288', '320', '352', '384', '416', '448'),
  1602. 'frequency' => array('8000', '11025', '12000', '16000', '22050', '24000', '32000', '44100', '48000'),
  1603. 'padding' => array('Y', 'N'), 'private' => array('Y', 'N'),
  1604. 'channelmode' => array('stereo', 'joint stereo', 'dual channel', 'mono'),
  1605. 'modeextension' => array('none', 'IS', 'MS', 'IS+MS', '4-31', '8-31', '12-31', '16-31'),
  1606. 'copyright' => array('Y', 'N'), 'original' => array('Y', 'N'), 'emphasis' => array('none', '50/15ms',
  1607. 'CCIT J.17'));
  1608. foreach ($MPEGgenerateValues as $name => $dataarray)
  1609. {
  1610. echo '<TR><TH>' . $name . ':</TH><TD><SELECT NAME="' . $name . '">';
  1611. foreach ($dataarray as $key => $value)
  1612. {
  1613. echo '<OPTION' . ((isset($_POST["$name"]) && ($_POST["$name"] == $value)) ? ' SELECTED' : '') . '>' . $value . '</OPTION>';
  1614. }
  1615. echo '</SELECT></TD></TR>';
  1616. }
  1617. if (isset($_POST['bitrate']))
  1618. {
  1619. echo '<TR><TH>Frame Length:</TH><TD>' . (int) MPEGaudioFrameLength($_POST['bitrate'], $_POST['version'], $_POST['layer'], (($_POST['padding'] == 'Y') ? '1' : '0'), $_POST['frequency']) . '</TD></TR>';
  1620. }
  1621. echo '</TABLE>';
  1622. echo '<INPUT TYPE="SUBMIT" NAME="Generate" VALUE="Generate"></FORM>';
  1623. echo '<HR>';
  1624. if (isset($_POST['Analyze']) && $_POST['HeaderHexBytes'])
  1625. {
  1626. $headerbytearray = explode(' ', $_POST['HeaderHexBytes']);
  1627. if (count($headerbytearray) != 4)
  1628. {
  1629. die('Invalid byte pattern');
  1630. }
  1631. $headerstring = '';
  1632. foreach ($headerbytearray as $textbyte)
  1633. {
  1634. $headerstring .= chr(hexdec($textbyte));
  1635. }
  1636. $MP3fileInfo['error'] = '';
  1637. $MPEGheaderRawArray = MPEGaudioHeaderDecode(substr($headerstring, 0, 4));
  1638. if (MPEGaudioHeaderValid($MPEGheaderRawArray, true))
  1639. {
  1640. $MP3fileInfo['raw'] = $MPEGheaderRawArray;
  1641. $MP3fileInfo['version'] = MPEGaudioVersionLookup($MP3fileInfo['raw']['version']);
  1642. $MP3fileInfo['layer'] = MPEGaudioLayerLookup($MP3fileInfo['raw']['layer']);
  1643. $MP3fileInfo['protection'] = MPEGaudioCRCLookup($MP3fileInfo['raw']['protection']);
  1644. $MP3fileInfo['bitrate'] = MPEGaudioBitrateLookup($MP3fileInfo['version'], $MP3fileInfo['layer'], $MP3fileInfo['raw']['bitrate']);
  1645. $MP3fileInfo['frequency'] = MPEGaudioFrequencyLookup($MP3fileInfo['version'], $MP3fileInfo['raw']['sample_rate']);
  1646. $MP3fileInfo['padding'] = (bool) $MP3fileInfo['raw']['padding'];
  1647. $MP3fileInfo['private'] = (bool) $MP3fileInfo['raw']['private'];
  1648. $MP3fileInfo['channelmode'] = MPEGaudioChannelModeLookup($MP3fileInfo['raw']['channelmode']);
  1649. $MP3fileInfo['channels'] = (($MP3fileInfo['channelmode'] == 'mono') ? 1 : 2);
  1650. $MP3fileInfo['modeextension'] = MPEGaudioModeExtensionLookup($MP3fileInfo['layer'], $MP3fileInfo['raw']['modeextension']);
  1651. $MP3fileInfo['copyright'] = (bool) $MP3fileInfo['raw']['copyright'];
  1652. $MP3fileInfo['original'] = (bool) $MP3fileInfo['raw']['original'];
  1653. $MP3fileInfo['emphasis'] = MPEGaudioEmphasisLookup($MP3fileInfo['raw']['emphasis']);
  1654. if ($MP3fileInfo['protection'])
  1655. {
  1656. $MP3fileInfo['crc'] = BigEndian2Int(substr($headerstring, 4, 2));
  1657. }
  1658. if ($MP3fileInfo['frequency'] > 0)
  1659. {
  1660. $MP3fileInfo['framelength'] = MPEGaudioFrameLength($MP3fileInfo['bitrate'], $MP3fileInfo['version'], $MP3fileInfo['layer'], (int) $MP3fileInfo['padding'], $MP3fileInfo['frequency']);
  1661. }
  1662. if ($MP3fileInfo['bitrate'] != 'free')
  1663. {
  1664. $MP3fileInfo['bitrate'] *= 1000;
  1665. }
  1666. }
  1667. else
  1668. {
  1669. $MP3fileInfo['error'] .= "\n" . 'Invalid MPEG audio header';
  1670. }
  1671. if (! $MP3fileInfo['error'])
  1672. {
  1673. unset($MP3fileInfo['error']);
  1674. }
  1675. echo table_var_dump($MP3fileInfo);
  1676. }
  1677. elseif (isset($_POST['Generate']))
  1678. {
  1679. // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
  1680. $headerbitstream = '11111111111'; // A - Frame sync (all bits set)
  1681. $MPEGversionLookup = array('2.5' => '00', '2' => '10', '1' => '11');
  1682. $headerbitstream .= $MPEGversionLookup[$_POST['version']]; // B - MPEG Audio version ID
  1683. $MPEGlayerLookup = array('III' => '01', 'II' => '10', 'I' => '11');
  1684. $headerbitstream .= $MPEGlayerLookup[$_POST['layer']]; // C - Layer description
  1685. $headerbitstream .= (($_POST['protection'] == 'Y') ? '0' : '1'); // D - Protection bit
  1686. $MPEGaudioBitrateLookup['1']['I'] = array('free' => '0000', '32' => '0001', '64' => '0010', '96' => '0011',
  1687. '128' => '0100', '160' => '0101', '192' => '0110', '224' => '0111', '256' => '1000', '288' => '1001',
  1688. '320' => '1010', '352' => '1011', '384' => '1100', '416' => '1101', '448' => '1110');
  1689. $MPEGaudioBitrateLookup['1']['II'] = array('free' => '0000', '32' => '0001', '48' => '0010', '56' => '0011',
  1690. '64' => '0100', '80' => '0101', '96' => '0110', '112' => '0111', '128' => '1000', '160' => '1001',
  1691. '192' => '1010', '224' => '1011', '256' => '1100', '320' => '1101', '384' => '1110');
  1692. $MPEGaudioBitrateLookup['1']['III'] = array('free' => '0000', '32' => '0001', '40' => '0010', '48' => '0011',
  1693. '56' => '0100', '64' => '0101', '80' => '0110', '96' => '0111', '112' => '1000', '128' => '1001',
  1694. '160' => '1010', '192' => '1011', '224' => '1100', '256' => '1101', '320' => '1110');
  1695. $MPEGaudioBitrateLookup['2']['I'] = array('free' => '0000', '32' => '0001', '48' => '0010', '56' => '0011',
  1696. '64' => '0100', '80' => '0101', '96' => '0110', '112' => '0111', '128' => '1000', '144' => '1001',
  1697. '160' => '1010', '176' => '1011', '192' => '1100', '224' => '1101', '256' => '1110');
  1698. $MPEGaudioBitrateLookup['2']['II'] = array('free' => '0000', '8' => '0001', '16' => '0010', '24' => '0011',
  1699. '32' => '0100', '40' => '0101', '48' => '0110', '56' => '0111', '64' => '1000', '80' => '1001', '96' => '1010',
  1700. '112' => '1011', '128' => '1100', '144' => '1101', '160' => '1110');
  1701. $MPEGaudioBitrateLookup['2']['III'] = $MPEGaudioBitrateLookup['2']['II'];
  1702. $MPEGaudioBitrateLookup['2.5']['I'] = $MPEGaudioBitrateLookup['2']['I'];
  1703. $MPEGaudioBitrateLookup['2.5']['II'] = $MPEGaudioBitrateLookup['2']['II'];
  1704. $MPEGaudioBitrateLookup['2.5']['III'] = $MPEGaudioBitrateLookup['2']['II'];
  1705. if (isset($MPEGaudioBitrateLookup[$_POST['version']][$_POST['layer']][$_POST['bitrate']]))
  1706. {
  1707. $headerbitstream .= $MPEGaudioBitrateLookup[$_POST['version']][$_POST['layer']][$_POST['bitrate']]; // E - Bitrate index
  1708. }
  1709. else
  1710. {
  1711. die('Invalid <B>Bitrate</B>');
  1712. }
  1713. $MPEGaudioFrequencyLookup['1'] = array('44100' => '00', '48000' => '01', '32000' => '10');
  1714. $MPEGaudioFrequencyLookup['2'] = array('22050' => '00', '24000' => '01', '16000' => '10');
  1715. $MPEGaudioFrequencyLookup['2.5'] = array('11025' => '00', '12000' => '01', '8000' => '10');
  1716. if (isset($MPEGaudioFrequencyLookup[$_POST['version']][$_POST['frequency']]))
  1717. {
  1718. $headerbitstream .= $MPEGaudioFrequencyLookup[$_POST['version']][$_POST['frequency']]; // F - Sampling rate frequency index
  1719. }
  1720. else
  1721. {
  1722. die('Invalid <B>Frequency</B>');
  1723. }
  1724. $headerbitstream .= (($_POST['padding'] == 'Y') ? '1' : '0'); // G - Padding bit
  1725. $headerbitstream .= (($_POST['private'] == 'Y') ? '1' : '0'); // H - Private bit
  1726. $MPEGaudioChannelModeLookup = array('stereo' => '00', 'joint stereo' => '01', 'dual channel' => '10', 'mono' => '11');
  1727. $headerbitstream .= $MPEGaudioChannelModeLookup[$_POST['channelmode']]; // I - Channel Mode
  1728. $MPEGaudioModeExtensionLookup['I'] = array('4-31' => '00', '8-31' => '01', '12-31' => '10', '16-31' => '11');
  1729. $MPEGaudioModeExtensionLookup['II'] = $MPEGaudioModeExtensionLookup['I'];
  1730. $MPEGaudioModeExtensionLookup['III'] = array('none' => '00', 'IS' => '01', 'MS' => '10', 'IS+MS' => '11');
  1731. if ($_POST['channelmode'] != 'joint stereo')
  1732. {
  1733. $headerbitstream .= '00';
  1734. }
  1735. elseif (isset($MPEGaudioModeExtensionLookup[$_POST['layer']][$_POST['modeextension']]))
  1736. {
  1737. $headerbitstream .= $MPEGaudioModeExtensionLookup[$_POST['layer']][$_POST['modeextension']]; // J - Mode extension (Only if Joint stereo)
  1738. }
  1739. else
  1740. {
  1741. die('Invalid <B>Mode Extension</B>');
  1742. }
  1743. $headerbitstream .= (($_POST['copyright'] == 'Y') ? '1' : '0'); // K - Copyright
  1744. $headerbitstream .= (($_POST['original'] == 'Y') ? '1' : '0'); // L - Original
  1745. $MPEGaudioEmphasisLookup = array('none' => '00', '50/15ms' => '01', 'CCIT J.17' => '11');
  1746. if (isset($MPEGaudioEmphasisLookup[$_POST['emphasis']]))
  1747. {
  1748. $headerbitstream .= $MPEGaudioEmphasisLookup[$_POST['emphasis']]; // M - Emphasis
  1749. }
  1750. else
  1751. {
  1752. die('Invalid <B>Emphasis</B>');
  1753. }
  1754. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 0, 8))), 2, '0', STR_PAD_LEFT)) . ' ';
  1755. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 8, 8))), 2, '0', STR_PAD_LEFT)) . ' ';
  1756. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 16, 8))), 2, '0', STR_PAD_LEFT)) . ' ';
  1757. echo strtoupper(str_pad(dechex(bindec(substr($headerbitstream, 24, 8))), 2, '0', STR_PAD_LEFT)) . '<BR>';
  1758. }
  1759. function MPEGaudioVersionLookup($rawversion)
  1760. {
  1761. $MPEGaudioVersionLookup = array('2.5', FALSE, '2', '1');
  1762. return (isset($MPEGaudioVersionLookup["$rawversion"]) ? $MPEGaudioVersionLookup["$rawversion"] : FALSE);
  1763. }
  1764. function MPEGaudioLayerLookup($rawlayer)
  1765. {
  1766. $MPEGaudioLayerLookup = array(FALSE, 'III', 'II', 'I');
  1767. return (isset($MPEGaudioLayerLookup["$rawlayer"]) ? $MPEGaudioLayerLookup["$rawlayer"] : FALSE);
  1768. }
  1769. function MPEGaudioBitrateLookup($version, $layer, $rawbitrate)
  1770. {
  1771. static $MPEGaudioBitrateLookup;
  1772. if (empty($MPEGaudioBitrateLookup))
  1773. {
  1774. $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
  1775. }
  1776. return (isset($MPEGaudioBitrateLookup["$version"]["$layer"]["$rawbitrate"]) ? $MPEGaudioBitrateLookup["$version"]["$layer"]["$rawbitrate"] : FALSE);
  1777. }
  1778. function MPEGaudioFrequencyLookup($version, $rawfrequency)
  1779. {
  1780. static $MPEGaudioFrequencyLookup;
  1781. if (empty($MPEGaudioFrequencyLookup))
  1782. {
  1783. $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
  1784. }
  1785. return (isset($MPEGaudioFrequencyLookup["$version"]["$rawfrequency"]) ? $MPEGaudioFrequencyLookup["$version"]["$rawfrequency"] : FALSE);
  1786. }
  1787. function MPEGaudioChannelModeLookup($rawchannelmode)
  1788. {
  1789. $MPEGaudioChannelModeLookup = array('stereo', 'joint stereo', 'dual channel', 'mono');
  1790. return (isset($MPEGaudioChannelModeLookup["$rawchannelmode"]) ? $MPEGaudioChannelModeLookup["$rawchannelmode"] : FALSE);
  1791. }
  1792. function MPEGaudioModeExtensionLookup($layer, $rawmodeextension)
  1793. {
  1794. $MPEGaudioModeExtensionLookup['I'] = array('4-31', '8-31', '12-31', '16-31');
  1795. $MPEGaudioModeExtensionLookup['II'] = array('4-31', '8-31', '12-31', '16-31');
  1796. $MPEGaudioModeExtensionLookup['III'] = array('', 'IS', 'MS', 'IS+MS');
  1797. return (isset($MPEGaudioModeExtensionLookup["$layer"]["$rawmodeextension"]) ? $MPEGaudioModeExtensionLookup["$layer"]["$rawmodeextension"] : FALSE);
  1798. }
  1799. function MPEGaudioEmphasisLookup($rawemphasis)
  1800. {
  1801. $MPEGaudioEmphasisLookup = array('none', '50/15ms', FALSE, 'CCIT J.17');
  1802. return (isset($MPEGaudioEmphasisLookup["$rawemphasis"]) ? $MPEGaudioEmphasisLookup["$rawemphasis"] : FALSE);
  1803. }
  1804. function MPEGaudioCRCLookup($CRCbit)
  1805. {
  1806. // inverse boolean cast :)
  1807. if ($CRCbit == '0')
  1808. {
  1809. return TRUE;
  1810. }
  1811. else
  1812. {
  1813. return FALSE;
  1814. }
  1815. }
  1816. /////////////////////////////////////////////////////////////////
  1817. /// getID3() by James Heinrich <info@getid3.org> //
  1818. // available at http://getid3.sourceforge.net ///
  1819. // or http://www.getid3.org ///
  1820. /////////////////////////////////////////////////////////////////
  1821. // //
  1822. // getid3.mp3.php - part of getID3() //
  1823. // See getid3.readme.txt for more details //
  1824. // //
  1825. /////////////////////////////////////////////////////////////////
  1826. // number of frames to scan to determine if MPEG-audio sequence is valid
  1827. // Lower this number to 5-20 for faster scanning
  1828. // Increase this number to 50+ for most accurate detection of valid VBR/CBR
  1829. // mpeg-audio streams
  1830. define('MPEG_VALID_CHECK_FRAMES', 35);
  1831. function getMP3headerFilepointer(&$fd, &$ThisFileInfo)
  1832. {
  1833. getOnlyMPEGaudioInfo($fd, $ThisFileInfo, $ThisFileInfo['avdataoffset']);
  1834. if (isset($ThisFileInfo['mpeg']['audio']['bitrate_mode']))
  1835. {
  1836. $ThisFileInfo['audio']['bitrate_mode'] = strtolower($ThisFileInfo['mpeg']['audio']['bitrate_mode']);
  1837. }
  1838. if (((isset($ThisFileInfo['id3v2']) && ($ThisFileInfo['avdataoffset'] > $ThisFileInfo['id3v2']['headerlength'])) || (! isset($ThisFileInfo['id3v2']) && ($ThisFileInfo['avdataoffset'] > 0))))
  1839. {
  1840. $ThisFileInfo['warning'] .= "\n" . 'Unknown data before synch ';
  1841. if (isset($ThisFileInfo['id3v2']['headerlength']))
  1842. {
  1843. $ThisFileInfo['warning'] .= '(ID3v2 header ends at ' . $ThisFileInfo['id3v2']['headerlength'] . ', then ' . ($ThisFileInfo['avdataoffset'] - $ThisFileInfo['id3v2']['headerlength']) . ' bytes garbage, ';
  1844. }
  1845. else
  1846. {
  1847. $ThisFileInfo['warning'] .= '(should be at beginning of file, ';
  1848. }
  1849. $ThisFileInfo['warning'] .= 'synch detected at ' . $ThisFileInfo['avdataoffset'] . ')';
  1850. if ($ThisFileInfo['audio']['bitrate_mode'] == 'cbr')
  1851. {
  1852. if (! empty($ThisFileInfo['id3v2']['headerlength']) && (($ThisFileInfo['avdataoffset'] - $ThisFileInfo['id3v2']['headerlength']) == $ThisFileInfo['mpeg']['audio']['framelength']))
  1853. {
  1854. $ThisFileInfo['warning'] .= '. This is a known problem with some versions of LAME (3.91, 3.92) DLL in CBR mode.';
  1855. $ThisFileInfo['audio']['codec'] = 'LAME';
  1856. }
  1857. elseif (empty($ThisFileInfo['id3v2']['headerlength']) && ($ThisFileInfo['avdataoffset'] == $ThisFileInfo['mpeg']['audio']['framelength']))
  1858. {
  1859. $ThisFileInfo['warning'] .= '. This is a known problem with some versions of LAME (3.91, 3.92) DLL in CBR mode.';
  1860. $ThisFileInfo['audio']['codec'] = 'LAME';
  1861. }
  1862. }
  1863. }
  1864. if (isset($ThisFileInfo['mpeg']['audio']['layer']) && ($ThisFileInfo['mpeg']['audio']['layer'] == 'II'))
  1865. {
  1866. $ThisFileInfo['audio']['dataformat'] = 'mp2';
  1867. }
  1868. elseif (isset($ThisFileInfo['mpeg']['audio']['layer']) && ($ThisFileInfo['mpeg']['audio']['layer'] == 'I'))
  1869. {
  1870. $ThisFileInfo['audio']['dataformat'] = 'mp1';
  1871. }
  1872. if ($ThisFileInfo['fileformat'] == 'mp3')
  1873. {
  1874. switch ($ThisFileInfo['audio']['dataformat'])
  1875. {
  1876. case 'mp1' :
  1877. case 'mp2' :
  1878. case 'mp3' :
  1879. $ThisFileInfo['fileformat'] = $ThisFileInfo['audio']['dataformat'];
  1880. break;
  1881. default :
  1882. $ThisFileInfo['warning'] .= "\n" . 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "' . $ThisFileInfo['audio']['dataformat'] . '"';
  1883. break;
  1884. }
  1885. }
  1886. if (empty($ThisFileInfo['fileformat']))
  1887. {
  1888. $ThisFileInfo['error'] .= "\n" . 'Synch not found';
  1889. unset($ThisFileInfo['fileformat']);
  1890. unset($ThisFileInfo['audio']['bitrate_mode']);
  1891. unset($ThisFileInfo['avdataoffset']);
  1892. unset($ThisFileInfo['avdataend']);
  1893. return false;
  1894. }
  1895. $ThisFileInfo['mime_type'] = 'audio/mpeg';
  1896. $ThisFileInfo['audio']['lossless'] = false;
  1897. // Calculate playtime
  1898. if (! isset($ThisFileInfo['playtime_seconds']) && isset($ThisFileInfo['audio']['bitrate']) && ($ThisFileInfo['audio']['bitrate'] > 0))
  1899. {
  1900. $ThisFileInfo['playtime_seconds'] = ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8 / $ThisFileInfo['audio']['bitrate'];
  1901. }
  1902. if (isset($ThisFileInfo['mpeg']['audio']['LAME']))
  1903. {
  1904. $ThisFileInfo['audio']['codec'] = 'LAME';
  1905. if (! empty($ThisFileInfo['mpeg']['audio']['LAME']['long_version']))
  1906. {
  1907. $ThisFileInfo['audio']['encoder'] = trim($ThisFileInfo['mpeg']['audio']['LAME']['long_version']);
  1908. }
  1909. }
  1910. return true;
  1911. }
  1912. function decodeMPEGaudioHeader($fd, $offset, &$ThisFileInfo, $recursivesearch = true, $ScanAsCBR = false, $FastMPEGheaderScan = false)
  1913. {
  1914. static $MPEGaudioVersionLookup;
  1915. static $MPEGaudioLayerLookup;
  1916. static $MPEGaudioBitrateLookup;
  1917. static $MPEGaudioFrequencyLookup;
  1918. static $MPEGaudioChannelModeLookup;
  1919. static $MPEGaudioModeExtensionLookup;
  1920. static $MPEGaudioEmphasisLookup;
  1921. if (empty($MPEGaudioVersionLookup))
  1922. {
  1923. $MPEGaudioVersionLookup = MPEGaudioVersionArray();
  1924. $MPEGaudioLayerLookup = MPEGaudioLayerArray();
  1925. $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
  1926. $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
  1927. $MPEGaudioChannelModeLookup = MPEGaudioChannelModeArray();
  1928. $MPEGaudioModeExtensionLookup = MPEGaudioModeExtensionArray();
  1929. $MPEGaudioEmphasisLookup = MPEGaudioEmphasisArray();
  1930. }
  1931. if ($offset >= $ThisFileInfo['avdataend'])
  1932. {
  1933. $ThisFileInfo['error'] .= "\n" . 'end of file encounter looking for MPEG synch';
  1934. return false;
  1935. }
  1936. fseek($fd, $offset, SEEK_SET);
  1937. $headerstring = fread($fd, 1441); // worse-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
  1938. // MP3 audio frame structure:
  1939. // $aa $aa $aa $aa [$bb $bb] $cc...
  1940. // where $aa..$aa is the four-byte mpeg-audio header (below)
  1941. // $bb $bb is the optional 2-byte CRC
  1942. // and $cc... is the audio data
  1943. $head4 = substr($headerstring, 0, 4);
  1944. static $MPEGaudioHeaderDecodeCache = array();
  1945. if (isset($MPEGaudioHeaderDecodeCache[$head4]))
  1946. {
  1947. $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
  1948. }
  1949. else
  1950. {
  1951. $MPEGheaderRawArray = MPEGaudioHeaderDecode($head4);
  1952. $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
  1953. }
  1954. static $MPEGaudioHeaderValidCache = array();
  1955. // Not in cache
  1956. if (! isset($MPEGaudioHeaderValidCache[$head4]))
  1957. {
  1958. $MPEGaudioHeaderValidCache[$head4] = MPEGaudioHeaderValid($MPEGheaderRawArray);
  1959. }
  1960. if ($MPEGaudioHeaderValidCache[$head4])
  1961. {
  1962. $ThisFileInfo['mpeg']['audio']['raw'] = $MPEGheaderRawArray;
  1963. }
  1964. else
  1965. {
  1966. $ThisFileInfo['error'] .= "\n" . 'Invalid MPEG audio header at offset ' . $offset;
  1967. return false;
  1968. }
  1969. if (! $FastMPEGheaderScan)
  1970. {
  1971. $ThisFileInfo['mpeg']['audio']['version'] = $MPEGaudioVersionLookup[$ThisFileInfo['mpeg']['audio']['raw']['version']];
  1972. $ThisFileInfo['mpeg']['audio']['layer'] = $MPEGaudioLayerLookup[$ThisFileInfo['mpeg']['audio']['raw']['layer']];
  1973. $ThisFileInfo['mpeg']['audio']['channelmode'] = $MPEGaudioChannelModeLookup[$ThisFileInfo['mpeg']['audio']['raw']['channelmode']];
  1974. $ThisFileInfo['mpeg']['audio']['channels'] = (($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') ? 1 : 2);
  1975. $ThisFileInfo['mpeg']['audio']['sample_rate'] = $MPEGaudioFrequencyLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['raw']['sample_rate']];
  1976. $ThisFileInfo['mpeg']['audio']['protection'] = ! $ThisFileInfo['mpeg']['audio']['raw']['protection'];
  1977. $ThisFileInfo['mpeg']['audio']['private'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['private'];
  1978. $ThisFileInfo['mpeg']['audio']['modeextension'] = $MPEGaudioModeExtensionLookup[$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['modeextension']];
  1979. $ThisFileInfo['mpeg']['audio']['copyright'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['copyright'];
  1980. $ThisFileInfo['mpeg']['audio']['original'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['original'];
  1981. $ThisFileInfo['mpeg']['audio']['emphasis'] = $MPEGaudioEmphasisLookup[$ThisFileInfo['mpeg']['audio']['raw']['emphasis']];
  1982. $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
  1983. $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
  1984. if ($ThisFileInfo['mpeg']['audio']['protection'])
  1985. {
  1986. $ThisFileInfo['mpeg']['audio']['crc'] = BigEndian2Int(substr($headerstring, 4, 2));
  1987. }
  1988. }
  1989. if ($ThisFileInfo['mpeg']['audio']['raw']['bitrate'] == 15)
  1990. {
  1991. // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
  1992. $ThisFileInfo['warning'] .= "\n" . 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';
  1993. $ThisFileInfo['mpeg']['audio']['raw']['bitrate'] = 0;
  1994. }
  1995. $ThisFileInfo['mpeg']['audio']['padding'] = (bool) $ThisFileInfo['mpeg']['audio']['raw']['padding'];
  1996. $ThisFileInfo['mpeg']['audio']['bitrate'] = $MPEGaudioBitrateLookup[$ThisFileInfo['mpeg']['audio']['version']][$ThisFileInfo['mpeg']['audio']['layer']][$ThisFileInfo['mpeg']['audio']['raw']['bitrate']];
  1997. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') && ($offset == $ThisFileInfo['avdataoffset']))
  1998. {
  1999. // only skip multiple frame check if free-format bitstream found at beginning of file
  2000. // otherwise is quite possibly simply corrupted data
  2001. $recursivesearch = false;
  2002. }
  2003. // For Layer II there are some combinations of bitrate and mode which are not allowed.
  2004. if (! $FastMPEGheaderScan && ($ThisFileInfo['mpeg']['audio']['layer'] == 'II'))
  2005. {
  2006. $ThisFileInfo['audio']['dataformat'] = 'mp2';
  2007. switch ($ThisFileInfo['mpeg']['audio']['channelmode'])
  2008. {
  2009. case 'mono' :
  2010. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') || ($ThisFileInfo['mpeg']['audio']['bitrate'] <= 192))
  2011. {
  2012. // these are ok
  2013. }
  2014. else
  2015. {
  2016. $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
  2017. return false;
  2018. }
  2019. break;
  2020. case 'stereo' :
  2021. case 'joint stereo' :
  2022. case 'dual channel' :
  2023. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') || ($ThisFileInfo['mpeg']['audio']['bitrate'] == 64) || ($ThisFileInfo['mpeg']['audio']['bitrate'] >= 96))
  2024. {
  2025. // these are ok
  2026. }
  2027. else
  2028. {
  2029. $ThisFileInfo['error'] .= "\n" . $ThisFileInfo['mpeg']['audio']['bitrate'] . 'kbps not allowed in Layer II, ' . $ThisFileInfo['mpeg']['audio']['channelmode'] . '.';
  2030. return false;
  2031. }
  2032. break;
  2033. }
  2034. }
  2035. if ($ThisFileInfo['audio']['sample_rate'] > 0)
  2036. {
  2037. $ThisFileInfo['mpeg']['audio']['framelength'] = MPEGaudioFrameLength($ThisFileInfo['mpeg']['audio']['bitrate'], $ThisFileInfo['mpeg']['audio']['version'], $ThisFileInfo['mpeg']['audio']['layer'], (int) $ThisFileInfo['mpeg']['audio']['padding'], $ThisFileInfo['audio']['sample_rate']);
  2038. }
  2039. if ($ThisFileInfo['mpeg']['audio']['bitrate'] != 'free')
  2040. {
  2041. $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['bitrate'];
  2042. if (isset($ThisFileInfo['mpeg']['audio']['framelength']))
  2043. {
  2044. $nextframetestoffset = $offset + $ThisFileInfo['mpeg']['audio']['framelength'];
  2045. }
  2046. else
  2047. {
  2048. $ThisFileInfo['error'] .= "\n" . 'Frame at offset(' . $offset . ') is has an invalid frame length.';
  2049. return false;
  2050. }
  2051. }
  2052. $ExpectedNumberOfAudioBytes = 0;
  2053. ////////////////////////////////////////////////////////////////////////////////////
  2054. // Variable-bitrate headers
  2055. if (substr($headerstring, 4 + 32, 4) == 'VBRI')
  2056. {
  2057. // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
  2058. // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
  2059. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
  2060. $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Fraunhofer';
  2061. $ThisFileInfo['audio']['codec'] = 'Fraunhofer';
  2062. $SideInfoData = substr($headerstring, 4 + 2, 32);
  2063. $FraunhoferVBROffset = 36;
  2064. $ThisFileInfo['mpeg']['audio']['VBR_encoder_version'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 4, 2));
  2065. $ThisFileInfo['mpeg']['audio']['VBR_encoder_delay'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 6, 2));
  2066. $ThisFileInfo['mpeg']['audio']['VBR_quality'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 8, 2));
  2067. $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4));
  2068. $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4));
  2069. $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2));
  2070. //$ThisFileInfo['mpeg']['audio']['reserved'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 4)); // hardcoded $00 $01 $00 $02 - purpose unknown
  2071. $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets_stride'] = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2));
  2072. $ExpectedNumberOfAudioBytes = $ThisFileInfo['mpeg']['audio']['VBR_bytes'];
  2073. $previousbyteoffset = $offset;
  2074. for($i = 0; $i < $ThisFileInfo['mpeg']['audio']['VBR_seek_offsets']; $i ++)
  2075. {
  2076. $Fraunhofer_OffsetN = BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, 2));
  2077. $FraunhoferVBROffset += 2;
  2078. $ThisFileInfo['mpeg']['audio']['VBR_offsets_relative'][$i] = $Fraunhofer_OffsetN;
  2079. $ThisFileInfo['mpeg']['audio']['VBR_offsets_absolute'][$i] = $Fraunhofer_OffsetN + $previousbyteoffset;
  2080. $previousbyteoffset += $Fraunhofer_OffsetN;
  2081. }
  2082. }
  2083. else
  2084. {
  2085. // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
  2086. // depending on MPEG layer and number of channels
  2087. if ($ThisFileInfo['mpeg']['audio']['version'] == '1')
  2088. {
  2089. if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono')
  2090. {
  2091. // MPEG-1 (mono)
  2092. $VBRidOffset = 4 + 17; // 0x15
  2093. $SideInfoData = substr($headerstring, 4 + 2, 17);
  2094. }
  2095. else
  2096. {
  2097. // MPEG-1 (stereo, joint-stereo, dual-channel)
  2098. $VBRidOffset = 4 + 32; // 0x24
  2099. $SideInfoData = substr($headerstring, 4 + 2, 32);
  2100. }
  2101. }
  2102. else
  2103. { // 2 or 2.5
  2104. if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono')
  2105. {
  2106. // MPEG-2, MPEG-2.5 (mono)
  2107. $VBRidOffset = 4 + 9; // 0x0D
  2108. $SideInfoData = substr($headerstring, 4 + 2, 9);
  2109. }
  2110. else
  2111. {
  2112. // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
  2113. $VBRidOffset = 4 + 17; // 0x15
  2114. $SideInfoData = substr($headerstring, 4 + 2, 17);
  2115. }
  2116. }
  2117. if ((substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing') || (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info'))
  2118. {
  2119. // 'Xing' is traditional Xing VBR frame
  2120. // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
  2121. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
  2122. $ThisFileInfo['mpeg']['audio']['VBR_method'] = 'Xing';
  2123. $ThisFileInfo['mpeg']['audio']['xing_flags_raw'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4));
  2124. $ThisFileInfo['mpeg']['audio']['xing_flags']['frames'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x00000001);
  2125. $ThisFileInfo['mpeg']['audio']['xing_flags']['bytes'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x00000002);
  2126. $ThisFileInfo['mpeg']['audio']['xing_flags']['toc'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x00000004);
  2127. $ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale'] = (bool) ($ThisFileInfo['mpeg']['audio']['xing_flags_raw'] & 0x00000008);
  2128. if ($ThisFileInfo['mpeg']['audio']['xing_flags']['frames'])
  2129. {
  2130. $ThisFileInfo['mpeg']['audio']['VBR_frames'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 8, 4));
  2131. }
  2132. if ($ThisFileInfo['mpeg']['audio']['xing_flags']['bytes'])
  2133. {
  2134. $ThisFileInfo['mpeg']['audio']['VBR_bytes'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4));
  2135. }
  2136. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') && ! empty($ThisFileInfo['mpeg']['audio']['VBR_frames']) && ! empty($ThisFileInfo['mpeg']['audio']['VBR_bytes']))
  2137. {
  2138. $framelengthfloat = $ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames'];
  2139. if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I')
  2140. {
  2141. // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
  2142. $ThisFileInfo['audio']['bitrate'] = ((($framelengthfloat / 4) - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate']) / 12;
  2143. }
  2144. else
  2145. {
  2146. // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
  2147. $ThisFileInfo['audio']['bitrate'] = (($framelengthfloat - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate']) / 144;
  2148. }
  2149. $ThisFileInfo['mpeg']['audio']['framelength'] = floor($framelengthfloat);
  2150. }
  2151. if ($ThisFileInfo['mpeg']['audio']['xing_flags']['toc'])
  2152. {
  2153. $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
  2154. for($i = 0; $i < 100; $i ++)
  2155. {
  2156. $ThisFileInfo['mpeg']['audio']['toc'][$i] = ord($LAMEtocData{$i});
  2157. }
  2158. }
  2159. if ($ThisFileInfo['mpeg']['audio']['xing_flags']['vbr_scale'])
  2160. {
  2161. $ThisFileInfo['mpeg']['audio']['VBR_scale'] = BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4));
  2162. }
  2163. // http://gabriel.mp3-tech.org/mp3infotag.html
  2164. if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME')
  2165. {
  2166. $ThisFileInfo['mpeg']['audio']['LAME']['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
  2167. $ThisFileInfo['mpeg']['audio']['LAME']['short_version'] = substr($ThisFileInfo['mpeg']['audio']['LAME']['long_version'], 0, 9);
  2168. $ThisFileInfo['mpeg']['audio']['LAME']['long_version'] = rtrim($ThisFileInfo['mpeg']['audio']['LAME']['long_version'], "\x55\xAA");
  2169. if ($ThisFileInfo['mpeg']['audio']['LAME']['short_version'] >= 'LAME3.90.')
  2170. {
  2171. // It the LAME tag was only introduced in LAME v3.90
  2172. // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
  2173. // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
  2174. // are assuming a 'Xing' identifier offset of 0x24, which is the case for
  2175. // MPEG-1 non-mono, but not for other combinations
  2176. $LAMEtagOffsetContant = $VBRidOffset - 0x24;
  2177. // byte $9B VBR Quality
  2178. // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
  2179. // Actually overwrites original Xing bytes
  2180. unset($ThisFileInfo['mpeg']['audio']['VBR_scale']);
  2181. $ThisFileInfo['mpeg']['audio']['LAME']['vbr_quality'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
  2182. // bytes $9C-$A4 Encoder short VersionString
  2183. $ThisFileInfo['mpeg']['audio']['LAME']['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
  2184. $ThisFileInfo['mpeg']['audio']['LAME']['long_version'] = $ThisFileInfo['mpeg']['audio']['LAME']['short_version'];
  2185. // byte $A5 Info Tag revision + VBR method
  2186. $LAMEtagRevisionVBRmethod = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
  2187. $ThisFileInfo['mpeg']['audio']['LAME']['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
  2188. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F;
  2189. $ThisFileInfo['mpeg']['audio']['LAME']['vbr_method'] = LAMEvbrMethodLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method']);
  2190. // byte $A6 Lowpass filter value
  2191. $ThisFileInfo['mpeg']['audio']['LAME']['lowpass_frequency'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
  2192. // bytes $A7-$AE Replay Gain
  2193. // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
  2194. // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
  2195. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] = BigEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
  2196. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
  2197. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
  2198. if ($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] == 0)
  2199. {
  2200. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] = false;
  2201. }
  2202. if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] != 0)
  2203. {
  2204. require_once (GETID3_INCLUDEPATH . 'getid3.rgad.php');
  2205. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['name'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0xE000) >> 13;
  2206. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['originator'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0x1C00) >> 10;
  2207. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['sign_bit'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0x0200) >> 9;
  2208. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['gain_adjust'] = $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_radio'] & 0x01FF;
  2209. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['name'] = RGADnameLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['name']);
  2210. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['originator'] = RGADoriginatorLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['originator']);
  2211. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['gain_db'] = RGADadjustmentLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['gain_adjust'], $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['raw']['sign_bit']);
  2212. if ($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] !== false)
  2213. {
  2214. $ThisFileInfo['replay_gain']['radio']['peak'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'];
  2215. }
  2216. $ThisFileInfo['replay_gain']['radio']['originator'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['originator'];
  2217. $ThisFileInfo['replay_gain']['radio']['adjustment'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['radio']['gain_db'];
  2218. }
  2219. if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] != 0)
  2220. {
  2221. require_once (GETID3_INCLUDEPATH . 'getid3.rgad.php');
  2222. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['name'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0xE000) >> 13;
  2223. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['originator'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0x1C00) >> 10;
  2224. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['sign_bit'] = ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0x0200) >> 9;
  2225. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['gain_adjust'] = $ThisFileInfo['mpeg']['audio']['LAME']['raw']['RGAD_audiophile'] & 0x01FF;
  2226. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['name'] = RGADnameLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['name']);
  2227. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['originator'] = RGADoriginatorLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['originator']);
  2228. $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['gain_db'] = RGADadjustmentLookup($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['gain_adjust'], $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['raw']['sign_bit']);
  2229. if ($ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'] !== false)
  2230. {
  2231. $ThisFileInfo['replay_gain']['audiophile']['peak'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['peak_amplitude'];
  2232. }
  2233. $ThisFileInfo['replay_gain']['audiophile']['originator'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['originator'];
  2234. $ThisFileInfo['replay_gain']['audiophile']['adjustment'] = $ThisFileInfo['mpeg']['audio']['LAME']['RGAD']['audiophile']['gain_db'];
  2235. }
  2236. // byte $AF Encoding flags + ATH Type
  2237. $EncodingFlagsATHtype = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
  2238. $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);
  2239. $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
  2240. $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);
  2241. $ThisFileInfo['mpeg']['audio']['LAME']['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);
  2242. $ThisFileInfo['mpeg']['audio']['LAME']['ath_type'] = $EncodingFlagsATHtype & 0x0F;
  2243. // byte $B0 if ABR {specified bitrate} else {minimal bitrate}
  2244. $ABRbitrateMinBitrate = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
  2245. if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method'] == 2)
  2246. { // Average BitRate (ABR)
  2247. $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_abr'] = $ABRbitrateMinBitrate;
  2248. }
  2249. elseif ($ABRbitrateMinBitrate > 0)
  2250. { // Variable BitRate (VBR) - minimum bitrate
  2251. $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] = $ABRbitrateMinBitrate;
  2252. }
  2253. // bytes $B1-$B3 Encoder delays
  2254. $EncoderDelays = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
  2255. $ThisFileInfo['mpeg']['audio']['LAME']['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
  2256. $ThisFileInfo['mpeg']['audio']['LAME']['end_padding'] = $EncoderDelays & 0x000FFF;
  2257. // byte $B4 Misc
  2258. $MiscByte = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
  2259. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['noise_shaping'] = ($MiscByte & 0x03);
  2260. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['stereo_mode'] = ($MiscByte & 0x1C) >> 2;
  2261. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
  2262. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['source_sample_freq'] = ($MiscByte & 0xC0) >> 6;
  2263. $ThisFileInfo['mpeg']['audio']['LAME']['noise_shaping'] = $ThisFileInfo['mpeg']['audio']['LAME']['raw']['noise_shaping'];
  2264. $ThisFileInfo['mpeg']['audio']['LAME']['stereo_mode'] = LAMEmiscStereoModeLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['stereo_mode']);
  2265. $ThisFileInfo['mpeg']['audio']['LAME']['not_optimal_quality'] = (bool) $ThisFileInfo['mpeg']['audio']['LAME']['raw']['not_optimal_quality'];
  2266. $ThisFileInfo['mpeg']['audio']['LAME']['source_sample_freq'] = LAMEmiscSourceSampleFrequencyLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['source_sample_freq']);
  2267. // byte $B5 MP3 Gain
  2268. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['mp3_gain'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
  2269. $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] = 1.5 * $ThisFileInfo['mpeg']['audio']['LAME']['raw']['mp3_gain'];
  2270. $ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_factor'] = pow(2, ($ThisFileInfo['mpeg']['audio']['LAME']['mp3_gain_db'] / 6));
  2271. // bytes $B6-$B7 Preset and surround info
  2272. $PresetSurroundBytes = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
  2273. // Reserved = ($PresetSurroundBytes & 0xC000);
  2274. $ThisFileInfo['mpeg']['audio']['LAME']['raw']['surround_info'] = ($PresetSurroundBytes & 0x3800);
  2275. $ThisFileInfo['mpeg']['audio']['LAME']['surround_info'] = LAMEsurroundInfoLookup($ThisFileInfo['mpeg']['audio']['LAME']['raw']['surround_info']);
  2276. $ThisFileInfo['mpeg']['audio']['LAME']['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);
  2277. // bytes $B8-$BB MusicLength
  2278. $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
  2279. $ExpectedNumberOfAudioBytes = (($ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] > 0) ? $ThisFileInfo['mpeg']['audio']['LAME']['audio_bytes'] : $ThisFileInfo['mpeg']['audio']['VBR_bytes']);
  2280. // bytes $BC-$BD MusicCRC
  2281. $ThisFileInfo['mpeg']['audio']['LAME']['music_crc'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
  2282. // bytes $BE-$BF CRC-16 of Info Tag
  2283. $ThisFileInfo['mpeg']['audio']['LAME']['lame_tag_crc'] = BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
  2284. // LAME CBR
  2285. if ($ThisFileInfo['mpeg']['audio']['LAME']['raw']['vbr_method'] == 1)
  2286. {
  2287. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
  2288. if (empty($ThisFileInfo['mpeg']['audio']['bitrate']) || ($ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'] != 255))
  2289. {
  2290. $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['LAME']['bitrate_min'];
  2291. }
  2292. }
  2293. }
  2294. }
  2295. }
  2296. else
  2297. {
  2298. // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
  2299. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
  2300. if ($recursivesearch)
  2301. {
  2302. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
  2303. if (RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, true))
  2304. {
  2305. $recursivesearch = false;
  2306. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
  2307. }
  2308. if ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')
  2309. {
  2310. $ThisFileInfo['warning'] .= "\n" . 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
  2311. }
  2312. }
  2313. }
  2314. }
  2315. if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'])))
  2316. {
  2317. if (($ExpectedNumberOfAudioBytes - ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'])) == 1)
  2318. {
  2319. $ThisFileInfo['warning'] .= "\n" . 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)';
  2320. }
  2321. elseif ($ExpectedNumberOfAudioBytes > ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']))
  2322. {
  2323. $ThisFileInfo['warning'] .= "\n" . 'Probable truncated file: expecting ' . $ExpectedNumberOfAudioBytes . ' bytes of audio data, only found ' . ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) . ' (short by ' . ($ExpectedNumberOfAudioBytes - ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset'])) . ' bytes)';
  2324. }
  2325. else
  2326. {
  2327. $ThisFileInfo['warning'] .= "\n" . 'Too much data in file: expecting ' . $ExpectedNumberOfAudioBytes . ' bytes of audio data, found ' . ($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) . ' (' . (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) - $ExpectedNumberOfAudioBytes) . ' bytes too many)';
  2328. }
  2329. }
  2330. if (($ThisFileInfo['mpeg']['audio']['bitrate'] == 'free') && empty($ThisFileInfo['audio']['bitrate']))
  2331. {
  2332. if (($offset == $ThisFileInfo['avdataoffset']) && empty($ThisFileInfo['mpeg']['audio']['VBR_frames']))
  2333. {
  2334. $framebytelength = FreeFormatFrameLength($fd, $offset, $ThisFileInfo, true);
  2335. if ($framebytelength > 0)
  2336. {
  2337. $ThisFileInfo['mpeg']['audio']['framelength'] = $framebytelength;
  2338. if ($ThisFileInfo['mpeg']['audio']['layer'] == 'I')
  2339. {
  2340. // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
  2341. $ThisFileInfo['audio']['bitrate'] = ((($framebytelength / 4) - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate']) / 12;
  2342. }
  2343. else
  2344. {
  2345. // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
  2346. $ThisFileInfo['audio']['bitrate'] = (($framebytelength - intval($ThisFileInfo['mpeg']['audio']['padding'])) * $ThisFileInfo['mpeg']['audio']['sample_rate']) / 144;
  2347. }
  2348. }
  2349. else
  2350. {
  2351. $ThisFileInfo['error'] .= "\n" . 'Error calculating frame length of free-format MP3 without Xing/LAME header';
  2352. }
  2353. }
  2354. }
  2355. if (($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr') && isset($ThisFileInfo['mpeg']['audio']['VBR_frames']) && ($ThisFileInfo['mpeg']['audio']['VBR_frames'] > 1))
  2356. {
  2357. $ThisFileInfo['mpeg']['audio']['VBR_frames'] --; // don't count the Xing / VBRI frame
  2358. if (($ThisFileInfo['mpeg']['audio']['version'] == '1') && ($ThisFileInfo['mpeg']['audio']['layer'] == 'I'))
  2359. {
  2360. $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = ((($ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames']) * 8) * ($ThisFileInfo['audio']['sample_rate'] / 384)) / 1000;
  2361. }
  2362. elseif ((($ThisFileInfo['mpeg']['audio']['version'] == '2') || ($ThisFileInfo['mpeg']['audio']['version'] == '2.5')) && ($ThisFileInfo['mpeg']['audio']['layer'] == 'III'))
  2363. {
  2364. $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = ((($ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames']) * 8) * ($ThisFileInfo['audio']['sample_rate'] / 576)) / 1000;
  2365. }
  2366. else
  2367. {
  2368. $ThisFileInfo['mpeg']['audio']['VBR_bitrate'] = ((($ThisFileInfo['mpeg']['audio']['VBR_bytes'] / $ThisFileInfo['mpeg']['audio']['VBR_frames']) * 8) * ($ThisFileInfo['audio']['sample_rate'] / 1152)) / 1000;
  2369. }
  2370. if ($ThisFileInfo['mpeg']['audio']['VBR_bitrate'] > 0)
  2371. {
  2372. $ThisFileInfo['audio']['bitrate'] = 1000 * $ThisFileInfo['mpeg']['audio']['VBR_bitrate'];
  2373. $ThisFileInfo['mpeg']['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['VBR_bitrate']; // to avoid confusion
  2374. }
  2375. }
  2376. // End variable-bitrate headers
  2377. ////////////////////////////////////////////////////////////////////////////////////
  2378. if ($recursivesearch)
  2379. {
  2380. if (! RecursiveFrameScanning($fd, $ThisFileInfo, $offset, $nextframetestoffset, $ScanAsCBR))
  2381. {
  2382. return false;
  2383. }
  2384. }
  2385. //if (false) {
  2386. // // experimental side info parsing section - not returning anything useful yet
  2387. //
  2388. // $SideInfoBitstream = BigEndian2Bin($SideInfoData);
  2389. // $SideInfoOffset = 0;
  2390. //
  2391. // if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
  2392. // if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
  2393. // // MPEG-1 (mono)
  2394. // $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
  2395. // $SideInfoOffset += 9;
  2396. // $SideInfoOffset += 5;
  2397. // } else {
  2398. // // MPEG-1 (stereo, joint-stereo, dual-channel)
  2399. // $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
  2400. // $SideInfoOffset += 9;
  2401. // $SideInfoOffset += 3;
  2402. // }
  2403. // } else { // 2 or 2.5
  2404. // if ($ThisFileInfo['mpeg']['audio']['channelmode'] == 'mono') {
  2405. // // MPEG-2, MPEG-2.5 (mono)
  2406. // $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
  2407. // $SideInfoOffset += 8;
  2408. // $SideInfoOffset += 1;
  2409. // } else {
  2410. // // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
  2411. // $ThisFileInfo['mpeg']['audio']['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
  2412. // $SideInfoOffset += 8;
  2413. // $SideInfoOffset += 2;
  2414. // }
  2415. // }
  2416. //
  2417. // if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
  2418. // for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
  2419. // for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
  2420. // $ThisFileInfo['mpeg']['audio']['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
  2421. // $SideInfoOffset += 2;
  2422. // }
  2423. // }
  2424. // }
  2425. // for ($granule = 0; $granule < (($ThisFileInfo['mpeg']['audio']['version'] == '1') ? 2 : 1); $granule++) {
  2426. // for ($channel = 0; $channel < $ThisFileInfo['audio']['channels']; $channel++) {
  2427. // $ThisFileInfo['mpeg']['audio']['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
  2428. // $SideInfoOffset += 12;
  2429. // $ThisFileInfo['mpeg']['audio']['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
  2430. // $SideInfoOffset += 9;
  2431. // $ThisFileInfo['mpeg']['audio']['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
  2432. // $SideInfoOffset += 8;
  2433. // if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
  2434. // $ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
  2435. // $SideInfoOffset += 4;
  2436. // } else {
  2437. // $ThisFileInfo['mpeg']['audio']['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
  2438. // $SideInfoOffset += 9;
  2439. // }
  2440. // $ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
  2441. // $SideInfoOffset += 1;
  2442. //
  2443. // if ($ThisFileInfo['mpeg']['audio']['window_switching_flag'][$granule][$channel] == '1') {
  2444. //
  2445. // $ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
  2446. // $SideInfoOffset += 2;
  2447. // $ThisFileInfo['mpeg']['audio']['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
  2448. // $SideInfoOffset += 1;
  2449. //
  2450. // for ($region = 0; $region < 2; $region++) {
  2451. // $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
  2452. // $SideInfoOffset += 5;
  2453. // }
  2454. // $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][2] = 0;
  2455. //
  2456. // for ($window = 0; $window < 3; $window++) {
  2457. // $ThisFileInfo['mpeg']['audio']['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
  2458. // $SideInfoOffset += 3;
  2459. // }
  2460. //
  2461. // } else {
  2462. //
  2463. // for ($region = 0; $region < 3; $region++) {
  2464. // $ThisFileInfo['mpeg']['audio']['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
  2465. // $SideInfoOffset += 5;
  2466. // }
  2467. //
  2468. // $ThisFileInfo['mpeg']['audio']['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
  2469. // $SideInfoOffset += 4;
  2470. // $ThisFileInfo['mpeg']['audio']['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
  2471. // $SideInfoOffset += 3;
  2472. // $ThisFileInfo['mpeg']['audio']['block_type'][$granule][$channel] = 0;
  2473. // }
  2474. //
  2475. // if ($ThisFileInfo['mpeg']['audio']['version'] == '1') {
  2476. // $ThisFileInfo['mpeg']['audio']['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
  2477. // $SideInfoOffset += 1;
  2478. // }
  2479. // $ThisFileInfo['mpeg']['audio']['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
  2480. // $SideInfoOffset += 1;
  2481. // $ThisFileInfo['mpeg']['audio']['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
  2482. // $SideInfoOffset += 1;
  2483. // }
  2484. // }
  2485. //}
  2486. return true;
  2487. }
  2488. function RecursiveFrameScanning(&$fd, &$ThisFileInfo, &$offset, &$nextframetestoffset, $ScanAsCBR)
  2489. {
  2490. for($i = 0; $i < MPEG_VALID_CHECK_FRAMES; $i ++)
  2491. {
  2492. // check next MPEG_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
  2493. if (($nextframetestoffset + 4) >= $ThisFileInfo['avdataend'])
  2494. {
  2495. // end of file
  2496. return true;
  2497. }
  2498. $nextframetestarray = array('error' => '', 'warning' => '', 'avdataend' => $ThisFileInfo['avdataend'],
  2499. 'avdataoffset' => $ThisFileInfo['avdataoffset']);
  2500. if (decodeMPEGaudioHeader($fd, $nextframetestoffset, $nextframetestarray, false))
  2501. {
  2502. if ($ScanAsCBR)
  2503. {
  2504. // force CBR mode, used for trying to pick out invalid audio streams with
  2505. // valid(?) VBR headers, or VBR streams with no VBR header
  2506. if (! isset($nextframetestarray['mpeg']['audio']['bitrate']) || ! isset($ThisFileInfo['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $ThisFileInfo['mpeg']['audio']['bitrate']))
  2507. {
  2508. return false;
  2509. }
  2510. }
  2511. // next frame is OK, get ready to check the one after that
  2512. if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0))
  2513. {
  2514. $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength'];
  2515. }
  2516. else
  2517. {
  2518. $ThisFileInfo['error'] .= "\n" . 'Frame at offset (' . $offset . ') is has an invalid frame length.';
  2519. return false;
  2520. }
  2521. }
  2522. else
  2523. {
  2524. // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
  2525. $ThisFileInfo['error'] .= "\n" . 'Frame at offset (' . $offset . ') is valid, but the next one at (' . $nextframetestoffset . ') is not.';
  2526. return false;
  2527. }
  2528. }
  2529. return true;
  2530. }
  2531. function FreeFormatFrameLength($fd, $offset, &$ThisFileInfo, $deepscan = false)
  2532. {
  2533. fseek($fd, $offset, SEEK_SET);
  2534. $MPEGaudioData = fread($fd, 32768);
  2535. $SyncPattern1 = substr($MPEGaudioData, 0, 4);
  2536. // may be different pattern due to padding
  2537. $SyncPattern2 = $SyncPattern1{0} . $SyncPattern1{1} . chr(ord($SyncPattern1{2}) | 0x02) . $SyncPattern1{3};
  2538. if ($SyncPattern2 === $SyncPattern1)
  2539. {
  2540. $SyncPattern2 = $SyncPattern1{0} . $SyncPattern1{1} . chr(ord($SyncPattern1{2}) & 0xFD) . $SyncPattern1{3};
  2541. }
  2542. $framelength = false;
  2543. $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4);
  2544. $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4);
  2545. if ($framelength1 > 4)
  2546. {
  2547. $framelength = $framelength1;
  2548. }
  2549. if (($framelength2 > 4) && ($framelength2 < $framelength1))
  2550. {
  2551. $framelength = $framelength2;
  2552. }
  2553. if (! $framelength)
  2554. {
  2555. // LAME 3.88 has a different value for modeextension on the first frame vs the rest
  2556. $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4);
  2557. $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4);
  2558. if ($framelength1 > 4)
  2559. {
  2560. $framelength = $framelength1;
  2561. }
  2562. if (($framelength2 > 4) && ($framelength2 < $framelength1))
  2563. {
  2564. $framelength = $framelength2;
  2565. }
  2566. if (! $framelength)
  2567. {
  2568. $ThisFileInfo['error'] .= "\n" . 'Cannot find next free-format synch pattern (' . PrintHexBytes($SyncPattern1) . ' or ' . PrintHexBytes($SyncPattern2) . ') after offset ' . $offset;
  2569. return false;
  2570. }
  2571. else
  2572. {
  2573. $ThisFileInfo['warning'] .= "\n" . 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)';
  2574. $ThisFileInfo['audio']['codec'] = 'LAME';
  2575. $ThisFileInfo['audio']['encoder'] = 'LAME3.88';
  2576. $SyncPattern1 = substr($SyncPattern1, 0, 3);
  2577. $SyncPattern2 = substr($SyncPattern2, 0, 3);
  2578. }
  2579. }
  2580. if ($deepscan)
  2581. {
  2582. $ActualFrameLengthValues = array();
  2583. $nextoffset = $offset + $framelength;
  2584. while ($nextoffset < ($ThisFileInfo['avdataend'] - 6))
  2585. {
  2586. fseek($fd, $nextoffset - 1, SEEK_SET);
  2587. $NextSyncPattern = fread($fd, 6);
  2588. if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2))
  2589. {
  2590. // good - found where expected
  2591. $ActualFrameLengthValues[] = $framelength;
  2592. }
  2593. elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2))
  2594. {
  2595. // ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
  2596. $ActualFrameLengthValues[] = ($framelength - 1);
  2597. $nextoffset --;
  2598. }
  2599. elseif ((substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2))
  2600. {
  2601. // ok - found one byte later than expected (last frame was padded, first frame wasn't)
  2602. $ActualFrameLengthValues[] = ($framelength + 1);
  2603. $nextoffset ++;
  2604. }
  2605. else
  2606. {
  2607. $ThisFileInfo['error'] .= "\n" . 'Did not find expected free-format sync pattern at offset ' . $nextoffset;
  2608. return false;
  2609. }
  2610. $nextoffset += $framelength;
  2611. }
  2612. if (count($ActualFrameLengthValues) > 0)
  2613. {
  2614. $framelength = round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues));
  2615. }
  2616. }
  2617. return $framelength;
  2618. }
  2619. function getOnlyMPEGaudioInfo($fd, &$ThisFileInfo, $avdataoffset, $BitrateHistogram = false)
  2620. {
  2621. // looks for synch, decodes MPEG audio header
  2622. fseek($fd, $avdataoffset, SEEK_SET);
  2623. $header = '';
  2624. $SynchSeekOffset = 0;
  2625. if (! defined('CONST_FF'))
  2626. {
  2627. define('CONST_FF', chr(0xFF));
  2628. define('CONST_E0', chr(0xE0));
  2629. }
  2630. static $MPEGaudioVersionLookup;
  2631. static $MPEGaudioLayerLookup;
  2632. static $MPEGaudioBitrateLookup;
  2633. if (empty($MPEGaudioVersionLookup))
  2634. {
  2635. $MPEGaudioVersionLookup = MPEGaudioVersionArray();
  2636. $MPEGaudioLayerLookup = MPEGaudioLayerArray();
  2637. $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
  2638. }
  2639. $header_len = strlen($header) - round(FREAD_BUFFER_SIZE / 2);
  2640. while (true)
  2641. {
  2642. if (($SynchSeekOffset > $header_len) && (($avdataoffset + $SynchSeekOffset) < $ThisFileInfo['avdataend']) && ! feof($fd))
  2643. {
  2644. if ($SynchSeekOffset > 131072)
  2645. {
  2646. // if a synch's not found within the first 128k bytes, then give up
  2647. $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch within the first 131072 bytes';
  2648. if (isset($ThisFileInfo['audio']['bitrate']))
  2649. {
  2650. unset($ThisFileInfo['audio']['bitrate']);
  2651. }
  2652. if (isset($ThisFileInfo['mpeg']['audio']))
  2653. {
  2654. unset($ThisFileInfo['mpeg']['audio']);
  2655. }
  2656. if (isset($ThisFileInfo['mpeg']) && (! is_array($ThisFileInfo['mpeg']) || (count($ThisFileInfo['mpeg']) == 0)))
  2657. {
  2658. unset($ThisFileInfo['mpeg']);
  2659. }
  2660. return false;
  2661. }
  2662. elseif ($header .= fread($fd, FREAD_BUFFER_SIZE))
  2663. {
  2664. // great
  2665. $header_len = strlen($header) - round(FREAD_BUFFER_SIZE / 2);
  2666. }
  2667. else
  2668. {
  2669. $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
  2670. if (isset($ThisFileInfo['audio']['bitrate']))
  2671. {
  2672. unset($ThisFileInfo['audio']['bitrate']);
  2673. }
  2674. if (isset($ThisFileInfo['mpeg']['audio']))
  2675. {
  2676. unset($ThisFileInfo['mpeg']['audio']);
  2677. }
  2678. if (isset($ThisFileInfo['mpeg']) && (! is_array($ThisFileInfo['mpeg']) || (count($ThisFileInfo['mpeg']) == 0)))
  2679. {
  2680. unset($ThisFileInfo['mpeg']);
  2681. }
  2682. return false;
  2683. }
  2684. }
  2685. if (($SynchSeekOffset + 1) >= strlen($header))
  2686. {
  2687. $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
  2688. return false;
  2689. }
  2690. if (($header{$SynchSeekOffset} == CONST_FF) && ($header{($SynchSeekOffset + 1)} > CONST_E0))
  2691. { // synch detected
  2692. if (! isset($FirstFrameThisfileInfo) && ! isset($ThisFileInfo['mpeg']['audio']))
  2693. {
  2694. $FirstFrameThisfileInfo = $ThisFileInfo;
  2695. $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
  2696. if (! decodeMPEGaudioHeader($fd, $avdataoffset + $SynchSeekOffset, $FirstFrameThisfileInfo, false))
  2697. {
  2698. // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
  2699. // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
  2700. unset($FirstFrameThisfileInfo);
  2701. }
  2702. }
  2703. $dummy = $ThisFileInfo; // only overwrite real data if valid header found
  2704. if (decodeMPEGaudioHeader($fd, $avdataoffset + $SynchSeekOffset, $dummy, true))
  2705. {
  2706. $ThisFileInfo = $dummy;
  2707. $ThisFileInfo['avdataoffset'] = $avdataoffset + $SynchSeekOffset;
  2708. switch ($ThisFileInfo['fileformat'])
  2709. {
  2710. case '' :
  2711. case 'id3' :
  2712. case 'ape' :
  2713. case 'mp3' :
  2714. $ThisFileInfo['fileformat'] = 'mp3';
  2715. $ThisFileInfo['audio']['dataformat'] = 'mp3';
  2716. }
  2717. if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr'))
  2718. {
  2719. if (! CloseMatch($ThisFileInfo['audio']['bitrate'], $FirstFrameThisfileInfo['audio']['bitrate'], 1))
  2720. {
  2721. // If there is garbage data between a valid VBR header frame and a sequence
  2722. // of valid MPEG-audio frames the VBR data is no longer discarded.
  2723. $ThisFileInfo = $FirstFrameThisfileInfo;
  2724. $ThisFileInfo['avdataoffset'] = $FirstFrameAVDataOffset;
  2725. $ThisFileInfo['fileformat'] = 'mp3';
  2726. $ThisFileInfo['audio']['dataformat'] = 'mp3';
  2727. $dummy = $ThisFileInfo;
  2728. unset($dummy['mpeg']['audio']);
  2729. $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
  2730. $GarbageOffsetEnd = $avdataoffset + $SynchSeekOffset;
  2731. if (decodeMPEGaudioHeader($fd, $GarbageOffsetEnd, $dummy, true, true))
  2732. {
  2733. $ThisFileInfo = $dummy;
  2734. $ThisFileInfo['avdataoffset'] = $GarbageOffsetEnd;
  2735. $ThisFileInfo['warning'] .= "\n" . 'apparently-valid VBR header not used because could not find ' . MPEG_VALID_CHECK_FRAMES . ' consecutive MPEG-audio frames immediately after VBR header (garbage data for ' . ($GarbageOffsetEnd - $GarbageOffsetStart) . ' bytes between ' . $GarbageOffsetStart . ' and ' . $GarbageOffsetEnd . '), but did find valid CBR stream starting at ' . $GarbageOffsetEnd;
  2736. }
  2737. else
  2738. {
  2739. $ThisFileInfo['warning'] .= "\n" . 'using data from VBR header even though could not find ' . MPEG_VALID_CHECK_FRAMES . ' consecutive MPEG-audio frames immediately after VBR header (garbage data for ' . ($GarbageOffsetEnd - $GarbageOffsetStart) . ' bytes between ' . $GarbageOffsetStart . ' and ' . $GarbageOffsetEnd . ')';
  2740. }
  2741. }
  2742. }
  2743. if (isset($ThisFileInfo['mpeg']['audio']['bitrate_mode']) && ($ThisFileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr') && ! isset($ThisFileInfo['mpeg']['audio']['VBR_method']))
  2744. {
  2745. // VBR file with no VBR header
  2746. $BitrateHistogram = true;
  2747. }
  2748. if ($BitrateHistogram)
  2749. {
  2750. $ThisFileInfo['mpeg']['audio']['stereo_distribution'] = array('stereo' => 0, 'joint stereo' => 0,
  2751. 'dual channel' => 0, 'mono' => 0);
  2752. $ThisFileInfo['mpeg']['audio']['version_distribution'] = array('1' => 0, '2' => 0, '2.5' => 0);
  2753. if ($ThisFileInfo['mpeg']['audio']['version'] == '1')
  2754. {
  2755. if ($ThisFileInfo['mpeg']['audio']['layer'] == 'III')
  2756. {
  2757. $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 40 => 0,
  2758. 48 => 0, 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0, 160 => 0, 192 => 0,
  2759. 224 => 0, 256 => 0, 320 => 0);
  2760. }
  2761. elseif ($ThisFileInfo['mpeg']['audio']['layer'] == 'II')
  2762. {
  2763. $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 48 => 0,
  2764. 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0, 160 => 0, 192 => 0, 224 => 0,
  2765. 256 => 0, 320 => 0, 384 => 0);
  2766. }
  2767. elseif ($ThisFileInfo['mpeg']['audio']['layer'] == 'I')
  2768. {
  2769. $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 64 => 0,
  2770. 96 => 0, 128 => 0, 160 => 0, 192 => 0, 224 => 0, 256 => 0, 288 => 0, 320 => 0,
  2771. 352 => 0, 384 => 0, 416 => 0, 448 => 0);
  2772. }
  2773. }
  2774. elseif ($ThisFileInfo['mpeg']['audio']['layer'] == 'I')
  2775. {
  2776. $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 32 => 0, 48 => 0,
  2777. 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0, 144 => 0, 160 => 0, 176 => 0,
  2778. 192 => 0, 224 => 0, 256 => 0);
  2779. }
  2780. else
  2781. {
  2782. $ThisFileInfo['mpeg']['audio']['bitrate_distribution'] = array('free' => 0, 8 => 0, 16 => 0,
  2783. 24 => 0, 32 => 0, 40 => 0, 48 => 0, 56 => 0, 64 => 0, 80 => 0, 96 => 0, 112 => 0, 128 => 0,
  2784. 144 => 0, 160 => 0);
  2785. }
  2786. $dummy = array('error' => $ThisFileInfo['error'], 'warning' => $ThisFileInfo['warning'],
  2787. 'avdataend' => $ThisFileInfo['avdataend'], 'avdataoffset' => $ThisFileInfo['avdataoffset']);
  2788. $synchstartoffset = $ThisFileInfo['avdataoffset'];
  2789. $FastMode = false;
  2790. while (decodeMPEGaudioHeader($fd, $synchstartoffset, $dummy, false, false, $FastMode))
  2791. {
  2792. $FastMode = true;
  2793. $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
  2794. $ThisFileInfo['mpeg']['audio']['bitrate_distribution'][$thisframebitrate] ++;
  2795. $ThisFileInfo['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']] ++;
  2796. $ThisFileInfo['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']] ++;
  2797. if (empty($dummy['mpeg']['audio']['framelength']))
  2798. {
  2799. $ThisFileInfo['warning'] .= "\n" . 'Invalid/missing framelength in histogram analysis - aborting';
  2800. $synchstartoffset += 4;
  2801. // return false;
  2802. }
  2803. $synchstartoffset += $dummy['mpeg']['audio']['framelength'];
  2804. }
  2805. $bittotal = 0;
  2806. $framecounter = 0;
  2807. foreach ($ThisFileInfo['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount)
  2808. {
  2809. $framecounter += $bitratecount;
  2810. if ($bitratevalue != 'free')
  2811. {
  2812. $bittotal += ($bitratevalue * $bitratecount);
  2813. }
  2814. }
  2815. if ($framecounter == 0)
  2816. {
  2817. $ThisFileInfo['error'] .= "\n" . 'Corrupt MP3 file: framecounter == zero';
  2818. return false;
  2819. }
  2820. $ThisFileInfo['mpeg']['audio']['frame_count'] = $framecounter;
  2821. $ThisFileInfo['mpeg']['audio']['bitrate'] = 1000 * ($bittotal / $framecounter);
  2822. $ThisFileInfo['audio']['bitrate'] = $ThisFileInfo['mpeg']['audio']['bitrate'];
  2823. // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
  2824. $distinct_bitrates = 0;
  2825. foreach ($ThisFileInfo['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count)
  2826. {
  2827. if ($bitrate_count > 0)
  2828. {
  2829. $distinct_bitrates ++;
  2830. }
  2831. }
  2832. if ($distinct_bitrates > 1)
  2833. {
  2834. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'vbr';
  2835. }
  2836. else
  2837. {
  2838. $ThisFileInfo['mpeg']['audio']['bitrate_mode'] = 'cbr';
  2839. }
  2840. $ThisFileInfo['audio']['bitrate_mode'] = $ThisFileInfo['mpeg']['audio']['bitrate_mode'];
  2841. }
  2842. break; // exit while()
  2843. }
  2844. }
  2845. $SynchSeekOffset ++;
  2846. if (($avdataoffset + $SynchSeekOffset) >= $ThisFileInfo['avdataend'])
  2847. {
  2848. // end of file/data
  2849. if (empty($ThisFileInfo['mpeg']['audio']))
  2850. {
  2851. $ThisFileInfo['error'] .= "\n" . 'could not find valid MPEG synch before end of file';
  2852. if (isset($ThisFileInfo['audio']['bitrate']))
  2853. {
  2854. unset($ThisFileInfo['audio']['bitrate']);
  2855. }
  2856. if (isset($ThisFileInfo['mpeg']['audio']))
  2857. {
  2858. unset($ThisFileInfo['mpeg']['audio']);
  2859. }
  2860. if (isset($ThisFileInfo['mpeg']) && (! is_array($ThisFileInfo['mpeg']) || empty($ThisFileInfo['mpeg'])))
  2861. {
  2862. unset($ThisFileInfo['mpeg']);
  2863. }
  2864. return false;
  2865. }
  2866. break;
  2867. }
  2868. }
  2869. $ThisFileInfo['audio']['bits_per_sample'] = 16;
  2870. $ThisFileInfo['audio']['channels'] = $ThisFileInfo['mpeg']['audio']['channels'];
  2871. $ThisFileInfo['audio']['channelmode'] = $ThisFileInfo['mpeg']['audio']['channelmode'];
  2872. $ThisFileInfo['audio']['sample_rate'] = $ThisFileInfo['mpeg']['audio']['sample_rate'];
  2873. return true;
  2874. }
  2875. function MPEGaudioVersionArray()
  2876. {
  2877. static $MPEGaudioVersion = array('2.5', false, '2', '1');
  2878. return $MPEGaudioVersion;
  2879. }
  2880. function MPEGaudioLayerArray()
  2881. {
  2882. static $MPEGaudioLayer = array(false, 'III', 'II', 'I');
  2883. return $MPEGaudioLayer;
  2884. }
  2885. function MPEGaudioBitrateArray()
  2886. {
  2887. static $MPEGaudioBitrate;
  2888. if (empty($MPEGaudioBitrate))
  2889. {
  2890. $MPEGaudioBitrate['1']['I'] = array('free', 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448);
  2891. $MPEGaudioBitrate['1']['II'] = array('free', 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384);
  2892. $MPEGaudioBitrate['1']['III'] = array('free', 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320);
  2893. $MPEGaudioBitrate['2']['I'] = array('free', 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256);
  2894. $MPEGaudioBitrate['2']['II'] = array('free', 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160);
  2895. $MPEGaudioBitrate['2']['III'] = $MPEGaudioBitrate['2']['II'];
  2896. $MPEGaudioBitrate['2.5']['I'] = $MPEGaudioBitrate['2']['I'];
  2897. $MPEGaudioBitrate['2.5']['II'] = $MPEGaudioBitrate['2']['II'];
  2898. $MPEGaudioBitrate['2.5']['III'] = $MPEGaudioBitrate['2']['III'];
  2899. }
  2900. return $MPEGaudioBitrate;
  2901. }
  2902. function MPEGaudioFrequencyArray()
  2903. {
  2904. static $MPEGaudioFrequency;
  2905. if (empty($MPEGaudioFrequency))
  2906. {
  2907. $MPEGaudioFrequency['1'] = array(44100, 48000, 32000);
  2908. $MPEGaudioFrequency['2'] = array(22050, 24000, 16000);
  2909. $MPEGaudioFrequency['2.5'] = array(11025, 12000, 8000);
  2910. }
  2911. return $MPEGaudioFrequency;
  2912. }
  2913. function MPEGaudioChannelModeArray()
  2914. {
  2915. static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
  2916. return $MPEGaudioChannelMode;
  2917. }
  2918. function MPEGaudioModeExtensionArray()
  2919. {
  2920. static $MPEGaudioModeExtension;
  2921. if (empty($MPEGaudioModeExtension))
  2922. {
  2923. $MPEGaudioModeExtension['I'] = array('4-31', '8-31', '12-31', '16-31');
  2924. $MPEGaudioModeExtension['II'] = array('4-31', '8-31', '12-31', '16-31');
  2925. $MPEGaudioModeExtension['III'] = array('', 'IS', 'MS', 'IS+MS');
  2926. }
  2927. return $MPEGaudioModeExtension;
  2928. }
  2929. function MPEGaudioEmphasisArray()
  2930. {
  2931. static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
  2932. return $MPEGaudioEmphasis;
  2933. }
  2934. function MPEGaudioHeaderBytesValid($head4)
  2935. {
  2936. return MPEGaudioHeaderValid(MPEGaudioHeaderDecode($head4));
  2937. }
  2938. function MPEGaudioHeaderValid($rawarray, $echoerrors = false)
  2939. {
  2940. if (($rawarray['synch'] & 0x0FFE) != 0x0FFE)
  2941. {
  2942. return false;
  2943. }
  2944. static $MPEGaudioVersionLookup;
  2945. static $MPEGaudioLayerLookup;
  2946. static $MPEGaudioBitrateLookup;
  2947. static $MPEGaudioFrequencyLookup;
  2948. static $MPEGaudioChannelModeLookup;
  2949. static $MPEGaudioModeExtensionLookup;
  2950. static $MPEGaudioEmphasisLookup;
  2951. if (empty($MPEGaudioVersionLookup))
  2952. {
  2953. $MPEGaudioVersionLookup = MPEGaudioVersionArray();
  2954. $MPEGaudioLayerLookup = MPEGaudioLayerArray();
  2955. $MPEGaudioBitrateLookup = MPEGaudioBitrateArray();
  2956. $MPEGaudioFrequencyLookup = MPEGaudioFrequencyArray();
  2957. $MPEGaudioChannelModeLookup = MPEGaudioChannelModeArray();
  2958. $MPEGaudioModeExtensionLookup = MPEGaudioModeExtensionArray();
  2959. $MPEGaudioEmphasisLookup = MPEGaudioEmphasisArray();
  2960. }
  2961. if (isset($MPEGaudioVersionLookup[$rawarray['version']]))
  2962. {
  2963. $decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']];
  2964. }
  2965. else
  2966. {
  2967. if ($echoerrors)
  2968. {
  2969. echo "\n" . 'invalid Version (' . $rawarray['version'] . ')';
  2970. }
  2971. return false;
  2972. }
  2973. if (isset($MPEGaudioLayerLookup[$rawarray['layer']]))
  2974. {
  2975. $decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']];
  2976. }
  2977. else
  2978. {
  2979. if ($echoerrors)
  2980. {
  2981. echo "\n" . 'invalid Layer (' . $rawarray['layer'] . ')';
  2982. }
  2983. return false;
  2984. }
  2985. if (! isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']]))
  2986. {
  2987. if ($echoerrors)
  2988. {
  2989. echo "\n" . 'invalid Bitrate (' . $rawarray['bitrate'] . ')';
  2990. }
  2991. if ($rawarray['bitrate'] == 15)
  2992. {
  2993. // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
  2994. // let it go through here otherwise file will not be identified
  2995. }
  2996. else
  2997. {
  2998. return false;
  2999. }
  3000. }
  3001. if (! isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']]))
  3002. {
  3003. if ($echoerrors)
  3004. {
  3005. echo "\n" . 'invalid Frequency (' . $rawarray['sample_rate'] . ')';
  3006. }
  3007. return false;
  3008. }
  3009. if (! isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']]))
  3010. {
  3011. if ($echoerrors)
  3012. {
  3013. echo "\n" . 'invalid ChannelMode (' . $rawarray['channelmode'] . ')';
  3014. }
  3015. return false;
  3016. }
  3017. if (! isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']]))
  3018. {
  3019. if ($echoerrors)
  3020. {
  3021. echo "\n" . 'invalid Mode Extension (' . $rawarray['modeextension'] . ')';
  3022. }
  3023. return false;
  3024. }
  3025. if (! isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']]))
  3026. {
  3027. if ($echoerrors)
  3028. {
  3029. echo "\n" . 'invalid Emphasis (' . $rawarray['emphasis'] . ')';
  3030. }
  3031. return false;
  3032. }
  3033. // These are just either set or not set, you can't mess that up :)
  3034. // $rawarray['protection'];
  3035. // $rawarray['padding'];
  3036. // $rawarray['private'];
  3037. // $rawarray['copyright'];
  3038. // $rawarray['original'];
  3039. return true;
  3040. }
  3041. function MPEGaudioHeaderDecode($Header4Bytes)
  3042. {
  3043. // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
  3044. // A - Frame sync (all bits set)
  3045. // B - MPEG Audio version ID
  3046. // C - Layer description
  3047. // D - Protection bit
  3048. // E - Bitrate index
  3049. // F - Sampling rate frequency index
  3050. // G - Padding bit
  3051. // H - Private bit
  3052. // I - Channel Mode
  3053. // J - Mode extension (Only if Joint stereo)
  3054. // K - Copyright
  3055. // L - Original
  3056. // M - Emphasis
  3057. if (strlen($Header4Bytes) != 4)
  3058. {
  3059. return false;
  3060. }
  3061. $MPEGrawHeader['synch'] = (BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
  3062. $MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB
  3063. $MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC
  3064. $MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D
  3065. $MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE
  3066. $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF
  3067. $MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G
  3068. $MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H
  3069. $MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II
  3070. $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ
  3071. $MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K
  3072. $MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L
  3073. $MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM
  3074. return $MPEGrawHeader;
  3075. }
  3076. function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate)
  3077. {
  3078. static $AudioFrameLengthCache = array();
  3079. if (! isset($AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate]))
  3080. {
  3081. $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = false;
  3082. if ($bitrate != 'free')
  3083. {
  3084. if ($version == '1')
  3085. {
  3086. if ($layer == 'I')
  3087. {
  3088. // For Layer I slot is 32 bits long
  3089. $FrameLengthCoefficient = 48;
  3090. $SlotLength = 4;
  3091. }
  3092. else
  3093. { // Layer II / III
  3094. // for Layer II and Layer III slot is 8 bits long.
  3095. $FrameLengthCoefficient = 144;
  3096. $SlotLength = 1;
  3097. }
  3098. }
  3099. else
  3100. { // MPEG-2 / MPEG-2.5
  3101. if ($layer == 'I')
  3102. {
  3103. // For Layer I slot is 32 bits long
  3104. $FrameLengthCoefficient = 24;
  3105. $SlotLength = 4;
  3106. }
  3107. elseif ($layer == 'II')
  3108. {
  3109. // for Layer II and Layer III slot is 8 bits long.
  3110. $FrameLengthCoefficient = 144;
  3111. $SlotLength = 1;
  3112. }
  3113. else
  3114. { // III
  3115. // for Layer II and Layer III slot is 8 bits long.
  3116. $FrameLengthCoefficient = 72;
  3117. $SlotLength = 1;
  3118. }
  3119. }
  3120. // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
  3121. // http://66.96.216.160/cgi-bin/YaBB.pl?board=c&action=display&num=1018474068
  3122. // -> [Finding the next frame synch] on www.r3mix.net forums if the above link goes dead
  3123. if ($samplerate > 0)
  3124. {
  3125. $NewFramelength = ($FrameLengthCoefficient * $bitrate * 1000) / $samplerate;
  3126. $NewFramelength = floor($NewFramelength / $SlotLength) * $SlotLength; // round to next-lower multiple of SlotLength (1 byte for Layer II/III, 4 bytes for Layer I)
  3127. if ($padding)
  3128. {
  3129. $NewFramelength += $SlotLength;
  3130. }
  3131. $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = (int) $NewFramelength;
  3132. }
  3133. }
  3134. }
  3135. return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
  3136. }
  3137. function LAMEvbrMethodLookup($VBRmethodID)
  3138. {
  3139. static $LAMEvbrMethodLookup = array();
  3140. if (empty($LAMEvbrMethodLookup))
  3141. {
  3142. $LAMEvbrMethodLookup[0x00] = 'unknown';
  3143. $LAMEvbrMethodLookup[0x01] = 'cbr';
  3144. $LAMEvbrMethodLookup[0x02] = 'abr';
  3145. $LAMEvbrMethodLookup[0x03] = 'vbr-old / vbr-rh';
  3146. $LAMEvbrMethodLookup[0x04] = 'vbr-mtrh';
  3147. $LAMEvbrMethodLookup[0x05] = 'vbr-new / vbr-mt';
  3148. }
  3149. return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
  3150. }
  3151. function LAMEmiscStereoModeLookup($StereoModeID)
  3152. {
  3153. static $LAMEmiscStereoModeLookup = array();
  3154. if (empty($LAMEmiscStereoModeLookup))
  3155. {
  3156. $LAMEmiscStereoModeLookup[0] = 'mono';
  3157. $LAMEmiscStereoModeLookup[1] = 'stereo';
  3158. $LAMEmiscStereoModeLookup[2] = 'dual';
  3159. $LAMEmiscStereoModeLookup[3] = 'joint';
  3160. $LAMEmiscStereoModeLookup[4] = 'forced';
  3161. $LAMEmiscStereoModeLookup[5] = 'auto';
  3162. $LAMEmiscStereoModeLookup[6] = 'intensity';
  3163. $LAMEmiscStereoModeLookup[7] = 'other';
  3164. }
  3165. return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
  3166. }
  3167. function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID)
  3168. {
  3169. static $LAMEmiscSourceSampleFrequencyLookup = array();
  3170. if (empty($LAMEmiscSourceSampleFrequencyLookup))
  3171. {
  3172. $LAMEmiscSourceSampleFrequencyLookup[0] = '<= 32 kHz';
  3173. $LAMEmiscSourceSampleFrequencyLookup[1] = '44.1 kHz';
  3174. $LAMEmiscSourceSampleFrequencyLookup[2] = '48 kHz';
  3175. $LAMEmiscSourceSampleFrequencyLookup[3] = '> 48kHz';
  3176. }
  3177. return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
  3178. }
  3179. function LAMEsurroundInfoLookup($SurroundInfoID)
  3180. {
  3181. static $LAMEsurroundInfoLookup = array();
  3182. if (empty($LAMEsurroundInfoLookup))
  3183. {
  3184. $LAMEsurroundInfoLookup[0] = 'no surround info';
  3185. $LAMEsurroundInfoLookup[1] = 'DPL encoding';
  3186. $LAMEsurroundInfoLookup[2] = 'DPL2 encoding';
  3187. $LAMEsurroundInfoLookup[3] = 'Ambisonic encoding';
  3188. }
  3189. return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
  3190. }
  3191. ?>