demo.mp3header.php 118 KB

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