[ Index ]

WordPress Cross Reference

title

Body

[close]

/wp-includes/ID3/ -> module.audio.mp3.php (source)

   1  <?php
   2  /////////////////////////////////////////////////////////////////
   3  /// getID3() by James Heinrich <info@getid3.org>               //
   4  //  available at http://getid3.sourceforge.net                 //
   5  //            or http://www.getid3.org                         //
   6  /////////////////////////////////////////////////////////////////
   7  // See readme.txt for more details                             //
   8  /////////////////////////////////////////////////////////////////
   9  //                                                             //
  10  // module.audio.mp3.php                                        //
  11  // module for analyzing MP3 files                              //
  12  // dependencies: NONE                                          //
  13  //                                                            ///
  14  /////////////////////////////////////////////////////////////////
  15  
  16  
  17  // number of frames to scan to determine if MPEG-audio sequence is valid
  18  // Lower this number to 5-20 for faster scanning
  19  // Increase this number to 50+ for most accurate detection of valid VBR/CBR
  20  // mpeg-audio streams
  21  define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
  22  
  23  
  24  class getid3_mp3 extends getid3_handler
  25  {
  26  
  27      public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files
  28  
  29  	public function Analyze() {
  30          $info = &$this->getid3->info;
  31  
  32          $initialOffset = $info['avdataoffset'];
  33  
  34          if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) {
  35              if ($this->allow_bruteforce) {
  36                  $info['error'][] = 'Rescanning file in BruteForce mode';
  37                  $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info);
  38              }
  39          }
  40  
  41  
  42          if (isset($info['mpeg']['audio']['bitrate_mode'])) {
  43              $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
  44          }
  45  
  46          if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
  47  
  48              $synchoffsetwarning = 'Unknown data before synch ';
  49              if (isset($info['id3v2']['headerlength'])) {
  50                  $synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, ';
  51              } elseif ($initialOffset > 0) {
  52                  $synchoffsetwarning .= '(should be at '.$initialOffset.', ';
  53              } else {
  54                  $synchoffsetwarning .= '(should be at beginning of file, ';
  55              }
  56              $synchoffsetwarning .= 'synch detected at '.$info['avdataoffset'].')';
  57              if (isset($info['audio']['bitrate_mode']) && ($info['audio']['bitrate_mode'] == 'cbr')) {
  58  
  59                  if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) {
  60  
  61                      $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.';
  62                      $info['audio']['codec'] = 'LAME';
  63                      $CurrentDataLAMEversionString = 'LAME3.';
  64  
  65                  } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) {
  66  
  67                      $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.';
  68                      $info['audio']['codec'] = 'LAME';
  69                      $CurrentDataLAMEversionString = 'LAME3.';
  70  
  71                  }
  72  
  73              }
  74              $info['warning'][] = $synchoffsetwarning;
  75  
  76          }
  77  
  78          if (isset($info['mpeg']['audio']['LAME'])) {
  79              $info['audio']['codec'] = 'LAME';
  80              if (!empty($info['mpeg']['audio']['LAME']['long_version'])) {
  81                  $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00");
  82              } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) {
  83                  $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00");
  84              }
  85          }
  86  
  87          $CurrentDataLAMEversionString = (!empty($CurrentDataLAMEversionString) ? $CurrentDataLAMEversionString : (isset($info['audio']['encoder']) ? $info['audio']['encoder'] : ''));
  88          if (!empty($CurrentDataLAMEversionString) && (substr($CurrentDataLAMEversionString, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($CurrentDataLAMEversionString, -1))) {
  89              // a version number of LAME that does not end with a number like "LAME3.92"
  90              // or with a closing parenthesis like "LAME3.88 (alpha)"
  91              // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92)
  92  
  93              // not sure what the actual last frame length will be, but will be less than or equal to 1441
  94              $PossiblyLongerLAMEversion_FrameLength = 1441;
  95  
  96              // Not sure what version of LAME this is - look in padding of last frame for longer version string
  97              $PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength;
  98              fseek($this->getid3->fp, $PossibleLAMEversionStringOffset);
  99              $PossiblyLongerLAMEversion_Data = fread($this->getid3->fp, $PossiblyLongerLAMEversion_FrameLength);
 100              switch (substr($CurrentDataLAMEversionString, -1)) {
 101                  case 'a':
 102                  case 'b':
 103                      // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
 104                      // need to trim off "a" to match longer string
 105                      $CurrentDataLAMEversionString = substr($CurrentDataLAMEversionString, 0, -1);
 106                      break;
 107              }
 108              if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) {
 109                  if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
 110                      $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3"  "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
 111                      if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
 112                          $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
 113                      }
 114                  }
 115              }
 116          }
 117          if (!empty($info['audio']['encoder'])) {
 118              $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 ");
 119          }
 120  
 121          switch (isset($info['mpeg']['audio']['layer']) ? $info['mpeg']['audio']['layer'] : '') {
 122              case 1:
 123              case 2:
 124                  $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
 125                  break;
 126          }
 127          if (isset($info['fileformat']) && ($info['fileformat'] == 'mp3')) {
 128              switch ($info['audio']['dataformat']) {
 129                  case 'mp1':
 130                  case 'mp2':
 131                  case 'mp3':
 132                      $info['fileformat'] = $info['audio']['dataformat'];
 133                      break;
 134  
 135                  default:
 136                      $info['warning'][] = 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"';
 137                      break;
 138              }
 139          }
 140  
 141          if (empty($info['fileformat'])) {
 142              unset($info['fileformat']);
 143              unset($info['audio']['bitrate_mode']);
 144              unset($info['avdataoffset']);
 145              unset($info['avdataend']);
 146              return false;
 147          }
 148  
 149          $info['mime_type']         = 'audio/mpeg';
 150          $info['audio']['lossless'] = false;
 151  
 152          // Calculate playtime
 153          if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
 154              $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
 155          }
 156  
 157          $info['audio']['encoder_options'] = $this->GuessEncoderOptions();
 158  
 159          return true;
 160      }
 161  
 162  
 163  	public function GuessEncoderOptions() {
 164          // shortcuts
 165          $info = &$this->getid3->info;
 166          if (!empty($info['mpeg']['audio'])) {
 167              $thisfile_mpeg_audio = &$info['mpeg']['audio'];
 168              if (!empty($thisfile_mpeg_audio['LAME'])) {
 169                  $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
 170              }
 171          }
 172  
 173          $encoder_options = '';
 174          static $NamedPresetBitrates = array(16, 24, 40, 56, 112, 128, 160, 192, 256);
 175  
 176          if (isset($thisfile_mpeg_audio['VBR_method']) && ($thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) {
 177  
 178              $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
 179  
 180          } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
 181  
 182              $encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
 183  
 184          } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) {
 185  
 186              static $KnownEncoderValues = array();
 187              if (empty($KnownEncoderValues)) {
 188  
 189                  //$KnownEncoderValues[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name';
 190                  $KnownEncoderValues[0xFF][58][1][1][3][2][20500] = '--alt-preset insane';        // 3.90,   3.90.1, 3.92
 191                  $KnownEncoderValues[0xFF][58][1][1][3][2][20600] = '--alt-preset insane';        // 3.90.2, 3.90.3, 3.91
 192                  $KnownEncoderValues[0xFF][57][1][1][3][4][20500] = '--alt-preset insane';        // 3.94,   3.95
 193                  $KnownEncoderValues['**'][78][3][2][3][2][19500] = '--alt-preset extreme';       // 3.90,   3.90.1, 3.92
 194                  $KnownEncoderValues['**'][78][3][2][3][2][19600] = '--alt-preset extreme';       // 3.90.2, 3.91
 195                  $KnownEncoderValues['**'][78][3][1][3][2][19600] = '--alt-preset extreme';       // 3.90.3
 196                  $KnownEncoderValues['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme';  // 3.90,   3.90.1, 3.92
 197                  $KnownEncoderValues['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme';  // 3.90.2, 3.90.3, 3.91
 198                  $KnownEncoderValues['**'][78][3][2][3][4][19000] = '--alt-preset standard';      // 3.90,   3.90.1, 3.90.2, 3.91, 3.92
 199                  $KnownEncoderValues['**'][78][3][1][3][4][19000] = '--alt-preset standard';      // 3.90.3
 200                  $KnownEncoderValues['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90,   3.90.1, 3.90.2, 3.91, 3.92
 201                  $KnownEncoderValues['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3
 202                  $KnownEncoderValues['**'][88][4][1][3][3][19500] = '--r3mix';                    // 3.90,   3.90.1, 3.92
 203                  $KnownEncoderValues['**'][88][4][1][3][3][19600] = '--r3mix';                    // 3.90.2, 3.90.3, 3.91
 204                  $KnownEncoderValues['**'][67][4][1][3][4][18000] = '--r3mix';                    // 3.94,   3.95
 205                  $KnownEncoderValues['**'][68][3][2][3][4][18000] = '--alt-preset medium';        // 3.90.3
 206                  $KnownEncoderValues['**'][68][4][2][3][4][18000] = '--alt-preset fast medium';   // 3.90.3
 207  
 208                  $KnownEncoderValues[0xFF][99][1][1][1][2][0]     = '--preset studio';            // 3.90,   3.90.1, 3.90.2, 3.91, 3.92
 209                  $KnownEncoderValues[0xFF][58][2][1][3][2][20600] = '--preset studio';            // 3.90.3, 3.93.1
 210                  $KnownEncoderValues[0xFF][58][2][1][3][2][20500] = '--preset studio';            // 3.93
 211                  $KnownEncoderValues[0xFF][57][2][1][3][4][20500] = '--preset studio';            // 3.94,   3.95
 212                  $KnownEncoderValues[0xC0][88][1][1][1][2][0]     = '--preset cd';                // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
 213                  $KnownEncoderValues[0xC0][58][2][2][3][2][19600] = '--preset cd';                // 3.90.3, 3.93.1
 214                  $KnownEncoderValues[0xC0][58][2][2][3][2][19500] = '--preset cd';                // 3.93
 215                  $KnownEncoderValues[0xC0][57][2][1][3][4][19500] = '--preset cd';                // 3.94,   3.95
 216                  $KnownEncoderValues[0xA0][78][1][1][3][2][18000] = '--preset hifi';              // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
 217                  $KnownEncoderValues[0xA0][58][2][2][3][2][18000] = '--preset hifi';              // 3.90.3, 3.93,   3.93.1
 218                  $KnownEncoderValues[0xA0][57][2][1][3][4][18000] = '--preset hifi';              // 3.94,   3.95
 219                  $KnownEncoderValues[0x80][67][1][1][3][2][18000] = '--preset tape';              // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
 220                  $KnownEncoderValues[0x80][67][1][1][3][2][15000] = '--preset radio';             // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
 221                  $KnownEncoderValues[0x70][67][1][1][3][2][15000] = '--preset fm';                // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
 222                  $KnownEncoderValues[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm';     // 3.90.3, 3.93,   3.93.1
 223                  $KnownEncoderValues[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm';     // 3.94,   3.95
 224                  $KnownEncoderValues[0x38][58][2][2][0][2][10000] = '--preset voice';             // 3.90.3, 3.93,   3.93.1
 225                  $KnownEncoderValues[0x38][57][2][1][0][4][15000] = '--preset voice';             // 3.94,   3.95
 226                  $KnownEncoderValues[0x38][57][2][1][0][4][16000] = '--preset voice';             // 3.94a14
 227                  $KnownEncoderValues[0x28][65][1][1][0][2][7500]  = '--preset mw-us';             // 3.90,   3.90.1, 3.92
 228                  $KnownEncoderValues[0x28][65][1][1][0][2][7600]  = '--preset mw-us';             // 3.90.2, 3.91
 229                  $KnownEncoderValues[0x28][58][2][2][0][2][7000]  = '--preset mw-us';             // 3.90.3, 3.93,   3.93.1
 230                  $KnownEncoderValues[0x28][57][2][1][0][4][10500] = '--preset mw-us';             // 3.94,   3.95
 231                  $KnownEncoderValues[0x28][57][2][1][0][4][11200] = '--preset mw-us';             // 3.94a14
 232                  $KnownEncoderValues[0x28][57][2][1][0][4][8800]  = '--preset mw-us';             // 3.94a15
 233                  $KnownEncoderValues[0x18][58][2][2][0][2][4000]  = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1
 234                  $KnownEncoderValues[0x18][58][2][2][0][2][3900]  = '--preset phon+/lw/mw-eu/sw'; // 3.93
 235                  $KnownEncoderValues[0x18][57][2][1][0][4][5900]  = '--preset phon+/lw/mw-eu/sw'; // 3.94,   3.95
 236                  $KnownEncoderValues[0x18][57][2][1][0][4][6200]  = '--preset phon+/lw/mw-eu/sw'; // 3.94a14
 237                  $KnownEncoderValues[0x18][57][2][1][0][4][3200]  = '--preset phon+/lw/mw-eu/sw'; // 3.94a15
 238                  $KnownEncoderValues[0x10][58][2][2][0][2][3800]  = '--preset phone';             // 3.90.3, 3.93.1
 239                  $KnownEncoderValues[0x10][58][2][2][0][2][3700]  = '--preset phone';             // 3.93
 240                  $KnownEncoderValues[0x10][57][2][1][0][4][5600]  = '--preset phone';             // 3.94,   3.95
 241              }
 242  
 243              if (isset($KnownEncoderValues[$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']])) {
 244  
 245                  $encoder_options = $KnownEncoderValues[$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']];
 246  
 247              } elseif (isset($KnownEncoderValues['**'][$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']])) {
 248  
 249                  $encoder_options = $KnownEncoderValues['**'][$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']];
 250  
 251              } elseif ($info['audio']['bitrate_mode'] == 'vbr') {
 252  
 253                  // http://gabriel.mp3-tech.org/mp3infotag.html
 254                  // int    Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h
 255  
 256  
 257                  $LAME_V_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10);
 258                  $LAME_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($LAME_V_value * 10);
 259                  $encoder_options = '-V'.$LAME_V_value.' -q'.$LAME_q_value;
 260  
 261              } elseif ($info['audio']['bitrate_mode'] == 'cbr') {
 262  
 263                  $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
 264  
 265              } else {
 266  
 267                  $encoder_options = strtoupper($info['audio']['bitrate_mode']);
 268  
 269              }
 270  
 271          } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) {
 272  
 273              $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr'];
 274  
 275          } elseif (!empty($info['audio']['bitrate'])) {
 276  
 277              if ($info['audio']['bitrate_mode'] == 'cbr') {
 278                  $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
 279              } else {
 280                  $encoder_options = strtoupper($info['audio']['bitrate_mode']);
 281              }
 282  
 283          }
 284          if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) {
 285              $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min'];
 286          }
 287  
 288          if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) {
 289              $encoder_options .= ' --nogap';
 290          }
 291  
 292          if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) {
 293              $ExplodedOptions = explode(' ', $encoder_options, 4);
 294              if ($ExplodedOptions[0] == '--r3mix') {
 295                  $ExplodedOptions[1] = 'r3mix';
 296              }
 297              switch ($ExplodedOptions[0]) {
 298                  case '--preset':
 299                  case '--alt-preset':
 300                  case '--r3mix':
 301                      if ($ExplodedOptions[1] == 'fast') {
 302                          $ExplodedOptions[1] .= ' '.$ExplodedOptions[2];
 303                      }
 304                      switch ($ExplodedOptions[1]) {
 305                          case 'portable':
 306                          case 'medium':
 307                          case 'standard':
 308                          case 'extreme':
 309                          case 'insane':
 310                          case 'fast portable':
 311                          case 'fast medium':
 312                          case 'fast standard':
 313                          case 'fast extreme':
 314                          case 'fast insane':
 315                          case 'r3mix':
 316                              static $ExpectedLowpass = array(
 317                                      'insane|20500'        => 20500,
 318                                      'insane|20600'        => 20600,  // 3.90.2, 3.90.3, 3.91
 319                                      'medium|18000'        => 18000,
 320                                      'fast medium|18000'   => 18000,
 321                                      'extreme|19500'       => 19500,  // 3.90,   3.90.1, 3.92, 3.95
 322                                      'extreme|19600'       => 19600,  // 3.90.2, 3.90.3, 3.91, 3.93.1
 323                                      'fast extreme|19500'  => 19500,  // 3.90,   3.90.1, 3.92, 3.95
 324                                      'fast extreme|19600'  => 19600,  // 3.90.2, 3.90.3, 3.91, 3.93.1
 325                                      'standard|19000'      => 19000,
 326                                      'fast standard|19000' => 19000,
 327                                      'r3mix|19500'         => 19500,  // 3.90,   3.90.1, 3.92
 328                                      'r3mix|19600'         => 19600,  // 3.90.2, 3.90.3, 3.91
 329                                      'r3mix|18000'         => 18000,  // 3.94,   3.95
 330                                  );
 331                              if (!isset($ExpectedLowpass[$ExplodedOptions[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))) {
 332                                  $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency'];
 333                              }
 334                              break;
 335  
 336                          default:
 337                              break;
 338                      }
 339                      break;
 340              }
 341          }
 342  
 343          if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) {
 344              if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) {
 345                  $encoder_options .= ' --resample 44100';
 346              } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) {
 347                  $encoder_options .= ' --resample 48000';
 348              } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) {
 349                  switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) {
 350                      case 0: // <= 32000
 351                          // may or may not be same as source frequency - ignore
 352                          break;
 353                      case 1: // 44100
 354                      case 2: // 48000
 355                      case 3: // 48000+
 356                          $ExplodedOptions = explode(' ', $encoder_options, 4);
 357                          switch ($ExplodedOptions[0]) {
 358                              case '--preset':
 359                              case '--alt-preset':
 360                                  switch ($ExplodedOptions[1]) {
 361                                      case 'fast':
 362                                      case 'portable':
 363                                      case 'medium':
 364                                      case 'standard':
 365                                      case 'extreme':
 366                                      case 'insane':
 367                                          $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
 368                                          break;
 369  
 370                                      default:
 371                                          static $ExpectedResampledRate = array(
 372                                                  'phon+/lw/mw-eu/sw|16000' => 16000,
 373                                                  'mw-us|24000'             => 24000, // 3.95
 374                                                  'mw-us|32000'             => 32000, // 3.93
 375                                                  'mw-us|16000'             => 16000, // 3.92
 376                                                  'phone|16000'             => 16000,
 377                                                  'phone|11025'             => 11025, // 3.94a15
 378                                                  'radio|32000'             => 32000, // 3.94a15
 379                                                  'fm/radio|32000'          => 32000, // 3.92
 380                                                  'fm|32000'                => 32000, // 3.90
 381                                                  'voice|32000'             => 32000);
 382                                          if (!isset($ExpectedResampledRate[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio['sample_rate']])) {
 383                                              $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
 384                                          }
 385                                          break;
 386                                  }
 387                                  break;
 388  
 389                              case '--r3mix':
 390                              default:
 391                                  $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
 392                                  break;
 393                          }
 394                          break;
 395                  }
 396              }
 397          }
 398          if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) {
 399              //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
 400              $encoder_options = strtoupper($info['audio']['bitrate_mode']);
 401          }
 402  
 403          return $encoder_options;
 404      }
 405  
 406  
 407  	public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) {
 408          static $MPEGaudioVersionLookup;
 409          static $MPEGaudioLayerLookup;
 410          static $MPEGaudioBitrateLookup;
 411          static $MPEGaudioFrequencyLookup;
 412          static $MPEGaudioChannelModeLookup;
 413          static $MPEGaudioModeExtensionLookup;
 414          static $MPEGaudioEmphasisLookup;
 415          if (empty($MPEGaudioVersionLookup)) {
 416              $MPEGaudioVersionLookup       = self::MPEGaudioVersionArray();
 417              $MPEGaudioLayerLookup         = self::MPEGaudioLayerArray();
 418              $MPEGaudioBitrateLookup       = self::MPEGaudioBitrateArray();
 419              $MPEGaudioFrequencyLookup     = self::MPEGaudioFrequencyArray();
 420              $MPEGaudioChannelModeLookup   = self::MPEGaudioChannelModeArray();
 421              $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
 422              $MPEGaudioEmphasisLookup      = self::MPEGaudioEmphasisArray();
 423          }
 424  
 425          if (fseek($this->getid3->fp, $offset, SEEK_SET) != 0) {
 426              $info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;
 427              return false;
 428          }
 429          //$headerstring = fread($this->getid3->fp, 1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
 430          $headerstring = fread($this->getid3->fp, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
 431  
 432          // MP3 audio frame structure:
 433          // $aa $aa $aa $aa [$bb $bb] $cc...
 434          // where $aa..$aa is the four-byte mpeg-audio header (below)
 435          // $bb $bb is the optional 2-byte CRC
 436          // and $cc... is the audio data
 437  
 438          $head4 = substr($headerstring, 0, 4);
 439  
 440          static $MPEGaudioHeaderDecodeCache = array();
 441          if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
 442              $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
 443          } else {
 444              $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4);
 445              $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
 446          }
 447  
 448          static $MPEGaudioHeaderValidCache = array();
 449          if (!isset($MPEGaudioHeaderValidCache[$head4])) { // Not in cache
 450              //$MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true);  // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1)
 451              $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false);
 452          }
 453  
 454          // shortcut
 455          if (!isset($info['mpeg']['audio'])) {
 456              $info['mpeg']['audio'] = array();
 457          }
 458          $thisfile_mpeg_audio = &$info['mpeg']['audio'];
 459  
 460  
 461          if ($MPEGaudioHeaderValidCache[$head4]) {
 462              $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
 463          } else {
 464              $info['error'][] = 'Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset;
 465              return false;
 466          }
 467  
 468          if (!$FastMPEGheaderScan) {
 469              $thisfile_mpeg_audio['version']       = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']];
 470              $thisfile_mpeg_audio['layer']         = $MPEGaudioLayerLookup[$thisfile_mpeg_audio['raw']['layer']];
 471  
 472              $thisfile_mpeg_audio['channelmode']   = $MPEGaudioChannelModeLookup[$thisfile_mpeg_audio['raw']['channelmode']];
 473              $thisfile_mpeg_audio['channels']      = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2);
 474              $thisfile_mpeg_audio['sample_rate']   = $MPEGaudioFrequencyLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']];
 475              $thisfile_mpeg_audio['protection']    = !$thisfile_mpeg_audio['raw']['protection'];
 476              $thisfile_mpeg_audio['private']       = (bool) $thisfile_mpeg_audio['raw']['private'];
 477              $thisfile_mpeg_audio['modeextension'] = $MPEGaudioModeExtensionLookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']];
 478              $thisfile_mpeg_audio['copyright']     = (bool) $thisfile_mpeg_audio['raw']['copyright'];
 479              $thisfile_mpeg_audio['original']      = (bool) $thisfile_mpeg_audio['raw']['original'];
 480              $thisfile_mpeg_audio['emphasis']      = $MPEGaudioEmphasisLookup[$thisfile_mpeg_audio['raw']['emphasis']];
 481  
 482              $info['audio']['channels']    = $thisfile_mpeg_audio['channels'];
 483              $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate'];
 484  
 485              if ($thisfile_mpeg_audio['protection']) {
 486                  $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($headerstring, 4, 2));
 487              }
 488          }
 489  
 490          if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) {
 491              // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
 492              $info['warning'][] = 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';
 493              $thisfile_mpeg_audio['raw']['bitrate'] = 0;
 494          }
 495          $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding'];
 496          $thisfile_mpeg_audio['bitrate'] = $MPEGaudioBitrateLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']];
 497  
 498          if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) {
 499              // only skip multiple frame check if free-format bitstream found at beginning of file
 500              // otherwise is quite possibly simply corrupted data
 501              $recursivesearch = false;
 502          }
 503  
 504          // For Layer 2 there are some combinations of bitrate and mode which are not allowed.
 505          if (!$FastMPEGheaderScan && ($thisfile_mpeg_audio['layer'] == '2')) {
 506  
 507              $info['audio']['dataformat'] = 'mp2';
 508              switch ($thisfile_mpeg_audio['channelmode']) {
 509  
 510                  case 'mono':
 511                      if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) {
 512                          // these are ok
 513                      } else {
 514                          $info['error'][] = $thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
 515                          return false;
 516                      }
 517                      break;
 518  
 519                  case 'stereo':
 520                  case 'joint stereo':
 521                  case 'dual channel':
 522                      if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) {
 523                          // these are ok
 524                      } else {
 525                          $info['error'][] = intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
 526                          return false;
 527                      }
 528                      break;
 529  
 530              }
 531  
 532          }
 533  
 534  
 535          if ($info['audio']['sample_rate'] > 0) {
 536              $thisfile_mpeg_audio['framelength'] = self::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']);
 537          }
 538  
 539          $nextframetestoffset = $offset + 1;
 540          if ($thisfile_mpeg_audio['bitrate'] != 'free') {
 541  
 542              $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
 543  
 544              if (isset($thisfile_mpeg_audio['framelength'])) {
 545                  $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength'];
 546              } else {
 547                  $info['error'][] = 'Frame at offset('.$offset.') is has an invalid frame length.';
 548                  return false;
 549              }
 550  
 551          }
 552  
 553          $ExpectedNumberOfAudioBytes = 0;
 554  
 555          ////////////////////////////////////////////////////////////////////////////////////
 556          // Variable-bitrate headers
 557  
 558          if (substr($headerstring, 4 + 32, 4) == 'VBRI') {
 559              // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
 560              // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
 561  
 562              $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
 563              $thisfile_mpeg_audio['VBR_method']   = 'Fraunhofer';
 564              $info['audio']['codec']                = 'Fraunhofer';
 565  
 566              $SideInfoData = substr($headerstring, 4 + 2, 32);
 567  
 568              $FraunhoferVBROffset = 36;
 569  
 570              $thisfile_mpeg_audio['VBR_encoder_version']     = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset +  4, 2)); // VbriVersion
 571              $thisfile_mpeg_audio['VBR_encoder_delay']       = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset +  6, 2)); // VbriDelay
 572              $thisfile_mpeg_audio['VBR_quality']             = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset +  8, 2)); // VbriQuality
 573              $thisfile_mpeg_audio['VBR_bytes']               = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4)); // VbriStreamBytes
 574              $thisfile_mpeg_audio['VBR_frames']              = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4)); // VbriStreamFrames
 575              $thisfile_mpeg_audio['VBR_seek_offsets']        = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2)); // VbriTableSize
 576              $thisfile_mpeg_audio['VBR_seek_scale']          = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 2)); // VbriTableScale
 577              $thisfile_mpeg_audio['VBR_entry_bytes']         = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 22, 2)); // VbriEntryBytes
 578              $thisfile_mpeg_audio['VBR_entry_frames']        = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2)); // VbriEntryFrames
 579  
 580              $ExpectedNumberOfAudioBytes = $thisfile_mpeg_audio['VBR_bytes'];
 581  
 582              $previousbyteoffset = $offset;
 583              for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) {
 584                  $Fraunhofer_OffsetN = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, $thisfile_mpeg_audio['VBR_entry_bytes']));
 585                  $FraunhoferVBROffset += $thisfile_mpeg_audio['VBR_entry_bytes'];
 586                  $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']);
 587                  $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']) + $previousbyteoffset;
 588                  $previousbyteoffset += $Fraunhofer_OffsetN;
 589              }
 590  
 591  
 592          } else {
 593  
 594              // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
 595              // depending on MPEG layer and number of channels
 596  
 597              $VBRidOffset = self::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']);
 598              $SideInfoData = substr($headerstring, 4 + 2, $VBRidOffset - 4);
 599  
 600              if ((substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing') || (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info')) {
 601                  // 'Xing' is traditional Xing VBR frame
 602                  // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
 603                  // 'Info' *can* legally be used to specify a VBR file as well, however.
 604  
 605                  // http://www.multiweb.cz/twoinches/MP3inside.htm
 606                  //00..03 = "Xing" or "Info"
 607                  //04..07 = Flags:
 608                  //  0x01  Frames Flag     set if value for number of frames in file is stored
 609                  //  0x02  Bytes Flag      set if value for filesize in bytes is stored
 610                  //  0x04  TOC Flag        set if values for TOC are stored
 611                  //  0x08  VBR Scale Flag  set if values for VBR scale is stored
 612                  //08..11  Frames: Number of frames in file (including the first Xing/Info one)
 613                  //12..15  Bytes:  File length in Bytes
 614                  //16..115  TOC (Table of Contents):
 615                  //  Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file.
 616                  //  Each Byte has a value according this formula:
 617                  //  (TOC[i] / 256) * fileLenInBytes
 618                  //  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:
 619                  //  TOC[(60/240)*100] = TOC[25]
 620                  //  and corresponding Byte in file is then approximately at:
 621                  //  (TOC[25]/256) * 5000000
 622                  //116..119  VBR Scale
 623  
 624  
 625                  // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME
 626  //                if (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Xing') {
 627                      $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
 628                      $thisfile_mpeg_audio['VBR_method']   = 'Xing';
 629  //                } else {
 630  //                    $ScanAsCBR = true;
 631  //                    $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
 632  //                }
 633  
 634                  $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4));
 635  
 636                  $thisfile_mpeg_audio['xing_flags']['frames']    = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001);
 637                  $thisfile_mpeg_audio['xing_flags']['bytes']     = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002);
 638                  $thisfile_mpeg_audio['xing_flags']['toc']       = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004);
 639                  $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008);
 640  
 641                  if ($thisfile_mpeg_audio['xing_flags']['frames']) {
 642                      $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset +  8, 4));
 643                      //$thisfile_mpeg_audio['VBR_frames']--; // don't count header Xing/Info frame
 644                  }
 645                  if ($thisfile_mpeg_audio['xing_flags']['bytes']) {
 646                      $thisfile_mpeg_audio['VBR_bytes']  = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4));
 647                  }
 648  
 649                  //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
 650                  if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
 651  
 652                      $framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames'];
 653  
 654                      if ($thisfile_mpeg_audio['layer'] == '1') {
 655                          // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
 656                          //$info['audio']['bitrate'] = ((($framelengthfloat / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
 657                          $info['audio']['bitrate'] = ($framelengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12;
 658                      } else {
 659                          // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
 660                          //$info['audio']['bitrate'] = (($framelengthfloat - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
 661                          $info['audio']['bitrate'] = $framelengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144;
 662                      }
 663                      $thisfile_mpeg_audio['framelength'] = floor($framelengthfloat);
 664                  }
 665  
 666                  if ($thisfile_mpeg_audio['xing_flags']['toc']) {
 667                      $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
 668                      for ($i = 0; $i < 100; $i++) {
 669                          $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i});
 670                      }
 671                  }
 672                  if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) {
 673                      $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4));
 674                  }
 675  
 676  
 677                  // http://gabriel.mp3-tech.org/mp3infotag.html
 678                  if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME') {
 679  
 680                      // shortcut
 681                      $thisfile_mpeg_audio['LAME'] = array();
 682                      $thisfile_mpeg_audio_lame    = &$thisfile_mpeg_audio['LAME'];
 683  
 684  
 685                      $thisfile_mpeg_audio_lame['long_version']  = substr($headerstring, $VBRidOffset + 120, 20);
 686                      $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
 687  
 688                      if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
 689  
 690                          // extra 11 chars are not part of version string when LAMEtag present
 691                          unset($thisfile_mpeg_audio_lame['long_version']);
 692  
 693                          // It the LAME tag was only introduced in LAME v3.90
 694                          // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
 695  
 696                          // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
 697                          // are assuming a 'Xing' identifier offset of 0x24, which is the case for
 698                          // MPEG-1 non-mono, but not for other combinations
 699                          $LAMEtagOffsetContant = $VBRidOffset - 0x24;
 700  
 701                          // shortcuts
 702                          $thisfile_mpeg_audio_lame['RGAD']    = array('track'=>array(), 'album'=>array());
 703                          $thisfile_mpeg_audio_lame_RGAD       = &$thisfile_mpeg_audio_lame['RGAD'];
 704                          $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
 705                          $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
 706                          $thisfile_mpeg_audio_lame['raw'] = array();
 707                          $thisfile_mpeg_audio_lame_raw    = &$thisfile_mpeg_audio_lame['raw'];
 708  
 709                          // byte $9B  VBR Quality
 710                          // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
 711                          // Actually overwrites original Xing bytes
 712                          unset($thisfile_mpeg_audio['VBR_scale']);
 713                          $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
 714  
 715                          // bytes $9C-$A4  Encoder short VersionString
 716                          $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
 717  
 718                          // byte $A5  Info Tag revision + VBR method
 719                          $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
 720  
 721                          $thisfile_mpeg_audio_lame['tag_revision']   = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
 722                          $thisfile_mpeg_audio_lame_raw['vbr_method'] =  $LAMEtagRevisionVBRmethod & 0x0F;
 723                          $thisfile_mpeg_audio_lame['vbr_method']     = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
 724                          $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'
 725  
 726                          // byte $A6  Lowpass filter value
 727                          $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
 728  
 729                          // bytes $A7-$AE  Replay Gain
 730                          // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
 731                          // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
 732                          if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
 733                              // LAME 3.94a16 and later - 9.23 fixed point
 734                              // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
 735                              $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
 736                          } else {
 737                              // LAME 3.94a15 and earlier - 32-bit floating point
 738                              // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
 739                              $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
 740                          }
 741                          if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
 742                              unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
 743                          } else {
 744                              $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
 745                          }
 746  
 747                          $thisfile_mpeg_audio_lame_raw['RGAD_track']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
 748                          $thisfile_mpeg_audio_lame_raw['RGAD_album']      =   getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
 749  
 750  
 751                          if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
 752  
 753                              $thisfile_mpeg_audio_lame_RGAD_track['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
 754                              $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
 755                              $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
 756                              $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
 757                              $thisfile_mpeg_audio_lame_RGAD_track['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
 758                              $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
 759                              $thisfile_mpeg_audio_lame_RGAD_track['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
 760  
 761                              if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
 762                                  $info['replay_gain']['track']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
 763                              }
 764                              $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
 765                              $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
 766                          } else {
 767                              unset($thisfile_mpeg_audio_lame_RGAD['track']);
 768                          }
 769                          if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
 770  
 771                              $thisfile_mpeg_audio_lame_RGAD_album['raw']['name']        = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
 772                              $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
 773                              $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
 774                              $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
 775                              $thisfile_mpeg_audio_lame_RGAD_album['name']       = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
 776                              $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
 777                              $thisfile_mpeg_audio_lame_RGAD_album['gain_db']    = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
 778  
 779                              if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
 780                                  $info['replay_gain']['album']['peak']   = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
 781                              }
 782                              $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
 783                              $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
 784                          } else {
 785                              unset($thisfile_mpeg_audio_lame_RGAD['album']);
 786                          }
 787                          if (empty($thisfile_mpeg_audio_lame_RGAD)) {
 788                              unset($thisfile_mpeg_audio_lame['RGAD']);
 789                          }
 790  
 791  
 792                          // byte $AF  Encoding flags + ATH Type
 793                          $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
 794                          $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune']   = (bool) ($EncodingFlagsATHtype & 0x10);
 795                          $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
 796                          $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next']  = (bool) ($EncodingFlagsATHtype & 0x40);
 797                          $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']  = (bool) ($EncodingFlagsATHtype & 0x80);
 798                          $thisfile_mpeg_audio_lame['ath_type']                      =         $EncodingFlagsATHtype & 0x0F;
 799  
 800                          // byte $B0  if ABR {specified bitrate} else {minimal bitrate}
 801                          $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
 802                          if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
 803                              $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
 804                          } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
 805                              // ignore
 806                          } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
 807                              $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
 808                          }
 809  
 810                          // bytes $B1-$B3  Encoder delays
 811                          $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
 812                          $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
 813                          $thisfile_mpeg_audio_lame['end_padding']   =  $EncoderDelays & 0x000FFF;
 814  
 815                          // byte $B4  Misc
 816                          $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
 817                          $thisfile_mpeg_audio_lame_raw['noise_shaping']       = ($MiscByte & 0x03);
 818                          $thisfile_mpeg_audio_lame_raw['stereo_mode']         = ($MiscByte & 0x1C) >> 2;
 819                          $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
 820                          $thisfile_mpeg_audio_lame_raw['source_sample_freq']  = ($MiscByte & 0xC0) >> 6;
 821                          $thisfile_mpeg_audio_lame['noise_shaping']       = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
 822                          $thisfile_mpeg_audio_lame['stereo_mode']         = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
 823                          $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
 824                          $thisfile_mpeg_audio_lame['source_sample_freq']  = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
 825  
 826                          // byte $B5  MP3 Gain
 827                          $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
 828                          $thisfile_mpeg_audio_lame['mp3_gain_db']     = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
 829                          $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
 830  
 831                          // bytes $B6-$B7  Preset and surround info
 832                          $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
 833                          // Reserved                                                    = ($PresetSurroundBytes & 0xC000);
 834                          $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
 835                          $thisfile_mpeg_audio_lame['surround_info']     = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
 836                          $thisfile_mpeg_audio_lame['preset_used_id']    = ($PresetSurroundBytes & 0x07FF);
 837                          $thisfile_mpeg_audio_lame['preset_used']       = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
 838                          if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
 839                              $info['warning'][] = 'Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org';
 840                          }
 841                          if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
 842                              // this may change if 3.90.4 ever comes out
 843                              $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
 844                          }
 845  
 846                          // bytes $B8-$BB  MusicLength
 847                          $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
 848                          $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
 849  
 850                          // bytes $BC-$BD  MusicCRC
 851                          $thisfile_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
 852  
 853                          // bytes $BE-$BF  CRC-16 of Info Tag
 854                          $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
 855  
 856  
 857                          // LAME CBR
 858                          if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
 859  
 860                              $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
 861                              $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
 862                              $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
 863                              //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
 864                              //    $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
 865                              //}
 866  
 867                          }
 868  
 869                      }
 870                  }
 871  
 872              } else {
 873  
 874                  // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
 875                  $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
 876                  if ($recursivesearch) {
 877                      $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
 878                      if ($this->RecursiveFrameScanning($offset, $nextframetestoffset, true)) {
 879                          $recursivesearch = false;
 880                          $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
 881                      }
 882                      if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') {
 883                          $info['warning'][] = 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
 884                      }
 885                  }
 886  
 887              }
 888  
 889          }
 890  
 891          if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) {
 892              if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) {
 893                  if (isset($info['fileformat']) && ($info['fileformat'] == 'riff')) {
 894                      // ignore, audio data is broken into chunks so will always be data "missing"
 895                  } elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
 896                      $info['warning'][] = 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)';
 897                  } else {
 898                      $info['warning'][] = 'Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)';
 899                  }
 900              } else {
 901                  if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) {
 902                  //    $prenullbytefileoffset = ftell($this->getid3->fp);
 903                  //    fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
 904                  //    $PossibleNullByte = fread($this->getid3->fp, 1);
 905                  //    fseek($this->getid3->fp, $prenullbytefileoffset, SEEK_SET);
 906                  //    if ($PossibleNullByte === "\x00") {
 907                          $info['avdataend']--;
 908                  //        $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
 909                  //    } else {
 910                  //        $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
 911                  //    }
 912                  } else {
 913                      $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
 914                  }
 915              }
 916          }
 917  
 918          if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) {
 919              if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) {
 920                  $framebytelength = $this->FreeFormatFrameLength($offset, true);
 921                  if ($framebytelength > 0) {
 922                      $thisfile_mpeg_audio['framelength'] = $framebytelength;
 923                      if ($thisfile_mpeg_audio['layer'] == '1') {
 924                          // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
 925                          $info['audio']['bitrate'] = ((($framebytelength / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
 926                      } else {
 927                          // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
 928                          $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
 929                      }
 930                  } else {
 931                      $info['error'][] = 'Error calculating frame length of free-format MP3 without Xing/LAME header';
 932                  }
 933              }
 934          }
 935  
 936          if (isset($thisfile_mpeg_audio['VBR_frames']) ? $thisfile_mpeg_audio['VBR_frames'] : '') {
 937              switch ($thisfile_mpeg_audio['bitrate_mode']) {
 938                  case 'vbr':
 939                  case 'abr':
 940                      $bytes_per_frame = 1152;
 941                      if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) {
 942                          $bytes_per_frame = 384;
 943                      } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) {
 944                          $bytes_per_frame = 576;
 945                      }
 946                      $thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0);
 947                      if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) {
 948                          $info['audio']['bitrate']         = $thisfile_mpeg_audio['VBR_bitrate'];
 949                          $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion
 950                      }
 951                      break;
 952              }
 953          }
 954  
 955          // End variable-bitrate headers
 956          ////////////////////////////////////////////////////////////////////////////////////
 957  
 958          if ($recursivesearch) {
 959  
 960              if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
 961                  return false;
 962              }
 963  
 964          }
 965  
 966  
 967          //if (false) {
 968          //    // experimental side info parsing section - not returning anything useful yet
 969          //
 970          //    $SideInfoBitstream = getid3_lib::BigEndian2Bin($SideInfoData);
 971          //    $SideInfoOffset = 0;
 972          //
 973          //    if ($thisfile_mpeg_audio['version'] == '1') {
 974          //        if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
 975          //            // MPEG-1 (mono)
 976          //            $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
 977          //            $SideInfoOffset += 9;
 978          //            $SideInfoOffset += 5;
 979          //        } else {
 980          //            // MPEG-1 (stereo, joint-stereo, dual-channel)
 981          //            $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
 982          //            $SideInfoOffset += 9;
 983          //            $SideInfoOffset += 3;
 984          //        }
 985          //    } else { // 2 or 2.5
 986          //        if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
 987          //            // MPEG-2, MPEG-2.5 (mono)
 988          //            $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
 989          //            $SideInfoOffset += 8;
 990          //            $SideInfoOffset += 1;
 991          //        } else {
 992          //            // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
 993          //            $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
 994          //            $SideInfoOffset += 8;
 995          //            $SideInfoOffset += 2;
 996          //        }
 997          //    }
 998          //
 999          //    if ($thisfile_mpeg_audio['version'] == '1') {
