PageRenderTime 33ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/public/library/xinha/plugins/MootoolsFileManager/mootools-filemanager/Backend/Assets/getid3/module.audio.mp3.php

https://bitbucket.org/mayorbrain/precurio-v2
PHP | 1696 lines | 1168 code | 347 blank | 181 comment | 327 complexity | 3d6c9200771812319016ccfa9a9602c9 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause, LGPL-2.0, CC-BY-SA-3.0, MIT
  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP version 5 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 2002-2006 James Heinrich, Allan Hansen |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to version 2 of the GPL license, |
  8. // | that is bundled with this package in the file license.txt and is |
  9. // | available through the world-wide-web at the following url: |
  10. // | http://www.gnu.org/copyleft/gpl.html |
  11. // +----------------------------------------------------------------------+
  12. // | getID3() - http://getid3.sourceforge.net or http://www.getid3.org |
  13. // +----------------------------------------------------------------------+
  14. // | Authors: James Heinrich <infoŘgetid3*org> |
  15. // | Allan Hansen <ahŘartemis*dk> |
  16. // +----------------------------------------------------------------------+
  17. // | module.audio.mp3.php |
  18. // | Module for analyzing MPEG Audio Layer 1,2,3 files. |
  19. // | dependencies: none |
  20. // +----------------------------------------------------------------------+
  21. //
  22. // $Id: module.audio.mp3.php,v 1.10 2006/11/16 22:57:57 ah Exp $
  23. class getid3_mp3 extends getid3_handler
  24. {
  25. // Number of frames to scan to determine if MPEG-audio sequence is valid.
  26. // Lower this number to 5-20 for faster scanning
  27. // Increase this number to 50+ for most accurate detection of valid VBR/CBR mpeg-audio streams
  28. const VALID_CHECK_FRAMES = 35;
  29. public function Analyze() {
  30. $this->getAllMPEGInfo($this->getid3->fp, $this->getid3->info);
  31. return true;
  32. }
  33. public function AnalyzeMPEGaudioInfo() {
  34. $this->getOnlyMPEGaudioInfo($this->getid3->fp, $this->getid3->info, $this->getid3->info['avdataoffset'], false);
  35. }
  36. public function getAllMPEGInfo(&$fd, &$info) {
  37. $this->getOnlyMPEGaudioInfo($fd, $info, 0 + $info['avdataoffset']);
  38. if (isset($info['mpeg']['audio']['bitrate_mode'])) {
  39. $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
  40. }
  41. if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0)))) {
  42. $synch_offset_warning = 'Unknown data before synch ';
  43. if (isset($info['id3v2']['headerlength'])) {
  44. $synch_offset_warning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, ';
  45. } else {
  46. $synch_offset_warning .= '(should be at beginning of file, ';
  47. }
  48. $synch_offset_warning .= 'synch detected at '.$info['avdataoffset'].')';
  49. if ($info['audio']['bitrate_mode'] == 'cbr') {
  50. if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) {
  51. $synch_offset_warning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.';
  52. $info['audio']['codec'] = 'LAME';
  53. $current_data_lame_version_string = 'LAME3.';
  54. } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) {
  55. $synch_offset_warning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.';
  56. $info['audio']['codec'] = 'LAME';
  57. $current_data_lame_version_string = 'LAME3.';
  58. }
  59. }
  60. $this->getid3->warning($synch_offset_warning);
  61. }
  62. if (isset($info['mpeg']['audio']['LAME'])) {
  63. $info['audio']['codec'] = 'LAME';
  64. if (!empty($info['mpeg']['audio']['LAME']['long_version'])) {
  65. $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00");
  66. } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) {
  67. $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00");
  68. }
  69. }
  70. $current_data_lame_version_string = (!empty($current_data_lame_version_string) ? $current_data_lame_version_string : @$info['audio']['encoder']);
  71. if (!empty($current_data_lame_version_string) && (substr($current_data_lame_version_string, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($current_data_lame_version_string, -1))) {
  72. // a version number of LAME that does not end with a number like "LAME3.92"
  73. // or with a closing parenthesis like "LAME3.88 (alpha)"
  74. // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92)
  75. // not sure what the actual last frame length will be, but will be less than or equal to 1441
  76. $possibly_longer_lame_version_frame_length = 1441;
  77. // Not sure what version of LAME this is - look in padding of last frame for longer version string
  78. $possible_lame_version_string_offset = $info['avdataend'] - $possibly_longer_lame_version_frame_length;
  79. fseek($fd, $possible_lame_version_string_offset);
  80. $possibly_longer_lame_version_data = fread($fd, $possibly_longer_lame_version_frame_length);
  81. switch (substr($current_data_lame_version_string, -1)) {
  82. case 'a':
  83. case 'b':
  84. // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
  85. // need to trim off "a" to match longer string
  86. $current_data_lame_version_string = substr($current_data_lame_version_string, 0, -1);
  87. break;
  88. }
  89. if (($possibly_longer_lame_version_string = strstr($possibly_longer_lame_version_data, $current_data_lame_version_string)) !== false) {
  90. if (substr($possibly_longer_lame_version_string, 0, strlen($current_data_lame_version_string)) == $current_data_lame_version_string) {
  91. $possibly_longer_lame_version_new_string = substr($possibly_longer_lame_version_string, 0, strspn($possibly_longer_lame_version_string, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
  92. if (strlen($possibly_longer_lame_version_new_string) > strlen(@$info['audio']['encoder'])) {
  93. $info['audio']['encoder'] = $possibly_longer_lame_version_new_string;
  94. }
  95. }
  96. }
  97. }
  98. if (!empty($info['audio']['encoder'])) {
  99. $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 ");
  100. }
  101. switch (@$info['mpeg']['audio']['layer']) {
  102. case 1:
  103. case 2:
  104. $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
  105. break;
  106. }
  107. if (@$info['fileformat'] == 'mp3') {
  108. switch ($info['audio']['dataformat']) {
  109. case 'mp1':
  110. case 'mp2':
  111. case 'mp3':
  112. $info['fileformat'] = $info['audio']['dataformat'];
  113. break;
  114. default:
  115. $this->getid3->warning('Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"');
  116. break;
  117. }
  118. }
  119. $info['mime_type'] = 'audio/mpeg';
  120. $info['audio']['lossless'] = false;
  121. // Calculate playtime
  122. if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
  123. $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
  124. }
  125. $info['audio']['encoder_options'] = getid3_mp3::GuessEncoderOptions($info);
  126. return true;
  127. }
  128. public static function GuessEncoderOptions(&$info) {
  129. // shortcuts
  130. if (!empty($info['mpeg']['audio'])) {
  131. $thisfile_mpeg_audio = &$info['mpeg']['audio'];
  132. if (!empty($thisfile_mpeg_audio['LAME'])) {
  133. $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
  134. }
  135. }
  136. $encoder_options = '';
  137. static $named_preset_bitrates = array (16, 24, 40, 56, 112, 128, 160, 192, 256);
  138. if ((@$thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) {
  139. $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
  140. } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $named_preset_bitrates))) {
  141. $encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
  142. } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) {
  143. static $known_encoder_values = array ();
  144. if (empty($known_encoder_values)) {
  145. //$known_encoder_values[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name';
  146. $known_encoder_values[0xFF][58][1][1][3][2][20500] = '--alt-preset insane'; // 3.90, 3.90.1, 3.92
  147. $known_encoder_values[0xFF][58][1][1][3][2][20600] = '--alt-preset insane'; // 3.90.2, 3.90.3, 3.91
  148. $known_encoder_values[0xFF][57][1][1][3][4][20500] = '--alt-preset insane'; // 3.94, 3.95
  149. $known_encoder_values['**'][78][3][2][3][2][19500] = '--alt-preset extreme'; // 3.90, 3.90.1, 3.92
  150. $known_encoder_values['**'][78][3][2][3][2][19600] = '--alt-preset extreme'; // 3.90.2, 3.91
  151. $known_encoder_values['**'][78][3][1][3][2][19600] = '--alt-preset extreme'; // 3.90.3
  152. $known_encoder_values['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme'; // 3.90, 3.90.1, 3.92
  153. $known_encoder_values['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme'; // 3.90.2, 3.90.3, 3.91
  154. $known_encoder_values['**'][78][3][2][3][4][19000] = '--alt-preset standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  155. $known_encoder_values['**'][78][3][1][3][4][19000] = '--alt-preset standard'; // 3.90.3
  156. $known_encoder_values['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  157. $known_encoder_values['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3
  158. $known_encoder_values['**'][88][4][1][3][3][19500] = '--r3mix'; // 3.90, 3.90.1, 3.92
  159. $known_encoder_values['**'][88][4][1][3][3][19600] = '--r3mix'; // 3.90.2, 3.90.3, 3.91
  160. $known_encoder_values['**'][67][4][1][3][4][18000] = '--r3mix'; // 3.94, 3.95
  161. $known_encoder_values['**'][68][3][2][3][4][18000] = '--alt-preset medium'; // 3.90.3
  162. $known_encoder_values['**'][68][4][2][3][4][18000] = '--alt-preset fast medium'; // 3.90.3
  163. $known_encoder_values[0xFF][99][1][1][1][2][0] = '--preset studio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  164. $known_encoder_values[0xFF][58][2][1][3][2][20600] = '--preset studio'; // 3.90.3, 3.93.1
  165. $known_encoder_values[0xFF][58][2][1][3][2][20500] = '--preset studio'; // 3.93
  166. $known_encoder_values[0xFF][57][2][1][3][4][20500] = '--preset studio'; // 3.94, 3.95
  167. $known_encoder_values[0xC0][88][1][1][1][2][0] = '--preset cd'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  168. $known_encoder_values[0xC0][58][2][2][3][2][19600] = '--preset cd'; // 3.90.3, 3.93.1
  169. $known_encoder_values[0xC0][58][2][2][3][2][19500] = '--preset cd'; // 3.93
  170. $known_encoder_values[0xC0][57][2][1][3][4][19500] = '--preset cd'; // 3.94, 3.95
  171. $known_encoder_values[0xA0][78][1][1][3][2][18000] = '--preset hifi'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  172. $known_encoder_values[0xA0][58][2][2][3][2][18000] = '--preset hifi'; // 3.90.3, 3.93, 3.93.1
  173. $known_encoder_values[0xA0][57][2][1][3][4][18000] = '--preset hifi'; // 3.94, 3.95
  174. $known_encoder_values[0x80][67][1][1][3][2][18000] = '--preset tape'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  175. $known_encoder_values[0x80][67][1][1][3][2][15000] = '--preset radio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  176. $known_encoder_values[0x70][67][1][1][3][2][15000] = '--preset fm'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
  177. $known_encoder_values[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm'; // 3.90.3, 3.93, 3.93.1
  178. $known_encoder_values[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm'; // 3.94, 3.95
  179. $known_encoder_values[0x38][58][2][2][0][2][10000] = '--preset voice'; // 3.90.3, 3.93, 3.93.1
  180. $known_encoder_values[0x38][57][2][1][0][4][15000] = '--preset voice'; // 3.94, 3.95
  181. $known_encoder_values[0x38][57][2][1][0][4][16000] = '--preset voice'; // 3.94a14
  182. $known_encoder_values[0x28][65][1][1][0][2][7500] = '--preset mw-us'; // 3.90, 3.90.1, 3.92
  183. $known_encoder_values[0x28][65][1][1][0][2][7600] = '--preset mw-us'; // 3.90.2, 3.91
  184. $known_encoder_values[0x28][58][2][2][0][2][7000] = '--preset mw-us'; // 3.90.3, 3.93, 3.93.1
  185. $known_encoder_values[0x28][57][2][1][0][4][10500] = '--preset mw-us'; // 3.94, 3.95
  186. $known_encoder_values[0x28][57][2][1][0][4][11200] = '--preset mw-us'; // 3.94a14
  187. $known_encoder_values[0x28][57][2][1][0][4][8800] = '--preset mw-us'; // 3.94a15
  188. $known_encoder_values[0x18][58][2][2][0][2][4000] = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1
  189. $known_encoder_values[0x18][58][2][2][0][2][3900] = '--preset phon+/lw/mw-eu/sw'; // 3.93
  190. $known_encoder_values[0x18][57][2][1][0][4][5900] = '--preset phon+/lw/mw-eu/sw'; // 3.94, 3.95
  191. $known_encoder_values[0x18][57][2][1][0][4][6200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a14
  192. $known_encoder_values[0x18][57][2][1][0][4][3200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a15
  193. $known_encoder_values[0x10][58][2][2][0][2][3800] = '--preset phone'; // 3.90.3, 3.93.1
  194. $known_encoder_values[0x10][58][2][2][0][2][3700] = '--preset phone'; // 3.93
  195. $known_encoder_values[0x10][57][2][1][0][4][5600] = '--preset phone'; // 3.94, 3.95
  196. }
  197. if (isset($known_encoder_values[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
  198. $encoder_options = $known_encoder_values[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
  199. } elseif (isset($known_encoder_values['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
  200. $encoder_options = $known_encoder_values['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
  201. } elseif ($info['audio']['bitrate_mode'] == 'vbr') {
  202. // http://gabriel.mp3-tech.org/mp3infotag.html
  203. // int Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h
  204. $lame_v_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10);
  205. $lame_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($lame_v_value * 10);
  206. $encoder_options = '-V'.$lame_v_value.' -q'.$lame_q_value;
  207. } elseif ($info['audio']['bitrate_mode'] == 'cbr') {
  208. $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
  209. } else {
  210. $encoder_options = strtoupper($info['audio']['bitrate_mode']);
  211. }
  212. } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) {
  213. $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr'];
  214. } elseif (!empty($info['audio']['bitrate'])) {
  215. if ($info['audio']['bitrate_mode'] == 'cbr') {
  216. $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
  217. } else {
  218. $encoder_options = strtoupper($info['audio']['bitrate_mode']);
  219. }
  220. }
  221. if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) {
  222. $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min'];
  223. }
  224. if (@$thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] || @$thisfile_mpeg_audio_lame['encoding_flags']['nogap_next']) {
  225. $encoder_options .= ' --nogap';
  226. }
  227. if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) {
  228. $exploded_options = explode(' ', $encoder_options, 4);
  229. if ($exploded_options[0] == '--r3mix') {
  230. $exploded_options[1] = 'r3mix';
  231. }
  232. switch ($exploded_options[0]) {
  233. case '--preset':
  234. case '--alt-preset':
  235. case '--r3mix':
  236. if ($exploded_options[1] == 'fast') {
  237. $exploded_options[1] .= ' '.$exploded_options[2];
  238. }
  239. switch ($exploded_options[1]) {
  240. case 'portable':
  241. case 'medium':
  242. case 'standard':
  243. case 'extreme':
  244. case 'insane':
  245. case 'fast portable':
  246. case 'fast medium':
  247. case 'fast standard':
  248. case 'fast extreme':
  249. case 'fast insane':
  250. case 'r3mix':
  251. static $expected_lowpass = array (
  252. 'insane|20500' => 20500,
  253. 'insane|20600' => 20600, // 3.90.2, 3.90.3, 3.91
  254. 'medium|18000' => 18000,
  255. 'fast medium|18000' => 18000,
  256. 'extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
  257. 'extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
  258. 'fast extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
  259. 'fast extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
  260. 'standard|19000' => 19000,
  261. 'fast standard|19000' => 19000,
  262. 'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92
  263. 'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91
  264. 'r3mix|18000' => 18000, // 3.94, 3.95
  265. );
  266. if (!isset($expected_lowpass[$exploded_options[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) {
  267. $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency'];
  268. }
  269. break;
  270. default:
  271. break;
  272. }
  273. break;
  274. }
  275. }
  276. if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) {
  277. if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) {
  278. $encoder_options .= ' --resample 44100';
  279. } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) {
  280. $encoder_options .= ' --resample 48000';
  281. } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) {
  282. switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) {
  283. case 0: // <= 32000
  284. // may or may not be same as source frequency - ignore
  285. break;
  286. case 1: // 44100
  287. case 2: // 48000
  288. case 3: // 48000+
  289. $exploded_options = explode(' ', $encoder_options, 4);
  290. switch ($exploded_options[0]) {
  291. case '--preset':
  292. case '--alt-preset':
  293. switch ($exploded_options[1]) {
  294. case 'fast':
  295. case 'portable':
  296. case 'medium':
  297. case 'standard':
  298. case 'extreme':
  299. case 'insane':
  300. $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
  301. break;
  302. default:
  303. static $expected_resampled_rate = array (
  304. 'phon+/lw/mw-eu/sw|16000' => 16000,
  305. 'mw-us|24000' => 24000, // 3.95
  306. 'mw-us|32000' => 32000, // 3.93
  307. 'mw-us|16000' => 16000, // 3.92
  308. 'phone|16000' => 16000,
  309. 'phone|11025' => 11025, // 3.94a15
  310. 'radio|32000' => 32000, // 3.94a15
  311. 'fm/radio|32000' => 32000, // 3.92
  312. 'fm|32000' => 32000, // 3.90
  313. 'voice|32000' => 32000);
  314. if (!isset($expected_resampled_rate[$exploded_options[1].'|'.$thisfile_mpeg_audio['sample_rate']])) {
  315. $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
  316. }
  317. break;
  318. }
  319. break;
  320. case '--r3mix':
  321. default:
  322. $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
  323. break;
  324. }
  325. break;
  326. }
  327. }
  328. }
  329. if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) {
  330. //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
  331. $encoder_options = strtoupper($info['audio']['bitrate_mode']);
  332. }
  333. return $encoder_options;
  334. }
  335. public function decodeMPEGaudioHeader($fd, $offset, &$info, $recursive_search=true, $scan_as_cbr=false, $fast_mpeg_header_scan=false) {
  336. static $mpeg_audio_version_lookup;
  337. static $mpeg_audio_layer_lookup;
  338. static $mpeg_audio_bitrate_lookup;
  339. static $mpeg_audio_frequency_lookup;
  340. static $mpeg_audio_channel_mode_lookup;
  341. static $mpeg_audio_mode_extension_lookup;
  342. static $mpeg_audio_emphasis_lookup;
  343. if (empty($mpeg_audio_version_lookup)) {
  344. $mpeg_audio_version_lookup = getid3_mp3::MPEGaudioVersionarray();
  345. $mpeg_audio_layer_lookup = getid3_mp3::MPEGaudioLayerarray();
  346. $mpeg_audio_bitrate_lookup = getid3_mp3::MPEGaudioBitratearray();
  347. $mpeg_audio_frequency_lookup = getid3_mp3::MPEGaudioFrequencyarray();
  348. $mpeg_audio_channel_mode_lookup = getid3_mp3::MPEGaudioChannelModearray();
  349. $mpeg_audio_mode_extension_lookup = getid3_mp3::MPEGaudioModeExtensionarray();
  350. $mpeg_audio_emphasis_lookup = getid3_mp3::MPEGaudioEmphasisarray();
  351. }
  352. if ($offset >= $info['avdataend']) {
  353. // non-fatal error: 'end of file encounter looking for MPEG synch'
  354. return;
  355. }
  356. fseek($fd, $offset, SEEK_SET);
  357. $header_string = fread($fd, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
  358. // MP3 audio frame structure:
  359. // $aa $aa $aa $aa [$bb $bb] $cc...
  360. // where $aa..$aa is the four-byte mpeg-audio header (below)
  361. // $bb $bb is the optional 2-byte CRC
  362. // and $cc... is the audio data
  363. $head4 = substr($header_string, 0, 4);
  364. if (isset($mpeg_audio_header_decode_cache[$head4])) {
  365. $mpeg_header_raw_array= $mpeg_audio_header_decode_cache[$head4];
  366. } else {
  367. $mpeg_header_raw_array = getid3_mp3::MPEGaudioHeaderDecode($head4);
  368. $mpeg_audio_header_decode_cache[$head4] = $mpeg_header_raw_array;
  369. }
  370. // Not in cache
  371. if (!isset($mpeg_audio_header_valid_cache[$head4])) {
  372. $mpeg_audio_header_valid_cache[$head4] = getid3_mp3::MPEGaudioHeaderValid($mpeg_header_raw_array, false, false);
  373. }
  374. // shortcut
  375. if (!isset($info['mpeg']['audio'])) {
  376. $info['mpeg']['audio'] = array ();
  377. }
  378. $thisfile_mpeg_audio = &$info['mpeg']['audio'];
  379. if ($mpeg_audio_header_valid_cache[$head4]) {
  380. $thisfile_mpeg_audio['raw'] = $mpeg_header_raw_array;
  381. } else {
  382. // non-fatal error: Invalid MPEG audio header at offset $offset
  383. return;
  384. }
  385. if (!$fast_mpeg_header_scan) {
  386. $thisfile_mpeg_audio['version'] = $mpeg_audio_version_lookup[$thisfile_mpeg_audio['raw']['version']];
  387. $thisfile_mpeg_audio['layer'] = $mpeg_audio_layer_lookup[$thisfile_mpeg_audio['raw']['layer']];
  388. $thisfile_mpeg_audio['channelmode'] = $mpeg_audio_channel_mode_lookup[$thisfile_mpeg_audio['raw']['channelmode']];
  389. $thisfile_mpeg_audio['channels'] = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2);
  390. $thisfile_mpeg_audio['sample_rate'] = $mpeg_audio_frequency_lookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']];
  391. $thisfile_mpeg_audio['protection'] = !$thisfile_mpeg_audio['raw']['protection'];
  392. $thisfile_mpeg_audio['private'] = (bool) $thisfile_mpeg_audio['raw']['private'];
  393. $thisfile_mpeg_audio['modeextension'] = $mpeg_audio_mode_extension_lookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']];
  394. $thisfile_mpeg_audio['copyright'] = (bool) $thisfile_mpeg_audio['raw']['copyright'];
  395. $thisfile_mpeg_audio['original'] = (bool) $thisfile_mpeg_audio['raw']['original'];
  396. $thisfile_mpeg_audio['emphasis'] = $mpeg_audio_emphasis_lookup[$thisfile_mpeg_audio['raw']['emphasis']];
  397. $info['audio']['channels'] = $thisfile_mpeg_audio['channels'];
  398. $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate'];
  399. if ($thisfile_mpeg_audio['protection']) {
  400. $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($header_string, 4, 2));
  401. }
  402. }
  403. if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) {
  404. // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
  405. $this->getid3->warning('Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1');
  406. $thisfile_mpeg_audio['raw']['bitrate'] = 0;
  407. }
  408. $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding'];
  409. $thisfile_mpeg_audio['bitrate'] = $mpeg_audio_bitrate_lookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']];
  410. if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) {
  411. // only skip multiple frame check if free-format bitstream found at beginning of file
  412. // otherwise is quite possibly simply corrupted data
  413. $recursive_search = false;
  414. }
  415. // For Layer 2 there are some combinations of bitrate and mode which are not allowed.
  416. if (!$fast_mpeg_header_scan && ($thisfile_mpeg_audio['layer'] == '2')) {
  417. $info['audio']['dataformat'] = 'mp2';
  418. switch ($thisfile_mpeg_audio['channelmode']) {
  419. case 'mono':
  420. if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) {
  421. // these are ok
  422. } else {
  423. // non-fatal error: bitrate not allowed in Layer 2/mono
  424. return;
  425. }
  426. break;
  427. case 'stereo':
  428. case 'joint stereo':
  429. case 'dual channel':
  430. if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) {
  431. // these are ok
  432. } else {
  433. // non-fatal error: bitrate not allowed in Layer 2/stereo/joint stereo/dual channel
  434. return;
  435. }
  436. break;
  437. }
  438. }
  439. if ($info['audio']['sample_rate'] > 0) {
  440. $thisfile_mpeg_audio['framelength'] = getid3_mp3::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']);
  441. }
  442. $next_frame_test_offset = $offset + 1;
  443. if ($thisfile_mpeg_audio['bitrate'] != 'free') {
  444. $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
  445. if (isset($thisfile_mpeg_audio['framelength'])) {
  446. $next_frame_test_offset = $offset + $thisfile_mpeg_audio['framelength'];
  447. } else {
  448. // non-fatal error: Frame at offset('.$offset.') is has an invalid frame length.
  449. return;
  450. }
  451. }
  452. $expected_number_of_audio_bytes = 0;
  453. ////////////////////////////////////////////////////////////////////////////////////
  454. // Variable-bitrate headers
  455. if (substr($header_string, 4 + 32, 4) == 'VBRI') {
  456. // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
  457. // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
  458. $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
  459. $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer';
  460. $info['audio']['codec'] = 'Fraunhofer';
  461. $side_info_data = substr($header_string, 4 + 2, 32);
  462. $fraunhofer_vbr_offset = 36;
  463. $thisfile_mpeg_audio['VBR_encoder_version'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 4, 2)); // VbriVersion
  464. $thisfile_mpeg_audio['VBR_encoder_delay'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 6, 2)); // VbriDelay
  465. $thisfile_mpeg_audio['VBR_quality'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 8, 2)); // VbriQuality
  466. $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 10, 4)); // VbriStreamBytes
  467. $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 14, 4)); // VbriStreamFrames
  468. $thisfile_mpeg_audio['VBR_seek_offsets'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 18, 2)); // VbriTableSize
  469. $thisfile_mpeg_audio['VBR_seek_scale'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 20, 2)); // VbriTableScale
  470. $thisfile_mpeg_audio['VBR_entry_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 22, 2)); // VbriEntryBytes
  471. $thisfile_mpeg_audio['VBR_entry_frames'] = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset + 24, 2)); // VbriEntryFrames
  472. $expected_number_of_audio_bytes = $thisfile_mpeg_audio['VBR_bytes'];
  473. $previous_byte_offset = $offset;
  474. for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) {
  475. $fraunhofer_offset_n = getid3_lib::BigEndian2Int(substr($header_string, $fraunhofer_vbr_offset, $thisfile_mpeg_audio['VBR_entry_bytes']));
  476. $fraunhofer_vbr_offset += $thisfile_mpeg_audio['VBR_entry_bytes'];
  477. $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($fraunhofer_offset_n * $thisfile_mpeg_audio['VBR_seek_scale']);
  478. $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($fraunhofer_offset_n * $thisfile_mpeg_audio['VBR_seek_scale']) + $previous_byte_offset;
  479. $previous_byte_offset += $fraunhofer_offset_n;
  480. }
  481. } else {
  482. // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
  483. // depending on MPEG layer and number of channels
  484. $vbr_id_offset = getid3_mp3::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']);
  485. $side_info_data = substr($header_string, 4 + 2, $vbr_id_offset - 4);
  486. if ((substr($header_string, $vbr_id_offset, strlen('Xing')) == 'Xing') || (substr($header_string, $vbr_id_offset, strlen('Info')) == 'Info')) {
  487. // 'Xing' is traditional Xing VBR frame
  488. // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
  489. // 'Info' *can* legally be used to specify a VBR file as well, however.
  490. // http://www.multiweb.cz/twoinches/MP3inside.htm
  491. //00..03 = "Xing" or "Info"
  492. //04..07 = Flags:
  493. // 0x01 Frames Flag set if value for number of frames in file is stored
  494. // 0x02 Bytes Flag set if value for filesize in bytes is stored
  495. // 0x04 TOC Flag set if values for TOC are stored
  496. // 0x08 VBR Scale Flag set if values for VBR scale is stored
  497. //08..11 Frames: Number of frames in file (including the first Xing/Info one)
  498. //12..15 Bytes: File length in Bytes
  499. //16..115 TOC (Table of Contents):
  500. // Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file.
  501. // Each Byte has a value according this formula:
  502. // (TOC[i] / 256) * fileLenInBytes
  503. // So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use:
  504. // TOC[(60/240)*100] = TOC[25]
  505. // and corresponding Byte in file is then approximately at:
  506. // (TOC[25]/256) * 5000000
  507. //116..119 VBR Scale
  508. // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME
  509. $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
  510. $thisfile_mpeg_audio['VBR_method'] = 'Xing';
  511. $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 4, 4));
  512. $thisfile_mpeg_audio['xing_flags']['frames'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001);
  513. $thisfile_mpeg_audio['xing_flags']['bytes'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002);
  514. $thisfile_mpeg_audio['xing_flags']['toc'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004);
  515. $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008);
  516. if ($thisfile_mpeg_audio['xing_flags']['frames']) {
  517. $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 8, 4));
  518. }
  519. if ($thisfile_mpeg_audio['xing_flags']['bytes']) {
  520. $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 12, 4));
  521. }
  522. if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
  523. $frame_lengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames'];
  524. if ($thisfile_mpeg_audio['layer'] == '1') {
  525. // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
  526. $info['audio']['bitrate'] = ($frame_lengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12;
  527. } else {
  528. // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
  529. $info['audio']['bitrate'] = $frame_lengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144;
  530. }
  531. $thisfile_mpeg_audio['framelength'] = floor($frame_lengthfloat);
  532. }
  533. if ($thisfile_mpeg_audio['xing_flags']['toc']) {
  534. $lame_toc_data = substr($header_string, $vbr_id_offset + 16, 100);
  535. for ($i = 0; $i < 100; $i++) {
  536. $thisfile_mpeg_audio['toc'][$i] = ord($lame_toc_data{$i});
  537. }
  538. }
  539. if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) {
  540. $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($header_string, $vbr_id_offset + 116, 4));
  541. }
  542. // http://gabriel.mp3-tech.org/mp3infotag.html
  543. if (substr($header_string, $vbr_id_offset + 120, 4) == 'LAME') {
  544. // shortcut
  545. $thisfile_mpeg_audio['LAME'] = array ();
  546. $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
  547. $thisfile_mpeg_audio_lame['long_version'] = substr($header_string, $vbr_id_offset + 120, 20);
  548. $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
  549. if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
  550. // extra 11 chars are not part of version string when LAMEtag present
  551. unset($thisfile_mpeg_audio_lame['long_version']);
  552. // It the LAME tag was only introduced in LAME v3.90
  553. // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
  554. // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
  555. // are assuming a 'Xing' identifier offset of 0x24, which is the case for
  556. // MPEG-1 non-mono, but not for other combinations
  557. $lame_tag_offset_contant = $vbr_id_offset - 0x24;
  558. // shortcuts
  559. $thisfile_mpeg_audio_lame['RGAD'] = array ('track'=>array(), 'album'=>array());
  560. $thisfile_mpeg_audio_lame_rgad = &$thisfile_mpeg_audio_lame['RGAD'];
  561. $thisfile_mpeg_audio_lame_rgad_track = &$thisfile_mpeg_audio_lame_rgad['track'];
  562. $thisfile_mpeg_audio_lame_rgad_album = &$thisfile_mpeg_audio_lame_rgad['album'];
  563. $thisfile_mpeg_audio_lame['raw'] = array ();
  564. $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw'];
  565. // byte $9B VBR Quality
  566. // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
  567. // Actually overwrites original Xing bytes
  568. unset($thisfile_mpeg_audio['VBR_scale']);
  569. $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0x9B, 1));
  570. // bytes $9C-$A4 Encoder short VersionString
  571. $thisfile_mpeg_audio_lame['short_version'] = substr($header_string, $lame_tag_offset_contant + 0x9C, 9);
  572. // byte $A5 Info Tag revision + VBR method
  573. $lame_tagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xA5, 1));
  574. $thisfile_mpeg_audio_lame['tag_revision'] = ($lame_tagRevisionVBRmethod & 0xF0) >> 4;
  575. $thisfile_mpeg_audio_lame_raw['vbr_method'] = $lame_tagRevisionVBRmethod & 0x0F;
  576. $thisfile_mpeg_audio_lame['vbr_method'] = getid3_mp3::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
  577. $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
  578. // byte $A6 Lowpass filter value
  579. $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xA6, 1)) * 100;
  580. // bytes $A7-$AE Replay Gain
  581. // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
  582. // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
  583. if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
  584. // LAME 3.94a16 and later - 9.23 fixed point
  585. // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
  586. $thisfile_mpeg_audio_lame_rgad['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xA7, 4))) / 8388608);
  587. } else {
  588. // LAME 3.94a15 and earlier - 32-bit floating point
  589. // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
  590. $thisfile_mpeg_audio_lame_rgad['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($header_string, $lame_tag_offset_contant + 0xA7, 4));
  591. }
  592. if ($thisfile_mpeg_audio_lame_rgad['peak_amplitude'] == 0) {
  593. unset($thisfile_mpeg_audio_lame_rgad['peak_amplitude']);
  594. } else {
  595. $thisfile_mpeg_audio_lame_rgad['peak_db'] = 20 * log10($thisfile_mpeg_audio_lame_rgad['peak_amplitude']);
  596. }
  597. $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xAB, 2));
  598. $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xAD, 2));
  599. if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
  600. $thisfile_mpeg_audio_lame_rgad_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
  601. $thisfile_mpeg_audio_lame_rgad_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
  602. $thisfile_mpeg_audio_lame_rgad_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
  603. $thisfile_mpeg_audio_lame_rgad_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
  604. $thisfile_mpeg_audio_lame_rgad_track['name'] = getid3_lib_replaygain::NameLookup($thisfile_mpeg_audio_lame_rgad_track['raw']['name']);
  605. $thisfile_mpeg_audio_lame_rgad_track['originator'] = getid3_lib_replaygain::OriginatorLookup($thisfile_mpeg_audio_lame_rgad_track['raw']['originator']);
  606. $thisfile_mpeg_audio_lame_rgad_track['gain_db'] = getid3_lib_replaygain::AdjustmentLookup($thisfile_mpeg_audio_lame_rgad_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_rgad_track['raw']['sign_bit']);
  607. if (!empty($thisfile_mpeg_audio_lame_rgad['peak_amplitude'])) {
  608. $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_rgad['peak_amplitude'];
  609. }
  610. $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_rgad_track['originator'];
  611. $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_rgad_track['gain_db'];
  612. } else {
  613. unset($thisfile_mpeg_audio_lame_rgad['track']);
  614. }
  615. if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
  616. $thisfile_mpeg_audio_lame_rgad_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
  617. $thisfile_mpeg_audio_lame_rgad_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
  618. $thisfile_mpeg_audio_lame_rgad_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
  619. $thisfile_mpeg_audio_lame_rgad_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
  620. $thisfile_mpeg_audio_lame_rgad_album['name'] = getid3_lib_replaygain::NameLookup($thisfile_mpeg_audio_lame_rgad_album['raw']['name']);
  621. $thisfile_mpeg_audio_lame_rgad_album['originator'] = getid3_lib_replaygain::OriginatorLookup($thisfile_mpeg_audio_lame_rgad_album['raw']['originator']);
  622. $thisfile_mpeg_audio_lame_rgad_album['gain_db'] = getid3_lib_replaygain::AdjustmentLookup($thisfile_mpeg_audio_lame_rgad_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_rgad_album['raw']['sign_bit']);
  623. if (!empty($thisfile_mpeg_audio_lame_rgad['peak_amplitude'])) {
  624. $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_rgad['peak_amplitude'];
  625. }
  626. $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_rgad_album['originator'];
  627. $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_rgad_album['gain_db'];
  628. } else {
  629. unset($thisfile_mpeg_audio_lame_rgad['album']);
  630. }
  631. if (empty($thisfile_mpeg_audio_lame_rgad)) {
  632. unset($thisfile_mpeg_audio_lame['RGAD']);
  633. }
  634. // byte $AF Encoding flags + ATH Type
  635. $encoding_flags_ath_type = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xAF, 1));
  636. $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($encoding_flags_ath_type & 0x10);
  637. $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($encoding_flags_ath_type & 0x20);
  638. $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($encoding_flags_ath_type & 0x40);
  639. $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($encoding_flags_ath_type & 0x80);
  640. $thisfile_mpeg_audio_lame['ath_type'] = $encoding_flags_ath_type & 0x0F;
  641. // byte $B0 if ABR {specified bitrate} else {minimal bitrate}
  642. $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB0, 1));
  643. if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
  644. $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
  645. } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
  646. // ignore
  647. } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
  648. $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
  649. }
  650. // bytes $B1-$B3 Encoder delays
  651. $encoder_delays = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB1, 3));
  652. $thisfile_mpeg_audio_lame['encoder_delay'] = ($encoder_delays & 0xFFF000) >> 12;
  653. $thisfile_mpeg_audio_lame['end_padding'] = $encoder_delays & 0x000FFF;
  654. // byte $B4 Misc
  655. $misc_byte = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB4, 1));
  656. $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($misc_byte & 0x03);
  657. $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($misc_byte & 0x1C) >> 2;
  658. $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($misc_byte & 0x20) >> 5;
  659. $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($misc_byte & 0xC0) >> 6;
  660. $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
  661. $thisfile_mpeg_audio_lame['stereo_mode'] = getid3_mp3::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
  662. $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
  663. $thisfile_mpeg_audio_lame['source_sample_freq'] = getid3_mp3::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
  664. // byte $B5 MP3 Gain
  665. $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB5, 1), false, true);
  666. $thisfile_mpeg_audio_lame['mp3_gain_db'] = (20 * log10(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
  667. $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
  668. // bytes $B6-$B7 Preset and surround info
  669. $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB6, 2));
  670. // Reserved = ($PresetSurroundBytes & 0xC000);
  671. $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
  672. $thisfile_mpeg_audio_lame['surround_info'] = getid3_mp3::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
  673. $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);
  674. $thisfile_mpeg_audio_lame['preset_used'] = getid3_mp3::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
  675. if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
  676. $this->getid3->warning('Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org');
  677. }
  678. if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
  679. // this may change if 3.90.4 ever comes out
  680. $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
  681. }
  682. // bytes $B8-$BB MusicLength
  683. $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xB8, 4));
  684. $expected_number_of_audio_bytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
  685. // bytes $BC-$BD MusicCRC
  686. $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xBC, 2));
  687. // bytes $BE-$BF CRC-16 of Info Tag
  688. $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($header_string, $lame_tag_offset_contant + 0xBE, 2));
  689. // LAME CBR
  690. if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
  691. $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
  692. $thisfile_mpeg_audio['bitrate'] = getid3_mp3::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
  693. $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
  694. }
  695. }
  696. }
  697. } else {
  698. // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
  699. $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
  700. if ($recursive_search) {
  701. $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
  702. if (getid3_mp3::RecursiveFrameScanning($fd, $info, $offset, $next_frame_test_offset, true)) {
  703. $recursive_search = false;
  704. $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
  705. }
  706. if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') {
  707. $this->getid3->warning('VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.');
  708. }
  709. }
  710. }
  711. }
  712. if (($expected_number_of_audio_bytes > 0) && ($expected_number_of_audio_bytes != ($info['avdataend'] - $info['avdataoffset']))) {
  713. if ($expected_number_of_audio_bytes > ($info['avdataend'] - $info['avdataoffset'])) {
  714. if (($expected_number_of_audio_bytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
  715. $this->getid3->warning('Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)');
  716. } else {
  717. $this->getid3->warning('Probable truncated file: expecting '.$expected_number_of_audio_bytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($expected_number_of_audio_bytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)');
  718. }
  719. } else {
  720. if ((($info['avdataend'] - $info['avdataoffset']) - $expected_number_of_audio_bytes) == 1) {
  721. $info['avdataend']--;
  722. } else {
  723. $this->getid3->warning('Too much data in file: expecting '.$expected_number_of_audio_bytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $expected_number_of_audio_bytes).' bytes too many)');
  724. }
  725. }
  726. }
  727. if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) {
  728. if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) {
  729. $frame_byte_length = getid3_mp3::FreeFormatFrameLength($fd, $offset, $info, true);
  730. if ($frame_byte_length > 0) {
  731. $thisfile_mpeg_audio['framelength'] = $frame_byte_length;
  732. if ($thisfile_mpeg_audio['layer'] == '1') {
  733. // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
  734. $info['audio']['bitrate'] = ((($frame_byte_length / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
  735. } else {
  736. // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
  737. $info['audio']['bitrate'] = (($frame_byte_length - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
  738. }
  739. } else {
  740. // non-fatal error: Error calculating frame length of free-format MP3 without Xing/LAME header.
  741. return;
  742. }
  743. }
  744. }
  745. if (@$thisfile_mpeg_audio['VBR_frames']) {
  746. switch ($thisfile_mpeg_audio['bitrate_mode']) {
  747. case 'vbr':
  748. case 'abr':
  749. if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) {
  750. $thisfile_mpeg_audio['VBR_bitrate'] = ((@$thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / 384);
  751. } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) {
  752. $thisfile_mpeg_audio['VBR_bitrate'] = ((@$thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / 576);
  753. } else {
  754. $thisfile_mpeg_audio['VBR_bitrate'] = ((@$thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / 1152);
  755. }
  756. if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) {
  757. $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate'];
  758. $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion
  759. }
  760. break;
  761. }
  762. }
  763. // End variable-bitrate headers
  764. ////////////////////////////////////////////////////////////////////////////////////
  765. if ($recursive_search) {
  766. if (!getid3_mp3::RecursiveFrameScanning($fd, $info, $offset, $next_frame_test_offset, $scan_as_cbr)) {
  767. return false;
  768. }
  769. }
  770. return true;
  771. }
  772. public function RecursiveFrameScanning(&$fd, &$info, &$offset, &$next_frame_test_offset, $scan_as_cbr) {
  773. for ($i = 0; $i < getid3_mp3::VALID_CHECK_FRAMES; $i++) {
  774. // check next getid3_mp3::VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
  775. if (($next_frame_test_offset + 4) >= $info['avdataend']) {
  776. // end of file
  777. return true;
  778. }
  779. $next_frame_test_array = array ('avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
  780. if ($this->decodeMPEGaudioHeader($fd, $next_frame_test_offset, $next_frame_test_array, false)) {
  781. if ($scan_as_cbr) {
  782. // force CBR mode, used for trying to pick out invalid audio streams with
  783. // valid(?) VBR headers, or VBR streams with no VBR header
  784. if (!isset($next_frame_test_array['mpeg']['audio']['bitrate']) || !isset($info['mpeg']['audio']['bitrate']) || ($next_frame_test_array['mpeg']['audio']['bitrate'] != $info['mpeg']['audio']['bitrate'])) {
  785. return false;
  786. }
  787. }
  788. // next frame is OK, get ready to check the one after that
  789. if (isset($next_frame_test_array['mpeg']['audio']['framelength']) && ($next_frame_test_array['mpeg']['audio']['framelength'] > 0)) {
  790. $next_frame_test_offset += $next_frame_test_array['mpeg']['audio']['framelength'];
  791. } else {
  792. // non-fatal error: Frame at offset $offset has an invalid frame length.
  793. return;
  794. }
  795. } else {
  796. // non-fatal error: Next frame is not valid.
  797. return;
  798. }
  799. }
  800. return true;
  801. }
  802. public function FreeFormatFrameLength($fd, $offset, &$info, $deep_scan=false) {
  803. fseek($fd, $offset, SEEK_SET);
  804. $mpeg_audio_data = fread($fd, 32768);
  805. $sync_pattern1 = substr($mpeg_audio_data, 0, 4);
  806. // may be different pattern due to padding
  807. $sync_pattern2 = $sync_pattern1{0}.$sync_pattern1{1}.chr(ord($sync_pattern1{2}) | 0x02).$sync_pattern1{3};
  808. if ($sync_pattern2 === $sync_pattern1) {
  809. $sync_pattern2 = $sync_pattern1{0}.$sync_pattern1{1}.chr(ord($sync_pattern1{2}) & 0xFD).$sync_pattern1{3};
  810. }
  811. $frame_length = false;
  812. $frame_length1 = strpos($mpeg_audio_data, $sync_pattern1, 4);
  813. $frame_length2 = strpos($mpeg_audio_data, $sync_pattern2, 4);
  814. if ($frame_length1 > 4) {
  815. $frame_length = $frame_length1;
  816. }
  817. if (($frame_length2 > 4) && ($frame_length2 < $frame_length1)) {
  818. $frame_length = $frame_length2;
  819. }
  820. if (!$frame_length) {
  821. // LAME 3.88 has a different value for modeextension on the first frame vs the rest
  822. $frame_length1 = strpos($mpeg_audio_data, substr($sync_pattern1, 0, 3), 4);
  823. $frame_length2 = strpos($mpeg_audio_data, substr($sync_pattern2, 0, 3), 4);
  824. if ($frame_length1 > 4) {
  825. $frame_length = $frame_length1;
  826. }
  827. if (($frame_length2 > 4) && ($frame_length2 < $frame_length1)) {
  828. $frame_length = $frame_length2;
  829. }
  830. if (!$frame_length) {
  831. throw new getid3_exception('Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($sync_pattern1).' or '.getid3_lib::PrintHexBytes($sync_pattern2).') after offset '.$offset);
  832. } else {
  833. $this->getid3->warning('ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)');
  834. $info['audio']['codec'] = 'LAME';
  835. $info['audio']['encoder'] = 'LAME3.88';
  836. $sync_pattern1 = substr($sync_pattern1, 0, 3);
  837. $sync_pattern2 = substr($sync_pattern2, 0, 3);
  838. }
  839. }
  840. if ($deep_scan) {
  841. $actual_frame_length_values = array ();
  842. $next_offset = $offset + $frame_length;
  843. while ($next_offset < ($info['avdataend'] - 6)) {
  844. fseek($fd, $next_offset - 1, SEEK_SET);
  845. $NextSyncPattern = fread($fd, 6);
  846. if ((substr($NextSyncPattern, 1, strlen($sync_pattern1)) == $sync_pattern1) || (substr($NextSyncPattern, 1, strlen($sync_pattern2)) == $sync_pattern2)) {
  847. // good - found where expected
  848. $actual_frame_length_values[] = $frame_length;
  849. } elseif ((substr($NextSyncPattern, 0, strlen($sync_pattern1)) == $sync_pattern1) || (substr($NextSyncPattern, 0, strlen($sync_pattern2)) == $sync_pattern2)) {
  850. // ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
  851. $actual_frame_length_values[] = ($frame_length - 1);
  852. $next_offset--;
  853. } elseif ((substr($NextSyncPattern, 2, strlen($sync_pattern1)) == $sync_pattern1) || (substr($NextSyncPattern, 2, strlen($sync_pattern2)) == $sync_pattern2)) {
  854. // ok - found one byte later than expected (last frame was padded, first frame wasn't)
  855. $actual_frame_length_values[] = ($frame_length + 1);
  856. $next_offset++;
  857. } else {
  858. throw new getid3_exception('Did not find expected free-format sync pattern at offset '.$next_offset);
  859. }
  860. $next_offset += $frame_length;
  861. }
  862. if (count($actual_frame_length_values) > 0) {
  863. $frame_length = intval(round(array_sum($actual_frame_length_values) / count($actual_frame_length_values)));
  864. }
  865. }
  866. return $frame_length;
  867. }
  868. public function getOnlyMPEGaudioInfo($fd, &$info, $avdata_offset, $bit_rate_histogram=false) {
  869. // looks for synch, decodes MPEG audio header
  870. fseek($fd, $avdata_offset, SEEK_SET);
  871. $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdata_offset);
  872. $header = fread($fd, $sync_seek_buffer_size);
  873. $sync_seek_buffer_size = strlen($header);
  874. $synch_seek_offset = 0;
  875. static $mpeg_audio_version_lookup;
  876. static $mpeg_audio_layer_lookup;
  877. static $mpeg_audio_bitrate_lookup;
  878. if (empty($mpeg_audio_version_lookup)) {
  879. $mpeg_audio_version_lookup = getid3_mp3::MPEGaudioVersionarray();
  880. $mpeg_audio_layer_lookup = getid3_mp3::MPEGaudioLayerarray();
  881. $mpeg_audio_bitrate_lookup = getid3_mp3::MPEGaudioBitratearray();
  882. }
  883. while ($synch_seek_offset < $sync_seek_buffer_size) {
  884. if ((($avdata_offset + $synch_seek_offset) < $info['avdataend']) && !feof($fd)) {
  885. // if a synch's not found within the first 128k bytes, then give up
  886. if ($synch_seek_offset > $sync_seek_buffer_size) {
  887. throw new getid3_exception('Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB');
  888. }
  889. if (feof($fd)) {
  890. throw new getid3_exception('Could not find valid MPEG audio synch before end of file');
  891. }
  892. }
  893. if (($synch_seek_offset + 1) >= strlen($header)) {
  894. throw new getid3_exception('Could not find valid MPEG synch before end of file');
  895. }
  896. if (($header{$synch_seek_offset} == "\xFF") && ($header{($synch_seek_offset + 1)} > "\xE0")) { // synch detected
  897. if (!isset($first_frame_info) && !isset($info['mpeg']['audio'])) {
  898. $first_frame_info = $info;
  899. $first_frame_avdata_offset = $avdata_offset + $synch_seek_offset;
  900. if (!getid3_mp3::decodeMPEGaudioHeader($fd, $avdata_offset + $synch_seek_offset, $first_frame_info, false)) {
  901. // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
  902. // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
  903. unset($first_frame_info);
  904. }
  905. }
  906. $dummy = $info; // only overwrite real data if valid header found
  907. if (getid3_mp3::decodeMPEGaudioHeader($fd, $avdata_offset + $synch_seek_offset, $dummy, true)) {
  908. $info = $dummy;
  909. $info['avdataoffset'] = $avdata_offset + $synch_seek_offset;
  910. switch (@$info['fileformat']) {
  911. case '':
  912. case 'mp3':
  913. $info['fileformat'] = 'mp3';
  914. $info['audio']['dataformat'] = 'mp3';
  915. break;
  916. }
  917. if (isset($first_frame_info['mpeg']['audio']['bitrate_mode']) && ($first_frame_info['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
  918. if (!(abs($info['audio']['bitrate'] - $first_frame_info['audio']['bitrate']) <= 1)) {
  919. // If there is garbage data between a valid VBR header frame and a sequence
  920. // of valid MPEG-audio frames the VBR data is no longer discarded.
  921. $info = $first_frame_info;
  922. $info['avdataoffset'] = $first_frame_avdata_offset;
  923. $info['fileformat'] = 'mp3';
  924. $info['audio']['dataformat'] = 'mp3';
  925. $dummy = $info;
  926. unset($dummy['mpeg']['audio']);
  927. $GarbageOffsetStart = $first_frame_avdata_offset + $first_frame_info['mpeg']['audio']['framelength'];
  928. $GarbageOffsetEnd = $avdata_offset + $synch_seek_offset;
  929. if (getid3_mp3::decodeMPEGaudioHeader($fd, $GarbageOffsetEnd, $dummy, true, true)) {
  930. $info = $dummy;
  931. $info['avdataoffset'] = $GarbageOffsetEnd;
  932. $this->getid3->warning('apparently-valid VBR header not used because could not find '.getid3_mp3::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);
  933. } else {
  934. $this->getid3->warning('using data from VBR header even though could not find '.getid3_mp3::VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')');
  935. }
  936. }
  937. }
  938. if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) {
  939. // VBR file with no VBR header
  940. $bit_rate_histogram = true;
  941. }
  942. if ($bit_rate_histogram) {
  943. $info['mpeg']['audio']['stereo_distribution'] = array ('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0);
  944. $info['mpeg']['audio']['version_distribution'] = array ('1'=>0, '2'=>0, '2.5'=>0);
  945. if ($info['mpeg']['audio']['version'] == '1') {
  946. if ($info['mpeg']['audio']['layer'] == 3) {
  947. $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0);
  948. } elseif ($info['mpeg']['audio']['layer'] == 2) {
  949. $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0, 384000=>0);
  950. } elseif ($info['mpeg']['audio']['layer'] == 1) {
  951. $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 64000=>0, 96000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 288000=>0, 320000=>0, 352000=>0, 384000=>0, 416000=>0, 448000=>0);
  952. }
  953. } elseif ($info['mpeg']['audio']['layer'] == 1) {
  954. $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0, 176000=>0, 192000=>0, 224000=>0, 256000=>0);
  955. } else {
  956. $info['mpeg']['audio']['bitrate_distribution'] = array ('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0);
  957. }
  958. $dummy = array ('avdataend' => $info['avdataend'], 'avdataoffset' => $info['avdataoffset']);
  959. $synch_start_offset = $info['avdataoffset'];
  960. $fast_mode = false;
  961. $synch_errors_found = 0;
  962. while ($this->decodeMPEGaudioHeader($fd, $synch_start_offset, $dummy, false, false, $fast_mode)) {
  963. $fast_mode = true;
  964. $thisframebitrate = $mpeg_audio_bitrate_lookup[$mpeg_audio_version_lookup[$dummy['mpeg']['audio']['raw']['version']]][$mpeg_audio_layer_lookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
  965. if (empty($dummy['mpeg']['audio']['framelength'])) {
  966. $synch_errors_found++;
  967. }
  968. else {
  969. @$info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]++;
  970. @$info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]++;
  971. @$info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]++;
  972. $synch_start_offset += $dummy['mpeg']['audio']['framelength'];
  973. }
  974. }
  975. if ($synch_errors_found > 0) {
  976. $this->getid3->warning('Found '.$synch_errors_found.' synch errors in histogram analysis');
  977. }
  978. $bit_total = 0;
  979. $frame_counter = 0;
  980. foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bit_rate_value => $bit_rate_count) {
  981. $frame_counter += $bit_rate_count;
  982. if ($bit_rate_value != 'free') {
  983. $bit_total += ($bit_rate_value * $bit_rate_count);
  984. }
  985. }
  986. if ($frame_counter == 0) {
  987. throw new getid3_exception('Corrupt MP3 file: framecounter == zero');
  988. }
  989. $info['mpeg']['audio']['frame_count'] = $frame_counter;
  990. $info['mpeg']['audio']['bitrate'] = ($bit_total / $frame_counter);
  991. $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
  992. // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
  993. $distinct_bit_rates = 0;
  994. foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bit_rate_value => $bit_rate_count) {
  995. if ($bit_rate_count > 0) {
  996. $distinct_bit_rates++;
  997. }
  998. }
  999. if ($distinct_bit_rates > 1) {
  1000. $info['mpeg']['audio']['bitrate_mode'] = 'vbr';
  1001. } else {
  1002. $info['mpeg']['audio']['bitrate_mode'] = 'cbr';
  1003. }
  1004. $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
  1005. }
  1006. break; // exit while()
  1007. }
  1008. }
  1009. $synch_seek_offset++;
  1010. if (($avdata_offset + $synch_seek_offset) >= $info['avdataend']) {
  1011. // end of file/data
  1012. if (empty($info['mpeg']['audio'])) {
  1013. throw new getid3_exception('could not find valid MPEG synch before end of file');
  1014. }
  1015. break;
  1016. }
  1017. }
  1018. $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
  1019. $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode'];
  1020. $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
  1021. return true;
  1022. }
  1023. public static function MPEGaudioVersionarray() {
  1024. static $array = array ('2.5', false, '2', '1');
  1025. return $array;
  1026. }
  1027. public static function MPEGaudioLayerarray() {
  1028. static $array = array (false, 3, 2, 1);
  1029. return $array;
  1030. }
  1031. public static function MPEGaudioBitratearray() {
  1032. static $array;
  1033. if (empty($array)) {
  1034. $array = array (
  1035. '1' => array (1 => array ('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000),
  1036. 2 => array ('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000),
  1037. 3 => array ('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000)
  1038. ),
  1039. '2' => array (1 => array ('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000),
  1040. 2 => array ('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000),
  1041. )
  1042. );
  1043. $array['2'][3] = $array['2'][2];
  1044. $array['2.5'] = $array['2'];
  1045. }
  1046. return $array;
  1047. }
  1048. public static function MPEGaudioFrequencyarray() {
  1049. static $array = array (
  1050. '1' => array (44100, 48000, 32000),
  1051. '2' => array (22050, 24000, 16000),
  1052. '2.5' => array (11025, 12000, 8000)
  1053. );
  1054. return $array;
  1055. }
  1056. public static function MPEGaudioChannelModearray() {
  1057. static $array = array ('stereo', 'joint stereo', 'dual channel', 'mono');
  1058. return $array;
  1059. }
  1060. public static function MPEGaudioModeExtensionarray() {
  1061. static $array = array (
  1062. 1 => array ('4-31', '8-31', '12-31', '16-31'),
  1063. 2 => array ('4-31', '8-31', '12-31', '16-31'),
  1064. 3 => array ('', 'IS', 'MS', 'IS+MS')
  1065. );
  1066. return $array;
  1067. }
  1068. public static function MPEGaudioEmphasisarray() {
  1069. static $array = array ('none', '50/15ms', false, 'CCIT J.17');
  1070. return $array;
  1071. }
  1072. public static function MPEGaudioHeaderBytesValid($head4, $allow_bitrate_15=false) {
  1073. return getid3_mp3::MPEGaudioHeaderValid(getid3_mp3::MPEGaudioHeaderDecode($head4), false, $allow_bitrate_15);
  1074. }
  1075. public static function MPEGaudioHeaderValid($raw_array, $echo_errors=false, $allow_bitrate_15=false) {
  1076. if (($raw_array['synch'] & 0x0FFE) != 0x0FFE) {
  1077. return false;
  1078. }
  1079. static $mpeg_audio_version_lookup;
  1080. static $mpeg_audio_layer_lookup;
  1081. static $mpeg_audio_bitrate_lookup;
  1082. static $mpeg_audio_frequency_lookup;
  1083. static $mpeg_audio_channel_mode_lookup;
  1084. static $mpeg_audio_mode_extension_lookup;
  1085. static $mpeg_audio_emphasis_lookup;
  1086. if (empty($mpeg_audio_version_lookup)) {
  1087. $mpeg_audio_version_lookup = getid3_mp3::MPEGaudioVersionarray();
  1088. $mpeg_audio_layer_lookup = getid3_mp3::MPEGaudioLayerarray();
  1089. $mpeg_audio_bitrate_lookup = getid3_mp3::MPEGaudioBitratearray();
  1090. $mpeg_audio_frequency_lookup = getid3_mp3::MPEGaudioFrequencyarray();
  1091. $mpeg_audio_channel_mode_lookup = getid3_mp3::MPEGaudioChannelModearray();
  1092. $mpeg_audio_mode_extension_lookup = getid3_mp3::MPEGaudioModeExtensionarray();
  1093. $mpeg_audio_emphasis_lookup = getid3_mp3::MPEGaudioEmphasisarray();
  1094. }
  1095. if (isset($mpeg_audio_version_lookup[$raw_array['version']])) {
  1096. $decodedVersion = $mpeg_audio_version_lookup[$raw_array['version']];
  1097. } else {
  1098. echo ($echo_errors ? "\n".'invalid Version ('.$raw_array['version'].')' : '');
  1099. return false;
  1100. }
  1101. if (isset($mpeg_audio_layer_lookup[$raw_array['layer']])) {
  1102. $decodedLayer = $mpeg_audio_layer_lookup[$raw_array['layer']];
  1103. } else {
  1104. echo ($echo_errors ? "\n".'invalid Layer ('.$raw_array['layer'].')' : '');
  1105. return false;
  1106. }
  1107. if (!isset($mpeg_audio_bitrate_lookup[$decodedVersion][$decodedLayer][$raw_array['bitrate']])) {
  1108. echo ($echo_errors ? "\n".'invalid Bitrate ('.$raw_array['bitrate'].')' : '');
  1109. if ($raw_array['bitrate'] == 15) {
  1110. // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
  1111. // let it go through here otherwise file will not be identified
  1112. if (!$allow_bitrate_15) {
  1113. return false;
  1114. }
  1115. } else {
  1116. return false;
  1117. }
  1118. }
  1119. if (!isset($mpeg_audio_frequency_lookup[$decodedVersion][$raw_array['sample_rate']])) {
  1120. echo ($echo_errors ? "\n".'invalid Frequency ('.$raw_array['sample_rate'].')' : '');
  1121. return false;
  1122. }
  1123. if (!isset($mpeg_audio_channel_mode_lookup[$raw_array['channelmode']])) {
  1124. echo ($echo_errors ? "\n".'invalid ChannelMode ('.$raw_array['channelmode'].')' : '');
  1125. return false;
  1126. }
  1127. if (!isset($mpeg_audio_mode_extension_lookup[$decodedLayer][$raw_array['modeextension']])) {
  1128. echo ($echo_errors ? "\n".'invalid Mode Extension ('.$raw_array['modeextension'].')' : '');
  1129. return false;
  1130. }
  1131. if (!isset($mpeg_audio_emphasis_lookup[$raw_array['emphasis']])) {
  1132. echo ($echo_errors ? "\n".'invalid Emphasis ('.$raw_array['emphasis'].')' : '');
  1133. return false;
  1134. }
  1135. // These are just either set or not set, you can't mess that up :)
  1136. // $raw_array['protection'];
  1137. // $raw_array['padding'];
  1138. // $raw_array['private'];
  1139. // $raw_array['copyright'];
  1140. // $raw_array['original'];
  1141. return true;
  1142. }
  1143. public static function MPEGaudioHeaderDecode($header_four_bytes) {
  1144. // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
  1145. // A - Frame sync (all bits set)
  1146. // B - MPEG Audio version ID
  1147. // C - Layer description
  1148. // D - Protection bit
  1149. // E - Bitrate index
  1150. // F - Sampling rate frequency index
  1151. // G - Padding bit
  1152. // H - Private bit
  1153. // I - Channel Mode
  1154. // J - Mode extension (Only if Joint stereo)
  1155. // K - Copyright
  1156. // L - Original
  1157. // M - Emphasis
  1158. if (strlen($header_four_bytes) != 4) {
  1159. return false;
  1160. }
  1161. $mpeg_raw_header['synch'] = (getid3_lib::BigEndian2Int(substr($header_four_bytes, 0, 2)) & 0xFFE0) >> 4;
  1162. $mpeg_raw_header['version'] = (ord($header_four_bytes{1}) & 0x18) >> 3; // BB
  1163. $mpeg_raw_header['layer'] = (ord($header_four_bytes{1}) & 0x06) >> 1; // CC
  1164. $mpeg_raw_header['protection'] = (ord($header_four_bytes{1}) & 0x01); // D
  1165. $mpeg_raw_header['bitrate'] = (ord($header_four_bytes{2}) & 0xF0) >> 4; // EEEE
  1166. $mpeg_raw_header['sample_rate'] = (ord($header_four_bytes{2}) & 0x0C) >> 2; // FF
  1167. $mpeg_raw_header['padding'] = (ord($header_four_bytes{2}) & 0x02) >> 1; // G
  1168. $mpeg_raw_header['private'] = (ord($header_four_bytes{2}) & 0x01); // H
  1169. $mpeg_raw_header['channelmode'] = (ord($header_four_bytes{3}) & 0xC0) >> 6; // II
  1170. $mpeg_raw_header['modeextension'] = (ord($header_four_bytes{3}) & 0x30) >> 4; // JJ
  1171. $mpeg_raw_header['copyright'] = (ord($header_four_bytes{3}) & 0x08) >> 3; // K
  1172. $mpeg_raw_header['original'] = (ord($header_four_bytes{3}) & 0x04) >> 2; // L
  1173. $mpeg_raw_header['emphasis'] = (ord($header_four_bytes{3}) & 0x03); // MM
  1174. return $mpeg_raw_header;
  1175. }
  1176. public static function MPEGaudioFrameLength(&$bit_rate, &$version, &$layer, $padding, &$sample_rate) {
  1177. if (!isset($cache[$bit_rate][$version][$layer][$padding][$sample_rate])) {
  1178. $cache[$bit_rate][$version][$layer][$padding][$sample_rate] = false;
  1179. if ($bit_rate != 'free') {
  1180. if ($version == '1') {
  1181. if ($layer == '1') {
  1182. // For Layer I slot is 32 bits long
  1183. $frame_length_coefficient = 48;
  1184. $slot_length = 4;
  1185. } else { // Layer 2 / 3
  1186. // for Layer 2 and Layer 3 slot is 8 bits long.
  1187. $frame_length_coefficient = 144;
  1188. $slot_length = 1;
  1189. }
  1190. } else { // MPEG-2 / MPEG-2.5
  1191. if ($layer == '1') {
  1192. // For Layer I slot is 32 bits long
  1193. $frame_length_coefficient = 24;
  1194. $slot_length = 4;
  1195. } elseif ($layer == '2') {
  1196. // for Layer 2 and Layer 3 slot is 8 bits long.
  1197. $frame_length_coefficient = 144;
  1198. $slot_length = 1;
  1199. } else { // layer 3
  1200. // for Layer 2 and Layer 3 slot is 8 bits long.
  1201. $frame_length_coefficient = 72;
  1202. $slot_length = 1;
  1203. }
  1204. }
  1205. // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
  1206. if ($sample_rate > 0) {
  1207. $new_frame_length = ($frame_length_coefficient * $bit_rate) / $sample_rate;
  1208. $new_frame_length = floor($new_frame_length / $slot_length) * $slot_length; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I)
  1209. if ($padding) {
  1210. $new_frame_length += $slot_length;
  1211. }
  1212. $cache[$bit_rate][$version][$layer][$padding][$sample_rate] = (int) $new_frame_length;
  1213. }
  1214. }
  1215. }
  1216. return $cache[$bit_rate][$version][$layer][$padding][$sample_rate];
  1217. }
  1218. public static function ClosestStandardMP3Bitrate($bit_rate) {
  1219. static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
  1220. static $bit_rate_table = array (0=>'-');
  1221. $round_bit_rate = intval(round($bit_rate, -3));
  1222. if (!isset($bit_rate_table[$round_bit_rate])) {
  1223. if ($round_bit_rate > 320000) {
  1224. $bit_rate_table[$round_bit_rate] = round($bit_rate, -4);
  1225. } else {
  1226. $last_bit_rate = 320000;
  1227. foreach ($standard_bit_rates as $standard_bit_rate) {
  1228. $bit_rate_table[$round_bit_rate] = $standard_bit_rate;
  1229. if ($round_bit_rate >= $standard_bit_rate - (($last_bit_rate - $standard_bit_rate) / 2)) {
  1230. break;
  1231. }
  1232. $last_bit_rate = $standard_bit_rate;
  1233. }
  1234. }
  1235. }
  1236. return $bit_rate_table[$round_bit_rate];
  1237. }
  1238. public static function XingVBRidOffset($version, $channel_mode) {
  1239. static $lookup = array (
  1240. '1' => array ('mono' => 0x15, // 4 + 17 = 21
  1241. 'stereo' => 0x24, // 4 + 32 = 36
  1242. 'joint stereo' => 0x24,
  1243. 'dual channel' => 0x24
  1244. ),
  1245. '2' => array ('mono' => 0x0D, // 4 + 9 = 13
  1246. 'stereo' => 0x15, // 4 + 17 = 21
  1247. 'joint stereo' => 0x15,
  1248. 'dual channel' => 0x15
  1249. ),
  1250. '2.5' => array ('mono' => 0x15,
  1251. 'stereo' => 0x15,
  1252. 'joint stereo' => 0x15,
  1253. 'dual channel' => 0x15
  1254. )
  1255. );
  1256. return $lookup[$version][$channel_mode];
  1257. }
  1258. public static function LAMEvbrMethodLookup($vbr_method_id) {
  1259. static $lookup = array (
  1260. 0x00 => 'unknown',
  1261. 0x01 => 'cbr',
  1262. 0x02 => 'abr',
  1263. 0x03 => 'vbr-old / vbr-rh',
  1264. 0x04 => 'vbr-new / vbr-mtrh',
  1265. 0x05 => 'vbr-mt',
  1266. 0x06 => 'Full VBR Method 4',
  1267. 0x08 => 'constant bitrate 2 pass',
  1268. 0x09 => 'abr 2 pass',
  1269. 0x0F => 'reserved'
  1270. );
  1271. return (isset($lookup[$vbr_method_id]) ? $lookup[$vbr_method_id] : '');
  1272. }
  1273. public static function LAMEmiscStereoModeLookup($stereo_mode_id) {
  1274. static $lookup = array (
  1275. 0 => 'mono',
  1276. 1 => 'stereo',
  1277. 2 => 'dual mono',
  1278. 3 => 'joint stereo',
  1279. 4 => 'forced stereo',
  1280. 5 => 'auto',
  1281. 6 => 'intensity stereo',
  1282. 7 => 'other'
  1283. );
  1284. return (isset($lookup[$stereo_mode_id]) ? $lookup[$stereo_mode_id] : '');
  1285. }
  1286. public static function LAMEmiscSourceSampleFrequencyLookup($source_sample_frequency_id) {
  1287. static $lookup = array (
  1288. 0 => '<= 32 kHz',
  1289. 1 => '44.1 kHz',
  1290. 2 => '48 kHz',
  1291. 3 => '> 48kHz'
  1292. );
  1293. return (isset($lookup[$source_sample_frequency_id]) ? $lookup[$source_sample_frequency_id] : '');
  1294. }
  1295. public static function LAMEsurroundInfoLookup($surround_info_id) {
  1296. static $lookup = array (
  1297. 0 => 'no surround info',
  1298. 1 => 'DPL encoding',
  1299. 2 => 'DPL2 encoding',
  1300. 3 => 'Ambisonic encoding'
  1301. );
  1302. return (isset($lookup[$surround_info_id]) ? $lookup[$surround_info_id] : 'reserved');
  1303. }
  1304. public static function LAMEpresetUsedLookup($lame_tag) {
  1305. if ($lame_tag['preset_used_id'] == 0) {
  1306. // no preset used (LAME >=3.93)
  1307. // no preset recorded (LAME <3.93)
  1308. return '';
  1309. }
  1310. $lame_preset_used_lookup = array ();
  1311. for ($i = 8; $i <= 320; $i++) {
  1312. switch ($lame_tag['vbr_method']) {
  1313. case 'cbr':
  1314. $lame_preset_used_lookup[$i] = '--alt-preset '.$lame_tag['vbr_method'].' '.$i;
  1315. break;
  1316. case 'abr':
  1317. default: // other VBR modes shouldn't be here(?)
  1318. $lame_preset_used_lookup[$i] = '--alt-preset '.$i;
  1319. break;
  1320. }
  1321. }
  1322. // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()
  1323. // named alt-presets
  1324. $lame_preset_used_lookup[1000] = '--r3mix';
  1325. $lame_preset_used_lookup[1001] = '--alt-preset standard';
  1326. $lame_preset_used_lookup[1002] = '--alt-preset extreme';
  1327. $lame_preset_used_lookup[1003] = '--alt-preset insane';
  1328. $lame_preset_used_lookup[1004] = '--alt-preset fast standard';
  1329. $lame_preset_used_lookup[1005] = '--alt-preset fast extreme';
  1330. $lame_preset_used_lookup[1006] = '--alt-preset medium';
  1331. $lame_preset_used_lookup[1007] = '--alt-preset fast medium';
  1332. // LAME 3.94 additions/changes
  1333. $lame_preset_used_lookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003
  1334. $lame_preset_used_lookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003
  1335. $lame_preset_used_lookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003
  1336. $lame_preset_used_lookup[410] = '-V9';
  1337. $lame_preset_used_lookup[420] = '-V8';
  1338. $lame_preset_used_lookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003
  1339. $lame_preset_used_lookup[440] = '-V6';
  1340. $lame_preset_used_lookup[450] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003
  1341. $lame_preset_used_lookup[460] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003
  1342. $lame_preset_used_lookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003
  1343. $lame_preset_used_lookup[480] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003
  1344. $lame_preset_used_lookup[490] = '-V1';
  1345. $lame_preset_used_lookup[500] = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003
  1346. return (isset($lame_preset_used_lookup[$lame_tag['preset_used_id']]) ? $lame_preset_used_lookup[$lame_tag['preset_used_id']] : 'new/unknown preset: '.$lame_tag['preset_used_id'].' - report to info@getid3.org');
  1347. }
  1348. }
  1349. ?>