1000          //        for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
1001          //            for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
1002          //                $thisfile_mpeg_audio['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1003          //                $SideInfoOffset += 2;
1004          //            }
1005          //        }
1006          //    }
1007          //    for ($granule = 0; $granule < (($thisfile_mpeg_audio['version'] == '1') ? 2 : 1); $granule++) {
1008          //        for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
1009          //            $thisfile_mpeg_audio['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
1010          //            $SideInfoOffset += 12;
1011          //            $thisfile_mpeg_audio['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
1012          //            $SideInfoOffset += 9;
1013          //            $thisfile_mpeg_audio['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
1014          //            $SideInfoOffset += 8;
1015          //            if ($thisfile_mpeg_audio['version'] == '1') {
1016          //                $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
1017          //                $SideInfoOffset += 4;
1018          //            } else {
1019          //                $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
1020          //                $SideInfoOffset += 9;
1021          //            }
1022          //            $thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1023          //            $SideInfoOffset += 1;
1024          //
1025          //            if ($thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] == '1') {
1026          //
1027          //                $thisfile_mpeg_audio['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
1028          //                $SideInfoOffset += 2;
1029          //                $thisfile_mpeg_audio['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1030          //                $SideInfoOffset += 1;
1031          //
1032          //                for ($region = 0; $region < 2; $region++) {
1033          //                    $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
1034          //                    $SideInfoOffset += 5;
1035          //                }
1036          //                $thisfile_mpeg_audio['table_select'][$granule][$channel][2] = 0;
1037          //
1038          //                for ($window = 0; $window < 3; $window++) {
1039          //                    $thisfile_mpeg_audio['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
1040          //                    $SideInfoOffset += 3;
1041          //                }
1042          //
1043          //            } else {
1044          //
1045          //                for ($region = 0; $region < 3; $region++) {
1046          //                    $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
1047          //                    $SideInfoOffset += 5;
1048          //                }
1049          //
1050          //                $thisfile_mpeg_audio['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
1051          //                $SideInfoOffset += 4;
1052          //                $thisfile_mpeg_audio['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
1053          //                $SideInfoOffset += 3;
1054          //                $thisfile_mpeg_audio['block_type'][$granule][$channel] = 0;
1055          //            }
1056          //
1057          //            if ($thisfile_mpeg_audio['version'] == '1') {
1058          //                $thisfile_mpeg_audio['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1059          //                $SideInfoOffset += 1;
1060          //            }
1061          //            $thisfile_mpeg_audio['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1062          //            $SideInfoOffset += 1;
1063          //            $thisfile_mpeg_audio['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
1064          //            $SideInfoOffset += 1;
1065          //        }
1066          //    }
1067          //}
1068  
1069          return true;
1070      }
1071  
1072  	public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
1073          $info = &$this->getid3->info;
1074          $firstframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1075          $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
1076  
1077          for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
1078              // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
1079              if (($nextframetestoffset + 4) >= $info['avdataend']) {
1080                  // end of file
1081                  return true;
1082              }
1083  
1084              $nextframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1085              if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
1086                  if ($ScanAsCBR) {
1087                      // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
1088                      if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
1089                          return false;
1090                      }
1091                  }
1092  
1093  
1094                  // next frame is OK, get ready to check the one after that
1095                  if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) {
1096                      $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength'];
1097                  } else {
1098                      $info['error'][] = 'Frame at offset ('.$offset.') is has an invalid frame length.';
1099                      return false;
1100                  }
1101  
1102              } elseif (!empty($firstframetestarray['mpeg']['audio']['framelength']) && (($nextframetestoffset + $firstframetestarray['mpeg']['audio']['framelength']) > $info['avdataend'])) {
1103  
1104                  // it's not the end of the file, but there's not enough data left for another frame, so assume it's garbage/padding and return OK
1105                  return true;
1106  
1107              } else {
1108  
1109                  // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
1110                  $info['warning'][] = 'Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.';
1111  
1112                  return false;
1113              }
1114          }
1115          return true;
1116      }
1117  
1118  	public function FreeFormatFrameLength($offset, $deepscan=false) {
1119          $info = &$this->getid3->info;
1120  
1121          fseek($this->getid3->fp, $offset, SEEK_SET);
1122          $MPEGaudioData = fread($this->getid3->fp, 32768);
1123  
1124          $SyncPattern1 = substr($MPEGaudioData, 0, 4);
1125          // may be different pattern due to padding
1126          $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
1127          if ($SyncPattern2 === $SyncPattern1) {
1128              $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};
1129          }
1130  
1131          $framelength = false;
1132          $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4);
1133          $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4);
1134          if ($framelength1 > 4) {
1135              $framelength = $framelength1;
1136          }
1137          if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
1138              $framelength = $framelength2;
1139          }
1140          if (!$framelength) {
1141  
1142              // LAME 3.88 has a different value for modeextension on the first frame vs the rest
1143              $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4);
1144              $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4);
1145  
1146              if ($framelength1 > 4) {
1147                  $framelength = $framelength1;
1148              }
1149              if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
1150                  $framelength = $framelength2;
1151              }
1152              if (!$framelength) {
1153                  $info['error'][] = 'Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset;
1154                  return false;
1155              } else {
1156                  $info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)';
1157                  $info['audio']['codec']   = 'LAME';
1158                  $info['audio']['encoder'] = 'LAME3.88';
1159                  $SyncPattern1 = substr($SyncPattern1, 0, 3);
1160                  $SyncPattern2 = substr($SyncPattern2, 0, 3);
1161              }
1162          }
1163  
1164          if ($deepscan) {
1165  
1166              $ActualFrameLengthValues = array();
1167              $nextoffset = $offset + $framelength;
1168              while ($nextoffset < ($info['avdataend'] - 6)) {
1169                  fseek($this->getid3->fp, $nextoffset - 1, SEEK_SET);
1170                  $NextSyncPattern = fread($this->getid3->fp, 6);
1171                  if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) {
1172                      // good - found where expected
1173                      $ActualFrameLengthValues[] = $framelength;
1174                  } elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) {
1175                      // ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
1176                      $ActualFrameLengthValues[] = ($framelength - 1);
1177                      $nextoffset--;
1178                  } elseif ((substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2)) {
1179                      // ok - found one byte later than expected (last frame was padded, first frame wasn't)
1180                      $ActualFrameLengthValues[] = ($framelength + 1);
1181                      $nextoffset++;
1182                  } else {
1183                      $info['error'][] = 'Did not find expected free-format sync pattern at offset '.$nextoffset;
1184                      return false;
1185                  }
1186                  $nextoffset += $framelength;
1187              }
1188              if (count($ActualFrameLengthValues) > 0) {
1189                  $framelength = intval(round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues)));
1190              }
1191          }
1192          return $framelength;
1193      }
1194  
1195  	public function getOnlyMPEGaudioInfoBruteForce() {
1196          $MPEGaudioHeaderDecodeCache   = array();
1197          $MPEGaudioHeaderValidCache    = array();
1198          $MPEGaudioHeaderLengthCache   = array();
1199          $MPEGaudioVersionLookup       = self::MPEGaudioVersionArray();
1200          $MPEGaudioLayerLookup         = self::MPEGaudioLayerArray();
1201          $MPEGaudioBitrateLookup       = self::MPEGaudioBitrateArray();
1202          $MPEGaudioFrequencyLookup     = self::MPEGaudioFrequencyArray();
1203          $MPEGaudioChannelModeLookup   = self::MPEGaudioChannelModeArray();
1204          $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
1205          $MPEGaudioEmphasisLookup      = self::MPEGaudioEmphasisArray();
1206          $LongMPEGversionLookup        = array();
1207          $LongMPEGlayerLookup          = array();
1208          $LongMPEGbitrateLookup        = array();
1209          $LongMPEGpaddingLookup        = array();
1210          $LongMPEGfrequencyLookup      = array();
1211          $Distribution['bitrate']      = array();
1212          $Distribution['frequency']    = array();
1213          $Distribution['layer']        = array();
1214          $Distribution['version']      = array();
1215          $Distribution['padding']      = array();
1216  
1217          $info = &$this->getid3->info;
1218          fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
1219  
1220          $max_frames_scan = 5000;
1221          $frames_scanned  = 0;
1222  
1223          $previousvalidframe = $info['avdataoffset'];
1224          while (ftell($this->getid3->fp) < $info['avdataend']) {
1225              set_time_limit(30);
1226              $head4 = fread($this->getid3->fp, 4);
1227              if (strlen($head4) < 4) {
1228                  break;
1229              }
1230              if ($head4{0} != "\xFF") {
1231                  for ($i = 1; $i < 4; $i++) {
1232                      if ($head4{$i} == "\xFF") {
1233                          fseek($this->getid3->fp, $i - 4, SEEK_CUR);
1234                          continue 2;
1235                      }
1236                  }
1237                  continue;
1238              }
1239              if (!isset($MPEGaudioHeaderDecodeCache[$head4])) {
1240                  $MPEGaudioHeaderDecodeCache[$head4] = self::MPEGaudioHeaderDecode($head4);
1241              }
1242              if (!isset($MPEGaudioHeaderValidCache[$head4])) {
1243                  $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false);
1244              }
1245              if ($MPEGaudioHeaderValidCache[$head4]) {
1246  
1247                  if (!isset($MPEGaudioHeaderLengthCache[$head4])) {
1248                      $LongMPEGversionLookup[$head4]   = $MPEGaudioVersionLookup[$MPEGaudioHeaderDecodeCache[$head4]['version']];
1249                      $LongMPEGlayerLookup[$head4]     = $MPEGaudioLayerLookup[$MPEGaudioHeaderDecodeCache[$head4]['layer']];
1250                      $LongMPEGbitrateLookup[$head4]   = $MPEGaudioBitrateLookup[$LongMPEGversionLookup[$head4]][$LongMPEGlayerLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['bitrate']];
1251                      $LongMPEGpaddingLookup[$head4]   = (bool) $MPEGaudioHeaderDecodeCache[$head4]['padding'];
1252                      $LongMPEGfrequencyLookup[$head4] = $MPEGaudioFrequencyLookup[$LongMPEGversionLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['sample_rate']];
1253                      $MPEGaudioHeaderLengthCache[$head4] = self::MPEGaudioFrameLength(
1254                          $LongMPEGbitrateLookup[$head4],
1255                          $LongMPEGversionLookup[$head4],
1256                          $LongMPEGlayerLookup[$head4],
1257                          $LongMPEGpaddingLookup[$head4],
1258                          $LongMPEGfrequencyLookup[$head4]);
1259                  }
1260                  if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
1261                      $WhereWeWere = ftell($this->getid3->fp);
1262                      fseek($this->getid3->fp, $MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
1263                      $next4 = fread($this->getid3->fp, 4);
1264                      if ($next4{0} == "\xFF") {
1265                          if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
1266                              $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
1267                          }
1268                          if (!isset($MPEGaudioHeaderValidCache[$next4])) {
1269                              $MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
1270                          }
1271                          if ($MPEGaudioHeaderValidCache[$next4]) {
1272                              fseek($this->getid3->fp, -4, SEEK_CUR);
1273  
1274                              getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
1275                              getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
1276                              getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
1277                              getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
1278                              getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
1279                              if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
1280                                  $pct_data_scanned = (ftell($this->getid3->fp) - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
1281                                  $info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
1282                                  foreach ($Distribution as $key1 => $value1) {
1283                                      foreach ($value1 as $key2 => $value2) {
1284                                          $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
1285                                      }
1286                                  }
1287                                  break;
1288                              }
1289                              continue;
1290                          }
1291                      }
1292                      unset($next4);
1293                      fseek($this->getid3->fp, $WhereWeWere - 3, SEEK_SET);
1294                  }
1295  
1296              }
1297          }
1298          foreach ($Distribution as $key => $value) {
1299              ksort($Distribution[$key], SORT_NUMERIC);
1300          }
1301          ksort($Distribution['version'], SORT_STRING);
1302          $info['mpeg']['audio']['bitrate_distribution']   = $Distribution['bitrate'];
1303          $info['mpeg']['audio']['frequency_distribution'] = $Distribution['frequency'];
1304          $info['mpeg']['audio']['layer_distribution']     = $Distribution['layer'];
1305          $info['mpeg']['audio']['version_distribution']   = $Distribution['version'];
1306          $info['mpeg']['audio']['padding_distribution']   = $Distribution['padding'];
1307          if (count($Distribution['version']) > 1) {
1308              $info['error'][] = 'Corrupt file - more than one MPEG version detected';
1309          }
1310          if (count($Distribution['layer']) > 1) {
1311              $info['error'][] = 'Corrupt file - more than one MPEG layer detected';
1312          }
1313          if (count($Distribution['frequency']) > 1) {
1314              $info['error'][] = 'Corrupt file - more than one MPEG sample rate detected';
1315          }
1316  
1317  
1318          $bittotal = 0;
1319          foreach ($Distribution['bitrate'] as $bitratevalue => $bitratecount) {
1320              if ($bitratevalue != 'free') {
1321                  $bittotal += ($bitratevalue * $bitratecount);
1322              }
1323          }
1324          $info['mpeg']['audio']['frame_count']  = array_sum($Distribution['bitrate']);
1325          if ($info['mpeg']['audio']['frame_count'] == 0) {
1326              $info['error'][] = 'no MPEG audio frames found';
1327              return false;
1328          }
1329          $info['mpeg']['audio']['bitrate']      = ($bittotal / $info['mpeg']['audio']['frame_count']);
1330          $info['mpeg']['audio']['bitrate_mode'] = ((count($Distribution['bitrate']) > 0) ? 'vbr' : 'cbr');
1331          $info['mpeg']['audio']['sample_rate']  = getid3_lib::array_max($Distribution['frequency'], true);
1332  
1333          $info['audio']['bitrate']      = $info['mpeg']['audio']['bitrate'];
1334          $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
1335          $info['audio']['sample_rate']  = $info['mpeg']['audio']['sample_rate'];
1336          $info['audio']['dataformat']   = 'mp'.getid3_lib::array_max($Distribution['layer'], true);
1337          $info['fileformat']            = $info['audio']['dataformat'];
1338  
1339          return true;
1340      }
1341  
1342  
1343  	public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) {
1344          // looks for synch, decodes MPEG audio header
1345  
1346          $info = &$this->getid3->info;
1347  
1348          static $MPEGaudioVersionLookup;
1349          static $MPEGaudioLayerLookup;
1350          static $MPEGaudioBitrateLookup;
1351          if (empty($MPEGaudioVersionLookup)) {
1352             $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
1353             $MPEGaudioLayerLookup   = self::MPEGaudioLayerArray();
1354             $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
1355  
1356          }
1357  
1358          fseek($this->getid3->fp, $avdataoffset, SEEK_SET);
1359          $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
1360          if ($sync_seek_buffer_size <= 0) {
1361              $info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;
1362              return false;
1363          }
1364          $header = fread($this->getid3->fp, $sync_seek_buffer_size);
1365          $sync_seek_buffer_size = strlen($header);
1366          $SynchSeekOffset = 0;
1367          while ($SynchSeekOffset < $sync_seek_buffer_size) {
1368              if ((($avdataoffset + $SynchSeekOffset)  < $info['avdataend']) && !feof($this->getid3->fp)) {
1369  
1370                  if ($SynchSeekOffset > $sync_seek_buffer_size) {
1371                      // if a synch's not found within the first 128k bytes, then give up
1372                      $info['error'][] = 'Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB';
1373                      if (isset($info['audio']['bitrate'])) {
1374                          unset($info['audio']['bitrate']);
1375                      }
1376                      if (isset($info['mpeg']['audio'])) {
1377                          unset($info['mpeg']['audio']);
1378                      }
1379                      if (empty($info['mpeg'])) {
1380                          unset($info['mpeg']);
1381                      }
1382                      return false;
1383  
1384                  } elseif (feof($this->getid3->fp)) {
1385  
1386                      $info['error'][] = 'Could not find valid MPEG audio synch before end of file';
1387                      if (isset($info['audio']['bitrate'])) {
1388                          unset($info['audio']['bitrate']);
1389                      }
1390                      if (isset($info['mpeg']['audio'])) {
1391                          unset($info['mpeg']['audio']);
1392                      }
1393                      if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) {
1394                          unset($info['mpeg']);
1395                      }
1396                      return false;
1397                  }
1398              }
1399  
1400              if (($SynchSeekOffset + 1) >= strlen($header)) {
1401                  $info['error'][] = 'Could not find valid MPEG synch before end of file';
1402                  return false;
1403              }
1404  
1405              if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
1406                  if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
1407                      $FirstFrameThisfileInfo = $info;
1408                      $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
1409                      if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) {
1410                          // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
1411                          // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
1412                          unset($FirstFrameThisfileInfo);
1413                      }
1414                  }
1415  
1416                  $dummy = $info; // only overwrite real data if valid header found
1417                  if ($this->decodeMPEGaudioHeader($avdataoffset + $SynchSeekOffset, $dummy, true)) {
1418                      $info = $dummy;
1419                      $info['avdataoffset'] = $avdataoffset + $SynchSeekOffset;
1420                      switch (isset($info['fileformat']) ? $info['fileformat'] : '') {
1421                          case '':
1422                          case 'id3':
1423                          case 'ape':
1424                          case 'mp3':
1425                              $info['fileformat']          = 'mp3';
1426                              $info['audio']['dataformat'] = 'mp3';
1427                              break;
1428                      }
1429                      if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
1430                          if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) {
1431                              // If there is garbage data between a valid VBR header frame and a sequence
1432                              // of valid MPEG-audio frames the VBR data is no longer discarded.
1433                              $info = $FirstFrameThisfileInfo;
1434                              $info['avdataoffset']        = $FirstFrameAVDataOffset;
1435                              $info['fileformat']          = 'mp3';
1436                              $info['audio']['dataformat'] = 'mp3';
1437                              $dummy                       = $info;
1438                              unset($dummy['mpeg']['audio']);
1439                              $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
1440                              $GarbageOffsetEnd   = $avdataoffset + $SynchSeekOffset;
1441                              if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
1442                                  $info = $dummy;
1443                                  $info['avdataoffset'] = $GarbageOffsetEnd;
1444                                  $info['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;
1445                              } else {
1446                                  $info['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.')';
1447                              }
1448                          }
1449                      }
1450                      if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) {
1451                          // VBR file with no VBR header
1452                          $BitrateHistogram = true;
1453                      }
1454  
1455                      if ($BitrateHistogram) {
1456  
1457                          $info['mpeg']['audio']['stereo_distribution']  = array('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0);
1458                          $info['mpeg']['audio']['version_distribution'] = array('1'=>0, '2'=>0, '2.5'=>0);
1459  
1460                          if ($info['mpeg']['audio']['version'] == '1') {
1461                              if ($info['mpeg']['audio']['layer'] == 3) {
1462                                  $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);
1463                              } elseif ($info['mpeg']['audio']['layer'] == 2) {
1464                                  $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);
1465                              } elseif ($info['mpeg']['audio']['layer'] == 1) {
1466                                  $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);
1467                              }
1468                          } elseif ($info['mpeg']['audio']['layer'] == 1) {
1469                              $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);
1470                          } else {
1471                              $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);
1472                          }
1473  
1474                          $dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
1475                          $synchstartoffset = $info['avdataoffset'];
1476                          fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
1477  
1478                          // you can play with these numbers:
1479                          $max_frames_scan  = 50000;
1480                          $max_scan_segments = 10;
1481  
1482                          // don't play with these numbers:
1483                          $FastMode = false;
1484                          $SynchErrorsFound = 0;
1485                          $frames_scanned   = 0;
1486                          $this_scan_segment = 0;
1487                          $frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
1488                          $pct_data_scanned = 0;
1489                          for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
1490                              $frames_scanned_this_segment = 0;
1491                              if (ftell($this->getid3->fp) >= $info['avdataend']) {
1492                                  break;
1493                              }
1494                              $scan_start_offset[$current_segment] = max(ftell($this->getid3->fp), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
1495                              if ($current_segment > 0) {
1496                                  fseek($this->getid3->fp, $scan_start_offset[$current_segment], SEEK_SET);
1497                                  $buffer_4k = fread($this->getid3->fp, 4096);
1498                                  for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
1499                                      if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
1500                                          if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
1501                                              $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
1502                                              if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
1503                                                  $scan_start_offset[$current_segment] += $j;
1504                                                  break;
1505                                              }
1506                                          }
1507                                      }
1508                                  }
1509                              }
1510                              $synchstartoffset = $scan_start_offset[$current_segment];
1511                              while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
1512                                  $FastMode = true;
1513                                  $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
1514  
1515                                  if (empty($dummy['mpeg']['audio']['framelength'])) {
1516                                      $SynchErrorsFound++;
1517                                      $synchstartoffset++;
1518                                  } else {
1519                                      getid3_lib::safe_inc($info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]);
1520                                      getid3_lib::safe_inc($info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]);
1521                                      getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]);
1522                                      $synchstartoffset += $dummy['mpeg']['audio']['framelength'];
1523                                  }
1524                                  $frames_scanned++;
1525                                  if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) {
1526                                      $this_pct_scanned = (ftell($this->getid3->fp) - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
1527                                      if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) {
1528                                          // file likely contains < $max_frames_scan, just scan as one segment
1529                                          $max_scan_segments = 1;
1530                                          $frames_scan_per_segment = $max_frames_scan;
1531                                      } else {
1532                                          $pct_data_scanned += $this_pct_scanned;
1533                                          break;
1534                                      }
1535                                  }
1536                              }
1537                          }
1538                          if ($pct_data_scanned > 0) {
1539                              $info['warning'][] = 'too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
1540                              foreach ($info['mpeg']['audio'] as $key1 => $value1) {
1541                                  if (!preg_match('#_distribution$#i', $key1)) {
1542                                      continue;
1543                                  }
1544                                  foreach ($value1 as $key2 => $value2) {
1545                                      $info['mpeg']['audio'][$key1][$key2] = round($value2 / $pct_data_scanned);
1546                                  }
1547                              }
1548                          }
1549  
1550                          if ($SynchErrorsFound > 0) {
1551                              $info['warning'][] = 'Found '.$SynchErrorsFound.' synch errors in histogram analysis';
1552                              //return false;
1553                          }
1554  
1555                          $bittotal     = 0;
1556                          $framecounter = 0;
1557                          foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount) {
1558                              $framecounter += $bitratecount;
1559                              if ($bitratevalue != 'free') {
1560                                  $bittotal += ($bitratevalue * $bitratecount);
1561                              }
1562                          }
1563                          if ($framecounter == 0) {
1564                              $info['error'][] = 'Corrupt MP3 file: framecounter == zero';
1565                              return false;
1566                          }
1567                          $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter);
1568                          $info['mpeg']['audio']['bitrate']     = ($bittotal / $framecounter);
1569  
1570                          $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
1571  
1572  
1573                          // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
1574                          $distinct_bitrates = 0;
1575                          foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) {
1576                              if ($bitrate_count > 0) {
1577                                  $distinct_bitrates++;
1578                              }
1579                          }
1580                          if ($distinct_bitrates > 1) {
1581                              $info['mpeg']['audio']['bitrate_mode'] = 'vbr';
1582                          } else {
1583                              $info['mpeg']['audio']['bitrate_mode'] = 'cbr';
1584                          }
1585                          $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
1586  
1587                      }
1588  
1589                      break; // exit while()
1590                  }
1591              }
1592  
1593              $SynchSeekOffset++;
1594              if (($avdataoffset + $SynchSeekOffset) >= $info['avdataend']) {
1595                  // end of file/data
1596  
1597                  if (empty($info['mpeg']['audio'])) {
1598  
1599                      $info['error'][] = 'could not find valid MPEG synch before end of file';
1600                      if (isset($info['audio']['bitrate'])) {
1601                          unset($info['audio']['bitrate']);
1602                      }
1603                      if (isset($info['mpeg']['audio'])) {
1604                          unset($info['mpeg']['audio']);
1605                      }
1606                      if (isset($info['mpeg']) && (!is_array($info['mpeg']) || empty($info['mpeg']))) {
1607                          unset($info['mpeg']);
1608                      }
1609                      return false;
1610  
1611                  }
1612                  break;
1613              }
1614  
1615          }
1616          $info['audio']['channels']        = $info['mpeg']['audio']['channels'];
1617          $info['audio']['channelmode']     = $info['mpeg']['audio']['channelmode'];
1618          $info['audio']['sample_rate']     = $info['mpeg']['audio']['sample_rate'];
1619          return true;
1620      }
1621  
1622  
1623  	public static function MPEGaudioVersionArray() {
1624          static $MPEGaudioVersion = array('2.5', false, '2', '1');
1625          return $MPEGaudioVersion;
1626      }
1627  
1628  	public static function MPEGaudioLayerArray() {
1629          static $MPEGaudioLayer = array(false, 3, 2, 1);
1630          return $MPEGaudioLayer;
1631      }
1632  
1633  	public static function MPEGaudioBitrateArray() {
1634          static $MPEGaudioBitrate;
1635          if (empty($MPEGaudioBitrate)) {
1636              $MPEGaudioBitrate = array (
1637                  '1'  =>  array (1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000),
1638                                  2 => array('free', 32000, 48000, 56000,  64000,  80000,  96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000),
1639                                  3 => array('free', 32000, 40000, 48000,  56000,  64000,  80000,  96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000)
1640                                 ),
1641  
1642                  '2'  =>  array (1 => array('free', 32000, 48000, 56000,  64000,  80000,  96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000),
1643                                  2 => array('free',  8000, 16000, 24000,  32000,  40000,  48000,  56000,  64000,  80000,  96000, 112000, 128000, 144000, 160000),
1644                                 )
1645              );
1646              $MPEGaudioBitrate['2'][3] = $MPEGaudioBitrate['2'][2];
1647              $MPEGaudioBitrate['2.5']  = $MPEGaudioBitrate['2'];
1648          }
1649          return $MPEGaudioBitrate;
1650      }
1651  
1652  	public static function MPEGaudioFrequencyArray() {
1653          static $MPEGaudioFrequency;
1654          if (empty($MPEGaudioFrequency)) {
1655              $MPEGaudioFrequency = array (
1656                  '1'   => array(44100, 48000, 32000),
1657                  '2'   => array(22050, 24000, 16000),
1658                  '2.5' => array(11025, 12000,  8000)
1659              );
1660          }
1661          return $MPEGaudioFrequency;
1662      }
1663  
1664  	public static function MPEGaudioChannelModeArray() {
1665          static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
1666          return $MPEGaudioChannelMode;
1667      }
1668  
1669  	public static function MPEGaudioModeExtensionArray() {
1670          static $MPEGaudioModeExtension;
1671          if (empty($MPEGaudioModeExtension)) {
1672              $MPEGaudioModeExtension = array (
1673                  1 => array('4-31', '8-31', '12-31', '16-31'),
1674                  2 => array('4-31', '8-31', '12-31', '16-31'),
1675                  3 => array('', 'IS', 'MS', 'IS+MS')
1676              );
1677          }
1678          return $MPEGaudioModeExtension;
1679      }
1680  
1681  	public static function MPEGaudioEmphasisArray() {
1682          static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
1683          return $MPEGaudioEmphasis;
1684      }
1685  
1686  	public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) {
1687          return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15);
1688      }
1689  
1690  	public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) {
1691          if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
1692              return false;
1693          }
1694  
1695          static $MPEGaudioVersionLookup;
1696          static $MPEGaudioLayerLookup;
1697          static $MPEGaudioBitrateLookup;
1698          static $MPEGaudioFrequencyLookup;
1699          static $MPEGaudioChannelModeLookup;
1700          static $MPEGaudioModeExtensionLookup;
1701          static $MPEGaudioEmphasisLookup;
1702          if (empty($MPEGaudioVersionLookup)) {
1703              $MPEGaudioVersionLookup       = self::MPEGaudioVersionArray();
1704              $MPEGaudioLayerLookup         = self::MPEGaudioLayerArray();
1705              $MPEGaudioBitrateLookup       = self::MPEGaudioBitrateArray();
1706              $MPEGaudioFrequencyLookup     = self::MPEGaudioFrequencyArray();
1707              $MPEGaudioChannelModeLookup   = self::MPEGaudioChannelModeArray();
1708              $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
1709              $MPEGaudioEmphasisLookup      = self::MPEGaudioEmphasisArray();
1710          }
1711  
1712          if (isset($MPEGaudioVersionLookup[$rawarray['version']])) {
1713              $decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']];
1714          } else {
1715              echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : '');
1716              return false;
1717          }
1718          if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) {
1719              $decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']];
1720          } else {
1721              echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : '');
1722              return false;
1723          }
1724          if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) {
1725              echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : '');
1726              if ($rawarray['bitrate'] == 15) {
1727                  // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
1728                  // let it go through here otherwise file will not be identified
1729                  if (!$allowBitrate15) {
1730                      return false;
1731                  }
1732              } else {
1733                  return false;
1734              }
1735          }
1736          if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) {
1737              echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : '');
1738              return false;
1739          }
1740          if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) {
1741              echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : '');
1742              return false;
1743          }
1744          if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) {
1745              echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : '');
1746              return false;
1747          }
1748          if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) {
1749              echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : '');
1750              return false;
1751          }
1752          // These are just either set or not set, you can't mess that up :)
1753          // $rawarray['protection'];
1754          // $rawarray['padding'];
1755          // $rawarray['private'];
1756          // $rawarray['copyright'];
1757          // $rawarray['original'];
1758  
1759          return true;
1760      }
1761  
1762  	public static function MPEGaudioHeaderDecode($Header4Bytes) {
1763          // AAAA AAAA  AAAB BCCD  EEEE FFGH  IIJJ KLMM
1764          // A - Frame sync (all bits set)
1765          // B - MPEG Audio version ID
1766          // C - Layer description
1767          // D - Protection bit
1768          // E - Bitrate index
1769          // F - Sampling rate frequency index
1770          // G - Padding bit
1771          // H - Private bit
1772          // I - Channel Mode
1773          // J - Mode extension (Only if Joint stereo)
1774          // K - Copyright
1775          // L - Original
1776          // M - Emphasis
1777  
1778          if (strlen($Header4Bytes) != 4) {
1779              return false;
1780          }
1781  
1782          $MPEGrawHeader['synch']         = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
1783          $MPEGrawHeader['version']       = (ord($Header4Bytes{1}) & 0x18) >> 3; //    BB
1784          $MPEGrawHeader['layer']         = (ord($Header4Bytes{1}) & 0x06) >> 1; //      CC
1785          $MPEGrawHeader['protection']    = (ord($Header4Bytes{1}) & 0x01);      //        D
1786          $MPEGrawHeader['bitrate']       = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE
1787          $MPEGrawHeader['sample_rate']   = (ord($Header4Bytes{2}) & 0x0C) >> 2; //     FF
1788          $MPEGrawHeader['padding']       = (ord($Header4Bytes{2}) & 0x02) >> 1; //       G
1789          $MPEGrawHeader['private']       = (ord($Header4Bytes{2}) & 0x01);      //        H
1790          $MPEGrawHeader['channelmode']   = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II
1791          $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; //   JJ
1792          $MPEGrawHeader['copyright']     = (ord($Header4Bytes{3}) & 0x08) >> 3; //     K
1793          $MPEGrawHeader['original']      = (ord($Header4Bytes{3}) & 0x04) >> 2; //      L
1794          $MPEGrawHeader['emphasis']      = (ord($Header4Bytes{3}) & 0x03);      //       MM
1795  
1796          return $MPEGrawHeader;
1797      }
1798  
1799  	public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) {
1800          static $AudioFrameLengthCache = array();
1801  
1802          if (!isset($AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate])) {
1803              $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = false;
1804              if ($bitrate != 'free') {
1805  
1806                  if ($version == '1') {
1807  
1808                      if ($layer == '1') {
1809  
1810                          // For Layer I slot is 32 bits long
1811                          $FrameLengthCoefficient = 48;
1812                          $SlotLength = 4;
1813  
1814                      } else { // Layer 2 / 3
1815  
1816                          // for Layer 2 and Layer 3 slot is 8 bits long.
1817                          $FrameLengthCoefficient = 144;
1818                          $SlotLength = 1;
1819  
1820                      }
1821  
1822                  } else { // MPEG-2 / MPEG-2.5
1823  
1824                      if ($layer == '1') {
1825  
1826                          // For Layer I slot is 32 bits long
1827                          $FrameLengthCoefficient = 24;
1828                          $SlotLength = 4;
1829  
1830                      } elseif ($layer == '2') {
1831  
1832                          // for Layer 2 and Layer 3 slot is 8 bits long.
1833                          $FrameLengthCoefficient = 144;
1834                          $SlotLength = 1;
1835  
1836                      } else { // layer 3
1837  
1838                          // for Layer 2 and Layer 3 slot is 8 bits long.
1839                          $FrameLengthCoefficient = 72;
1840                          $SlotLength = 1;
1841  
1842                      }
1843  
1844                  }
1845  
1846                  // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
1847                  if ($samplerate > 0) {
1848                      $NewFramelength  = ($FrameLengthCoefficient * $bitrate) / $samplerate;
1849                      $NewFramelength  = floor($NewFramelength / $SlotLength) * $SlotLength; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I)
1850                      if ($padding) {
1851                          $NewFramelength += $SlotLength;
1852                      }
1853                      $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = (int) $NewFramelength;
1854                  }
1855              }
1856          }
1857          return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
1858      }
1859  
1860  	public static function ClosestStandardMP3Bitrate($bit_rate) {
1861          static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
1862          static $bit_rate_table = array (0=>'-');
1863          $round_bit_rate = intval(round($bit_rate, -3));
1864          if (!isset($bit_rate_table[$round_bit_rate])) {
1865              if ($round_bit_rate > max($standard_bit_rates)) {
1866                  $bit_rate_table[$round_bit_rate] = round($bit_rate, 2 - strlen($bit_rate));
1867              } else {
1868                  $bit_rate_table[$round_bit_rate] = max($standard_bit_rates);
1869                  foreach ($standard_bit_rates as $standard_bit_rate) {
1870                      if ($round_bit_rate >= $standard_bit_rate + (($bit_rate_table[$round_bit_rate] - $standard_bit_rate) / 2)) {
1871                          break;
1872                      }
1873                      $bit_rate_table[$round_bit_rate] = $standard_bit_rate;
1874                  }
1875              }
1876          }
1877          return $bit_rate_table[$round_bit_rate];
1878      }
1879  
1880  	public static function XingVBRidOffset($version, $channelmode) {
1881          static $XingVBRidOffsetCache = array();
1882          if (empty($XingVBRidOffset)) {
1883              $XingVBRidOffset = array (
1884                  '1'   => array ('mono'          => 0x15, // 4 + 17 = 21
1885                                  'stereo'        => 0x24, // 4 + 32 = 36
1886                                  'joint stereo'  => 0x24,
1887                                  'dual channel'  => 0x24
1888                                 ),
1889  
1890                  '2'   => array ('mono'          => 0x0D, // 4 +  9 = 13
1891                                  'stereo'        => 0x15, // 4 + 17 = 21
1892                                  'joint stereo'  => 0x15,
1893                                  'dual channel'  => 0x15
1894                                 ),
1895  
1896                  '2.5' => array ('mono'          => 0x15,
1897                                  'stereo'        => 0x15,
1898                                  'joint stereo'  => 0x15,
1899                                  'dual channel'  => 0x15
1900                                 )
1901              );
1902          }
1903          return $XingVBRidOffset[$version][$channelmode];
1904      }
1905  
1906  	public static function LAMEvbrMethodLookup($VBRmethodID) {
1907          static $LAMEvbrMethodLookup = array(
1908              0x00 => 'unknown',
1909              0x01 => 'cbr',
1910              0x02 => 'abr',
1911              0x03 => 'vbr-old / vbr-rh',
1912              0x04 => 'vbr-new / vbr-mtrh',
1913              0x05 => 'vbr-mt',
1914              0x06 => 'vbr (full vbr method 4)',
1915              0x08 => 'cbr (constant bitrate 2 pass)',
1916              0x09 => 'abr (2 pass)',
1917              0x0F => 'reserved'
1918          );
1919          return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
1920      }
1921  
1922  	public static function LAMEmiscStereoModeLookup($StereoModeID) {
1923          static $LAMEmiscStereoModeLookup = array(
1924              0 => 'mono',
1925              1 => 'stereo',
1926              2 => 'dual mono',
1927              3 => 'joint stereo',
1928              4 => 'forced stereo',
1929              5 => 'auto',
1930              6 => 'intensity stereo',
1931              7 => 'other'
1932          );
1933          return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
1934      }
1935  
1936  	public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) {
1937          static $LAMEmiscSourceSampleFrequencyLookup = array(
1938              0 => '<= 32 kHz',
1939              1 => '44.1 kHz',
1940              2 => '48 kHz',
1941              3 => '> 48kHz'
1942          );
1943          return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
1944      }
1945  
1946  	public static function LAMEsurroundInfoLookup($SurroundInfoID) {
1947          static $LAMEsurroundInfoLookup = array(
1948              0 => 'no surround info',
1949              1 => 'DPL encoding',
1950              2 => 'DPL2 encoding',
1951              3 => 'Ambisonic encoding'
1952          );
1953          return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
1954      }
1955  
1956  	public static function LAMEpresetUsedLookup($LAMEtag) {
1957  
1958          if ($LAMEtag['preset_used_id'] == 0) {
1959              // no preset used (LAME >=3.93)
1960              // no preset recorded (LAME <3.93)
1961              return '';
1962          }
1963          $LAMEpresetUsedLookup = array();
1964  
1965          /////  THIS PART CANNOT BE STATIC .
1966          for ($i = 8; $i <= 320; $i++) {
1967              switch ($LAMEtag['vbr_method']) {
1968                  case 'cbr':
1969                      $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i;
1970                      break;
1971                  case 'abr':
1972                  default: // other VBR modes shouldn't be here(?)
1973                      $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i;
1974                      break;
1975              }
1976          }
1977  
1978          // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()
1979  
1980          // named alt-presets
1981          $LAMEpresetUsedLookup[1000] = '--r3mix';
1982          $LAMEpresetUsedLookup[1001] = '--alt-preset standard';
1983          $LAMEpresetUsedLookup[1002] = '--alt-preset extreme';
1984          $LAMEpresetUsedLookup[1003] = '--alt-preset insane';
1985          $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard';
1986          $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme';
1987          $LAMEpresetUsedLookup[1006] = '--alt-preset medium';
1988          $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium';
1989  
1990          // LAME 3.94 additions/changes
1991          $LAMEpresetUsedLookup[1010] = '--preset portable';                                                           // 3.94a15 Oct 21 2003
1992          $LAMEpresetUsedLookup[1015] = '--preset radio';                                                              // 3.94a15 Oct 21 2003
1993  
1994          $LAMEpresetUsedLookup[320]  = '--preset insane';                                                             // 3.94a15 Nov 12 2003
1995          $LAMEpresetUsedLookup[410]  = '-V9';
1996          $LAMEpresetUsedLookup[420]  = '-V8';
1997          $LAMEpresetUsedLookup[440]  = '-V6';
1998          $LAMEpresetUsedLookup[430]  = '--preset radio';                                                              // 3.94a15 Nov 12 2003
1999          $LAMEpresetUsedLookup[450]  = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable';  // 3.94a15 Nov 12 2003
2000          $LAMEpresetUsedLookup[460]  = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium';    // 3.94a15 Nov 12 2003
2001          $LAMEpresetUsedLookup[470]  = '--r3mix';                                                                     // 3.94b1  Dec 18 2003
2002          $LAMEpresetUsedLookup[480]  = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard';  // 3.94a15 Nov 12 2003
2003          $LAMEpresetUsedLookup[490]  = '-V1';
2004          $LAMEpresetUsedLookup[500]  = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme';   // 3.94a15 Nov 12 2003
2005  
2006          return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info@getid3.org');
2007      }
2008  
2009  }


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu