Location: PHPKode > projects > mediaIndex > lib/getid3/module.audio.mp3.php
<?php
// +----------------------------------------------------------------------+
// | PHP version 5                                                        |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002-2004 James Heinrich                               |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2 of the GPL license,         |
// | that is bundled with this package in the file license.txt and is     |
// | available through the world-wide-web at the following url:           |
// | http://www.gnu.org/copyleft/gpl.html                                 |
// +----------------------------------------------------------------------+
// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org    |
// +----------------------------------------------------------------------+
// | Authors: James Heinrich <infoØgetid3*org>                            |
// |          Allan Hansen <ahØartemis*dk>                                |
// +----------------------------------------------------------------------+
// | module.audio.mp3.php                                                 |
// | Module for analyzing MPEG Audio Layer 1,2,3 Audio files              |
// | dependencies: NONE                                                   |
// +----------------------------------------------------------------------+
//
// $Id: module.audio.mp3.php,v 1.1 2004/11/17 19:15:07 openface Exp $



class getid3_mp3 extends getid3_handler
{
	// Number of frames to scan to determine if MPEG-audio sequence is valid
	// Lower this number to 5-20 for faster scanning
	// Increase this number to 50+ for most accurate detection of valid VBR/CBR
	// mpeg-audio streams
	const MP3_VALID_CHECK_FRAMES = 35;


	public function Analyze() {

		$getid3 = $this->getid3;

		// Save copy
		$this->getid3 = $getid3;

		$getid3->info['mpeg']['audio'] = array ();
		$getid3->info['audio']         = array ();
		$info_mpeg_audio = &$getid3->info['mpeg']['audio'];
		$info_audio      = &$getid3->info['audio'];


		fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET);
		$mp3_frameheader_data = fread($getid3->fp, getid3::FREAD_BUFFER_SIZE);

		$synch_offset = 0;
		while (!preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB][\x00-\xFF]/', substr($mp3_frameheader_data, $synch_offset, 4))) {
			$synch_offset++;
		}

		if ($synch_offset && !preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB][\x00-\xFF]/', substr($mp3_frameheader_data, $synch_offset, 4))) {
			throw new getid3_exception('MPEG audio header expected at '.$getid3->info['avdataoffset'].' but not found.');
		}

		if ($info_mpeg_audio = getid3_mp3::DecodeMPEGaudioHeader($mp3_frameheader_data, $synch_offset)) {
			$info_audio['bitrate']      = $info_mpeg_audio['bitrate'];
			$info_audio['channels']     = $info_mpeg_audio['channels'];
			$info_audio['channelmode']  = $info_mpeg_audio['channelmode'];
			$info_audio['sample_rate']  = $info_mpeg_audio['sample_rate'];
			$info_audio['dataformat']   = 'mp'.$info_mpeg_audio['layer'];
			if (!isset($getid3->info['fileformat'])) {
				$getid3->info['fileformat'] = $info_audio['dataformat'];
			}

			if ($synch_offset) {
				if (($info_mpeg_audio['bitrate_mode'] == 'cbr') && ($synch_offset == $info_mpeg_audio['framelength'])) {
					$getid3->warning('MPEG audio header expected at '.$getid3->info['avdataoffset'].' but found '.$synch_offset.' bytes later at '.($getid3->info['avdataoffset'] + $synch_offset).' (this is a known problem with LAME v3.90-v3.92 DLL encodings in CBR mode)');
				} else {
					$getid3->warning('MPEG audio header expected at '.$getid3->info['avdataoffset'].' but found '.$synch_offset.' bytes later at '.($getid3->info['avdataoffset'] + $synch_offset));
				}
			}
		}

//		$this->GetOnlyMPEGaudioInfo();

		if (isset($info_mpeg_audio['bitrate_mode'])) {
			$info_audio['bitrate_mode'] = strtolower($info_mpeg_audio['bitrate_mode']);
		}

//		if (((isset($getid3->info['id3v2']['headerlength']) && ($getid3->info['avdataoffset'] > $getid3->info['id3v2']['headerlength'])) || (!isset($getid3->info['id3v2']) && ($getid3->info['avdataoffset'] > 0)))) {
//
//			$synch_offset_warning = 'Unknown data before synch ';
//			if (isset($getid3->info['id3v2']['headerlength'])) {
//				$synch_offset_warning .= '(ID3v2 header ends at '.$getid3->info['id3v2']['headerlength'].', then '.($getid3->info['avdataoffset'] - $getid3->info['id3v2']['headerlength']).' bytes garbage, ';
//			} else {
//				$synch_offset_warning .= '(should be at beginning of file, ';
//			}
//			$synch_offset_warning .= 'synch detected at '.$getid3->info['avdataoffset'].')';
//			if ($info_audio['bitrate_mode'] == 'cbr') {
//
//				if (!empty($getid3->info['id3v2']['headerlength']) && (($getid3->info['avdataoffset'] - $getid3->info['id3v2']['headerlength']) == $info_mpeg_audio['framelength'])) {
//
//					$synch_offset_warning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.';
//					$info_audio['codec']   = 'LAME';
//					$current_data_lame_version_string = 'LAME3.';
//
//				} elseif (empty($getid3->info['id3v2']['headerlength']) && ($getid3->info['avdataoffset'] == $info_mpeg_audio['framelength'])) {
//
//					$synch_offset_warning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.';
//					$info_audio['codec']   = 'LAME';
//					$current_data_lame_version_string = 'LAME3.';
//				}
//
//			}
//			$getid3->warning($synch_offset_warning);
//		}

		if (isset($info_mpeg_audio['LAME'])) {
			$info_audio['codec'] = 'LAME';
			if (!empty($info_mpeg_audio['LAME']['long_version'])) {
				$info_audio['encoder'] = rtrim($info_mpeg_audio['LAME']['long_version'], "\x00");
			} elseif (!empty($info_mpeg_audio['LAME']['short_version'])) {
				$info_audio['encoder'] = rtrim($info_mpeg_audio['LAME']['short_version'], "\x00");
			}
		}

		$current_data_lame_version_string = (!empty($current_data_lame_version_string) ? $current_data_lame_version_string : @$info_audio['encoder']);
		if (!empty($current_data_lame_version_string) && (substr($current_data_lame_version_string, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($current_data_lame_version_string, -1))) {
			// a version number of LAME that does not end with a number like "LAME3.92"
			// or with a closing parenthesis like "LAME3.88 (alpha)"
			// or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92)

			// not sure what the actual last frame length will be, but will be less than or equal to 1441
			$possibly_longer_lame_version_frame_length = 1441;

			// Not sure what version of LAME this is - look in padding of last frame for longer version string
			$possible_lame_version_string_offset = $getid3->info['avdataend'] - $possibly_longer_lame_version_frame_length;
			fseek($getid3->fp, $possible_lame_version_string_offset);
			$possibly_longer_lame_version_data = fread($getid3->fp, $possibly_longer_lame_version_frame_length);
			switch (substr($current_data_lame_version_string, -1)) {
				case 'a':
				case 'b':
					// "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
					// need to trim off "a" to match longer string
					$current_data_lame_version_string = substr($current_data_lame_version_string, 0, -1);
					break;
			}
			if (($possibly_longer_lame_version_string = strstr($possibly_longer_lame_version_data, $current_data_lame_version_string)) !== false) {
				if (substr($possibly_longer_lame_version_string, 0, strlen($current_data_lame_version_string)) == $current_data_lame_version_string) {
					$possibly_longer_lame_version_new_string = substr($possibly_longer_lame_version_string, 0, strspn($possibly_longer_lame_version_string, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3"  "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
					if (strlen($possibly_longer_lame_version_new_string) > strlen(@$info_audio['encoder'])) {
						$info_audio['encoder'] = $possibly_longer_lame_version_new_string;
					}
				}
			}
		}
		if (!empty($info_audio['encoder'])) {
			$info_audio['encoder'] = rtrim($info_audio['encoder'], "\x00 ");
		}

		switch (@$info_mpeg_audio['layer']) {
			case 1:
			case 2:
				$info_audio['dataformat'] = 'mp'.$info_mpeg_audio['layer'];
				break;
		}
//		if ($getid3->info['fileformat'] == 'mp3') {
//			switch ($info_audio['dataformat']) {
//				case 'mp1':
//				case 'mp2':
//				case 'mp3':
//					$getid3->info['fileformat'] = $info_audio['dataformat'];
//					break;
//
//				default:
//					$getid3->warning('Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info_audio['dataformat'].'"');
//					break;
//			}
//		}

//		if (empty($getid3->info['fileformat'])) {
//			return false;
//		}

		$getid3->info['mime_type'] = 'audio/mpeg';
		$info_audio['lossless'] = false;

		// Calculate playtime
		if (!isset($getid3->info['playtime_seconds']) && isset($info_audio['bitrate']) && ($info_audio['bitrate'] > 0)) {
			$getid3->info['playtime_seconds'] = ($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8 / $info_audio['bitrate'];
		}

		$info_audio['encoder_options'] = $this->GuessEncoderOptions();

		return true;
	}



	public static function DecodeMPEGaudioHeader(&$header_data, $offset, $recursive_search = true, $fast_mpeg_header_scan = false) {

		static $mpeg_audio_version_lookup;
		static $mpeg_audio_layer_lookup;
		static $mpeg_audio_bitrate_lookup;
		static $mpeg_audio_frequency_lookup;
		static $mpeg_audio_channel_mode_lookup;
		static $mpeg_audio_extention_lookup;
		static $mpeg_audio_emphasis_lookup;
		if (empty($mpeg_audio_version_lookup)) {
			$mpeg_audio_version_lookup      = getid3_mp3::MPEGaudioVersionArray();
			$mpeg_audio_layer_lookup        = getid3_mp3::MPEGaudioLayerArray();
			$mpeg_audio_bitrate_lookup      = getid3_mp3::MPEGaudioBitrateArray();
			$mpeg_audio_frequency_lookup    = getid3_mp3::MPEGaudioFrequencyArray();
			$mpeg_audio_channel_mode_lookup = getid3_mp3::MPEGaudioChannelModeArray();
			$mpeg_audio_extention_lookup    = getid3_mp3::MPEGaudioModeExtensionArray();
			$mpeg_audio_emphasis_lookup     = getid3_mp3::MPEGaudioEmphasisArray();
		}

		$head4 = substr($header_data, $offset, 4);

		static $mpeg_audio_header_decode_cache = array ();
		if (isset($mpeg_audio_header_decode_cache[$head4])) {
			$mpeg_header_raw_array = $mpeg_audio_header_decode_cache[$head4];
		} else {
			$mpeg_header_raw_array = getid3_mp3::MPEGaudioHeaderDecode($head4);
			$mpeg_audio_header_decode_cache[$head4] = $mpeg_header_raw_array;
		}

		static $mpeg_audio_header_valid_cache = array ();

		// Not in cache
		if (!isset($mpeg_audio_header_valid_cache[$head4])) {
			$mpeg_audio_header_valid_cache[$head4] = getid3_mp3::MPEGaudioHeaderValid($mpeg_header_raw_array, false);
		}

		$info_mpeg_audio = &$getid3->info['mpeg']['audio'];

		if ($mpeg_audio_header_valid_cache[$head4]) {
			$info_mpeg_audio['raw'] = $mpeg_header_raw_array;
		} else {
			throw new getid3_exception('Invalid MPEG audio header at offset '.$offset);
		}

		if (!$fast_mpeg_header_scan) {

			$info_mpeg_audio['version']       = $mpeg_audio_version_lookup[$info_mpeg_audio['raw']['version']];
			$info_mpeg_audio['layer']         = $mpeg_audio_layer_lookup[$info_mpeg_audio['raw']['layer']];

			$info_mpeg_audio['channelmode']   = $mpeg_audio_channel_mode_lookup[$info_mpeg_audio['raw']['channelmode']];
			$info_mpeg_audio['channels']      = (($info_mpeg_audio['channelmode'] == 'mono') ? 1 : 2);
			$info_mpeg_audio['sample_rate']   = $mpeg_audio_frequency_lookup[$info_mpeg_audio['version']][$info_mpeg_audio['raw']['sample_rate']];
			$info_mpeg_audio['protection']    = !$info_mpeg_audio['raw']['protection'];
			$info_mpeg_audio['private']       = (bool)$info_mpeg_audio['raw']['private'];
			$info_mpeg_audio['modeextension'] = $mpeg_audio_extention_lookup[$info_mpeg_audio['layer']][$info_mpeg_audio['raw']['modeextension']];
			$info_mpeg_audio['copyright']     = (bool)$info_mpeg_audio['raw']['copyright'];
			$info_mpeg_audio['original']      = (bool)$info_mpeg_audio['raw']['original'];
			$info_mpeg_audio['emphasis']      = $mpeg_audio_emphasis_lookup[$info_mpeg_audio['raw']['emphasis']];

			$getid3->info['audio']['channels']    = $info_mpeg_audio['channels'];
			$getid3->info['audio']['sample_rate'] = $info_mpeg_audio['sample_rate'];

			if ($info_mpeg_audio['protection']) {
				$info_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($header_data, 4, 2));
			}

		}

		if ($info_mpeg_audio['raw']['bitrate'] == 15) {
			// http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
			$getid3->warning('Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1');
			$info_mpeg_audio['raw']['bitrate'] = 0;
		}
		$info_mpeg_audio['padding'] = (bool)$info_mpeg_audio['raw']['padding'];
		$info_mpeg_audio['bitrate'] = $mpeg_audio_bitrate_lookup[$info_mpeg_audio['version']][$info_mpeg_audio['layer']][$info_mpeg_audio['raw']['bitrate']];

		if (($info_mpeg_audio['bitrate'] == 'free') && ($offset == @$getid3->info['avdataoffset'])) {
			// only skip multiple frame check if free-format bitstream found at beginning of file
			// otherwise is quite possibly simply corrupted data
			$recursive_search = false;
		}

		// For Layer 2 there are some combinations of bitrate and mode which are not allowed.
		if (!$fast_mpeg_header_scan && ($info_mpeg_audio['layer'] == '2')) {

			$getid3->info['audio']['dataformat'] = 'mp2';
			switch ($info_mpeg_audio['channelmode']) {

				case 'mono':
					if (($info_mpeg_audio['bitrate'] == 'free') || ($info_mpeg_audio['bitrate'] <= 192000)) {
						// these are ok
					} else {
						throw new getid3_exception($info_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$info_mpeg_audio['channelmode'].'.');
					}
					break;

				case 'stereo':
				case 'joint stereo':
				case 'dual channel':
					if (($info_mpeg_audio['bitrate'] == 'free') || ($info_mpeg_audio['bitrate'] == 64000) || ($info_mpeg_audio['bitrate'] >= 96000)) {
						// these are ok
					} else {
						throw new getid3_exception(intval(round($info_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$info_mpeg_audio['channelmode'].'.');
					}
					break;
			}
		}

		if ($getid3->info['audio']['sample_rate'] > 0) {
			$info_mpeg_audio['framelength'] = getid3_mp3::MPEGaudioFrameLength($info_mpeg_audio['bitrate'], $info_mpeg_audio['version'], $info_mpeg_audio['layer'], (int)$info_mpeg_audio['padding'], $getid3->info['audio']['sample_rate']);
		}

//		$next_frame_test_offset = $offset + 1;
//		if ($info_mpeg_audio['bitrate'] != 'free') {
//
//			$getid3->info['audio']['bitrate'] = $info_mpeg_audio['bitrate'];
//
//			if (isset($info_mpeg_audio['framelength'])) {
//				$next_frame_test_offset = $offset + $info_mpeg_audio['framelength'];
//			} else {
//				throw new getid3_exception('Frame at offset('.$offset.') is has an invalid frame length.');
//			}
//
//		}
		$expected_number_of_audio_bytes = 0;

		////////////////////////////////////////////////////////////////////////////////////
		// Variable-bitrate headers


		if (substr($header_data, 4 + 32, 4) == 'VBRI') {

			// Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
			// specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html

			$info_mpeg_audio['bitrate_mode'] = 'vbr';
			$info_mpeg_audio['VBR_method']   = 'Fraunhofer';
			$getid3->info['audio']['codec']  = 'Fraunhofer';

			$side_info_data = substr($header_data, 4 + 2, 32);

			$fraunhofer_vbr_offset = 36;

			getid3_lib::ReadSequence('BigEndian2Int', $info_mpeg_audio, $header_data, $fraunhofer_vbr_offset + 4,
				array (
					'VBR_encoder_version' => 2,
					'VBR_encoder_delay'   => 2,
					'VBR_quality'         => 2,
					'VBR_bytes'           => 4,
					'VBR_frames'          => 4,
					'VBR_seek_offsets'    => 2,
					'VBR_seek_scale'      => 2,
					'VBR_entry_bytes'     => 2,
					'VBR_entry_frames'    => 2
				)
			);

			$expected_number_of_audio_bytes = $info_mpeg_audio['VBR_bytes'];

			$previous_byte_offset = $offset;
			for ($i = 0; $i < $info_mpeg_audio['VBR_seek_offsets']; $i++) {
				$fraunhofer_offset_n = getid3_lib::BigEndian2Int(substr($header_data, $fraunhofer_vbr_offset, $info_mpeg_audio['VBR_entry_bytes']));
				$fraunhofer_vbr_offset += $info_mpeg_audio['VBR_entry_bytes'];
				$info_mpeg_audio['VBR_offsets_relative'][$i] = ($fraunhofer_offset_n * $info_mpeg_audio['VBR_seek_scale']);
				$info_mpeg_audio['VBR_offsets_absolute'][$i] = ($fraunhofer_offset_n * $info_mpeg_audio['VBR_seek_scale']) + $previous_byte_offset;
				$previous_byte_offset += $fraunhofer_offset_n;
			}


		} else {

			// Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
			// depending on MPEG layer and number of channels

			$vbr_id_offset  = getid3_mp3::XingVBRidOffset($info_mpeg_audio['version'], $info_mpeg_audio['channelmode']);
			$side_info_data = substr($header_data, 4 + 2, $vbr_id_offset - 4);

			if ((substr($header_data, $vbr_id_offset, 4) == 'Xing') || (substr($header_data, $vbr_id_offset, 4) == 'Info')) {

				/*
				 'Xing' is traditional Xing VBR frame
				 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
				 'Info' *can* legally be used to specify a VBR file as well, however.

				 http://www.multiweb.cz/twoinches/MP3inside.htm
				00..03 = "Xing" or "Info"
				04..07 = Flags:
				  0x01  Frames Flag     set if value for number of frames in file is stored
				  0x02  Bytes Flag      set if value for filesize in bytes is stored
				  0x04  TOC Flag        set if values for TOC are stored
				  0x08  VBR Scale Flag  set if values for VBR scale is stored
				08..11  Frames: Number of frames in file (including the first Xing/Info one)
				12..15  Bytes:  File length in Bytes
				16..115  TOC (Table of Contents):
				  Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file.
				  Each Byte has a value according this formula:
				  (TOC[i] / 256) * fileLenInBytes
				  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:
				  TOC[(60/240)*100] = TOC[25]
				  and corresponding Byte in file is then approximately at:
				  (TOC[25]/256) * 5000000
				116..119  VBR Scale


				 should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME
					if (substr($header_data, $vbr_id_offset, strlen('Info')) == 'Xing') {
						$info_mpeg_audio['bitrate_mode'] = 'vbr';
						$info_mpeg_audio['VBR_method']   = 'Xing';
				} else {
					$info_mpeg_audio['bitrate_mode'] = 'cbr';
				}
				*/
				$info_mpeg_audio['bitrate_mode'] = 'vbr';
				$info_mpeg_audio['VBR_method']   = 'Xing';

				$info_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($header_data, $vbr_id_offset + 4, 4));

				$info_mpeg_audio['xing_flags']['frames']    = (bool)($info_mpeg_audio['xing_flags_raw'] & 0x00000001);
				$info_mpeg_audio['xing_flags']['bytes']     = (bool)($info_mpeg_audio['xing_flags_raw'] & 0x00000002);
				$info_mpeg_audio['xing_flags']['toc']       = (bool)($info_mpeg_audio['xing_flags_raw'] & 0x00000004);
				$info_mpeg_audio['xing_flags']['vbr_scale'] = (bool)($info_mpeg_audio['xing_flags_raw'] & 0x00000008);

				if ($info_mpeg_audio['xing_flags']['frames']) {
					$info_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($header_data, $vbr_id_offset +  8, 4));
				}
				if ($info_mpeg_audio['xing_flags']['bytes']) {
					$info_mpeg_audio['VBR_bytes']  = getid3_lib::BigEndian2Int(substr($header_data, $vbr_id_offset + 12, 4));
				}

				if (!empty($info_mpeg_audio['VBR_frames']) && !empty($info_mpeg_audio['VBR_bytes'])) {

					$frame_length_float = $info_mpeg_audio['VBR_bytes'] / $info_mpeg_audio['VBR_frames'];

					if ($info_mpeg_audio['layer'] == '1') {
						$getid3->info['audio']['bitrate'] = ($frame_length_float / 4) * $info_mpeg_audio['sample_rate'] * (2 / $getid3->info['audio']['channels']) / 12;
					} else {
						$getid3->info['audio']['bitrate'] = $frame_length_float * $info_mpeg_audio['sample_rate'] * (2 / $getid3->info['audio']['channels']) / 144;
					}
					$info_mpeg_audio['framelength'] = floor($frame_length_float);
				}

				if ($info_mpeg_audio['xing_flags']['toc']) {
					$lame_toc_data = substr($header_data, $vbr_id_offset + 16, 100);
					for ($i = 0; $i < 100; $i++) {
						$info_mpeg_audio['toc'][$i] = ord($lame_toc_data{$i});
					}
				}
				if ($info_mpeg_audio['xing_flags']['vbr_scale']) {
					$info_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($header_data, $vbr_id_offset + 116, 4));
				}


				// http://gabriel.mp3-tech.org/mp3infotag.html
				if (substr($header_data, $vbr_id_offset + 120, 4) == 'LAME') {

					// shortcut
					$info_mpeg_audio['LAME'] = array ();
					$info_mpeg_audio_lame    = &$info_mpeg_audio['LAME'];

					$info_mpeg_audio_lame['long_version']  = substr($header_data, $vbr_id_offset + 120, 20);
					$info_mpeg_audio_lame['short_version'] = substr($info_mpeg_audio_lame['long_version'], 0, 9);

					if ($info_mpeg_audio_lame['short_version'] >= 'LAME3.90') {

						// extra 11 chars are not part of version string when LAMEtag present
						unset($info_mpeg_audio_lame['long_version']);

						// It the LAME tag was only introduced in LAME v3.90
						// http://www.hydrogenaudio.org/?act=ST&f=15&t=9933

						// Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
						// are assuming a 'Xing' identifier offset of 0x24, which is the case for
						// MPEG-1 non-mono, but not for other combinations
						$lame_tag_offset_contant = $vbr_id_offset - 0x24;

						// shortcuts
						$info_mpeg_audio_lame['RGAD']    = array ('track'=>array(), 'album'=>array());
						$info_mpeg_audio_lame_RGAD       = &$info_mpeg_audio_lame['RGAD'];
						$info_mpeg_audio_lame_RGAD_track = &$info_mpeg_audio_lame_RGAD['track'];
						$info_mpeg_audio_lame_RGAD_album = &$info_mpeg_audio_lame_RGAD['album'];
						$info_mpeg_audio_lame['raw']     = array ();
						$info_mpeg_audio_lame_raw        = &$info_mpeg_audio_lame['raw'];

						// byte $9B  VBR Quality
						// This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
						// Actually overwrites original Xing bytes
						unset($info_mpeg_audio['VBR_scale']);
						$info_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0x9B, 1));

						// bytes $9C-$A4  Encoder short VersionString
						$info_mpeg_audio_lame['short_version'] = substr($header_data, $lame_tag_offset_contant + 0x9C, 9);

						// byte $A5  Info Tag revision + VBR method
						$lame_tag_revision_vbr_method = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xA5, 1));

						$info_mpeg_audio_lame['tag_revision']   = ($lame_tag_revision_vbr_method & 0xF0) >> 4;
						$info_mpeg_audio_lame_raw['vbr_method'] =  $lame_tag_revision_vbr_method & 0x0F;
						$info_mpeg_audio_lame['vbr_method']     = getid3_mp3::LAMEvbrMethodLookup($info_mpeg_audio_lame_raw['vbr_method']);
						$info_mpeg_audio['bitrate_mode']        = substr($info_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'

						// byte $A6  Lowpass filter value
						$info_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xA6, 1)) * 100;

						// bytes $A7-$AE  Replay Gain
						// http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
						// bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
						if ($info_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
							// LAME 3.94a16 and later - 9.23 fixed point
							// ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
							$info_mpeg_audio_lame_RGAD['peak_amplitude'] = (float)((getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xA7, 4))) / 8388608);
						} else {
							// LAME 3.94a15 and earlier - 32-bit floating point
							// Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
							$info_mpeg_audio_lame_RGAD['peak_amplitude'] = (float)getid3_lib::LittleEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xA7, 4));
						}
						if ($info_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
							unset($info_mpeg_audio_lame_RGAD['peak_amplitude']);
						} else {
							$info_mpeg_audio_lame_RGAD['peak_db'] = 20 * log10($info_mpeg_audio_lame_RGAD['peak_amplitude']);
						}

						$info_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xAB, 2));
						$info_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xAD, 2));


						if ($info_mpeg_audio_lame_raw['RGAD_track'] != 0) {

							$info_mpeg_audio_lame_RGAD_track['raw']['name']        = ($info_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
							$info_mpeg_audio_lame_RGAD_track['raw']['originator']  = ($info_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
							$info_mpeg_audio_lame_RGAD_track['raw']['sign_bit']    = ($info_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
							$info_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] =  $info_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
							$info_mpeg_audio_lame_RGAD_track['name']               = getid3_lib_replaygain::NameLookup($info_mpeg_audio_lame_RGAD_track['raw']['name']);
							$info_mpeg_audio_lame_RGAD_track['originator']         = getid3_lib_replaygain::OriginatorLookup($info_mpeg_audio_lame_RGAD_track['raw']['originator']);
							$info_mpeg_audio_lame_RGAD_track['gain_db']            = getid3_lib_replaygain::AdjustmentLookup($info_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $info_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);

							if (!empty($info_mpeg_audio_lame_RGAD['peak_amplitude'])) {
								$getid3->info['replay_gain']['track']['peak']   = $info_mpeg_audio_lame_RGAD['peak_amplitude'];
							}
							$getid3->info['replay_gain']['track']['originator'] = $info_mpeg_audio_lame_RGAD_track['originator'];
							$getid3->info['replay_gain']['track']['adjustment'] = $info_mpeg_audio_lame_RGAD_track['gain_db'];
						} else {
							unset($info_mpeg_audio_lame_RGAD['track']);
						}
						if ($info_mpeg_audio_lame_raw['RGAD_album'] != 0) {

							$info_mpeg_audio_lame_RGAD_album['raw']['name']        = ($info_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
							$info_mpeg_audio_lame_RGAD_album['raw']['originator']  = ($info_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
							$info_mpeg_audio_lame_RGAD_album['raw']['sign_bit']    = ($info_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
							$info_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $info_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
							$info_mpeg_audio_lame_RGAD_album['name']               = getid3_lib_replaygain::NameLookup($info_mpeg_audio_lame_RGAD_album['raw']['name']);
							$info_mpeg_audio_lame_RGAD_album['originator']         = getid3_lib_replaygain::OriginatorLookup($info_mpeg_audio_lame_RGAD_album['raw']['originator']);
							$info_mpeg_audio_lame_RGAD_album['gain_db']            = getid3_lib_replaygain::AdjustmentLookup($info_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $info_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);

							if (!empty($info_mpeg_audio_lame_RGAD['peak_amplitude'])) {
								$getid3->info['replay_gain']['album']['peak']   = $info_mpeg_audio_lame_RGAD['peak_amplitude'];
							}
							$getid3->info['replay_gain']['album']['originator'] = $info_mpeg_audio_lame_RGAD_album['originator'];
							$getid3->info['replay_gain']['album']['adjustment'] = $info_mpeg_audio_lame_RGAD_album['gain_db'];
						} else {
							unset($info_mpeg_audio_lame_RGAD['album']);
						}
						if (empty($info_mpeg_audio_lame_RGAD)) {
							unset($info_mpeg_audio_lame['RGAD']);
						}


						// byte $AF  Encoding flags + ATH Type
						$encoding_flags_ath_type = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xAF, 1));
						$info_mpeg_audio_lame['encoding_flags']['nspsytune']   = (bool)($encoding_flags_ath_type & 0x10);
						$info_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool)($encoding_flags_ath_type & 0x20);
						$info_mpeg_audio_lame['encoding_flags']['nogap_next']  = (bool)($encoding_flags_ath_type & 0x40);
						$info_mpeg_audio_lame['encoding_flags']['nogap_prev']  = (bool)($encoding_flags_ath_type & 0x80);
						$info_mpeg_audio_lame['ath_type']                      =        $encoding_flags_ath_type & 0x0F;

						// byte $B0  if ABR {specified bitrate} else {minimal bitrate}
						$info_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xB0, 1));
						if ($info_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
							$info_mpeg_audio_lame['bitrate_abr'] = $info_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
						} elseif ($info_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
							// ignore
						} elseif ($info_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
							$info_mpeg_audio_lame['bitrate_min'] = $info_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
						}

						// bytes $B1-$B3  Encoder delays
						$encoder_delays = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xB1, 3));
						$info_mpeg_audio_lame['encoder_delay'] = ($encoder_delays & 0xFFF000) >> 12;
						$info_mpeg_audio_lame['end_padding']   =  $encoder_delays & 0x000FFF;

						// byte $B4  Misc
						$MiscByte = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xB4, 1));
						$info_mpeg_audio_lame_raw['noise_shaping']       = ($MiscByte & 0x03);
						$info_mpeg_audio_lame_raw['stereo_mode']         = ($MiscByte & 0x1C) >> 2;
						$info_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
						$info_mpeg_audio_lame_raw['source_sample_freq']  = ($MiscByte & 0xC0) >> 6;

						$info_mpeg_audio_lame['noise_shaping']           = $info_mpeg_audio_lame_raw['noise_shaping'];
						$info_mpeg_audio_lame['stereo_mode']             = getid3_mp3::LAMEmiscStereoModeLookup($info_mpeg_audio_lame_raw['stereo_mode']);
						$info_mpeg_audio_lame['not_optimal_quality']     = (bool)$info_mpeg_audio_lame_raw['not_optimal_quality'];
						$info_mpeg_audio_lame['source_sample_freq']      = getid3_mp3::LAMEmiscSourceSampleFrequencyLookup($info_mpeg_audio_lame_raw['source_sample_freq']);

						// byte $B5  MP3 Gain
						$info_mpeg_audio_lame_raw['mp3_gain']    = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xB5, 1), false, true);
						$info_mpeg_audio_lame['mp3_gain_db']     = 5 * log10(2) * $info_mpeg_audio_lame_raw['mp3_gain'];
						$info_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($info_mpeg_audio_lame['mp3_gain_db'] / 6));

						// bytes $B6-$B7  Preset and surround info
						$preset_surround_bytes = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xB6, 2));
						// Reserved                                = ($preset_surround_bytes & 0xC000);
						$info_mpeg_audio_lame_raw['surround_info'] = ($preset_surround_bytes & 0x3800);
						$info_mpeg_audio_lame['surround_info']     = getid3_mp3::LAMEsurroundInfoLookup($info_mpeg_audio_lame_raw['surround_info']);
						$info_mpeg_audio_lame['preset_used_id']    = ($preset_surround_bytes & 0x07FF);
						$info_mpeg_audio_lame['preset_used']       = getid3_mp3::LAMEpresetUsedLookup($info_mpeg_audio_lame);
						if (!empty($info_mpeg_audio_lame['preset_used_id']) && empty($info_mpeg_audio_lame['preset_used'])) {
							$getid3->warning('Unknown LAME preset used ('.$info_mpeg_audio_lame['preset_used_id'].') - please report to hide@address.com');
						}
						if (($info_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($info_mpeg_audio_lame['preset_used_id'])) {
							// this may change if 3.90.4 ever comes out
							$info_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
						}

						// bytes $B8-$BB  MusicLength
						$info_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xB8, 4));
						$expected_number_of_audio_bytes = (($info_mpeg_audio_lame['audio_bytes'] > 0) ? $info_mpeg_audio_lame['audio_bytes'] : $info_mpeg_audio['VBR_bytes']);

						// bytes $BC-$BD  MusicCRC
						$info_mpeg_audio_lame['music_crc']    = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xBC, 2));

						// bytes $BE-$BF  CRC-16 of Info Tag
						$info_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($header_data, $lame_tag_offset_contant + 0xBE, 2));


						// LAME CBR
						if ($info_mpeg_audio_lame_raw['vbr_method'] == 1) {

							$info_mpeg_audio['bitrate_mode'] = 'cbr';
							$info_mpeg_audio['bitrate'] = getid3_mp3::ClosestStandardMP3Bitrate($info_mpeg_audio['bitrate']);
							$getid3->info['audio']['bitrate'] = $info_mpeg_audio['bitrate'];
							//if (empty($info_mpeg_audio['bitrate']) || (!empty($info_mpeg_audio_lame['bitrate_min']) && ($info_mpeg_audio_lame['bitrate_min'] != 255))) {
							//    $info_mpeg_audio['bitrate'] = $info_mpeg_audio_lame['bitrate_min'];
							//}

						}
					}
				}

			} else {

				// not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
				$info_mpeg_audio['bitrate_mode'] = 'cbr';
//				if ($recursive_search) {
//					$info_mpeg_audio['bitrate_mode'] = 'vbr';
//					if ($this->RecursiveFrameScanning($offset, $next_frame_test_offset, true)) {
//						$recursive_search = false;
//						$info_mpeg_audio['bitrate_mode'] = 'cbr';
//					}
//					if ($info_mpeg_audio['bitrate_mode'] == 'vbr') {
//						$getid3->warning('VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.');
//					}
//				}

			}
		}

//		if (($expected_number_of_audio_bytes > 0) && ($expected_number_of_audio_bytes != ($getid3->info['avdataend'] - $getid3->info['avdataoffset']))) {
//			if ($expected_number_of_audio_bytes > ($getid3->info['avdataend'] - $getid3->info['avdataoffset'])) {
//				if (($expected_number_of_audio_bytes - ($getid3->info['avdataend'] - $getid3->info['avdataoffset'])) == 1) {
//					$getid3->warning('Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)');
//				} else {
//					$getid3->warning('Probable truncated file: expecting '.$expected_number_of_audio_bytes.' bytes of audio data, only found '.($getid3->info['avdataend'] - $getid3->info['avdataoffset']).' (short by '.($expected_number_of_audio_bytes - ($getid3->info['avdataend'] - $getid3->info['avdataoffset'])).' bytes)');
//				}
//			} else {
//				if ((($getid3->info['avdataend'] - $getid3->info['avdataoffset']) - $expected_number_of_audio_bytes) == 1) {
//				//    $prenullbytefileoffset = ftell($getid3->fp);
//				//    fseek($getid3->fp, $getid3->info['avdataend'], SEEK_SET);
//				//    $PossibleNullByte = fread($getid3->fp, 1);
//				//    fseek($getid3->fp, $prenullbytefileoffset, SEEK_SET);
//				//    if ($PossibleNullByte === "\x00") {
//						$getid3->info['avdataend']--;
//				//        $getid3->warning('Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored');
//				//    } else {
//				//        $getid3->warning('Too much data in file: expecting '.$expected_number_of_audio_bytes.' bytes of audio data, found '.($getid3->info['avdataend'] - $getid3->info['avdataoffset']).' ('.(($getid3->info['avdataend'] - $getid3->info['avdataoffset']) - $expected_number_of_audio_bytes).' bytes too many)');
//				//    }
//				} else {
//					$getid3->warning('Too much data in file: expecting '.$expected_number_of_audio_bytes.' bytes of audio data, found '.($getid3->info['avdataend'] - $getid3->info['avdataoffset']).' ('.(($getid3->info['avdataend'] - $getid3->info['avdataoffset']) - $expected_number_of_audio_bytes).' bytes too many)');
//				}
//			}
//		}

		if (($info_mpeg_audio['bitrate'] == 'free') && empty($getid3->info['audio']['bitrate'])) {
			if (($offset == @$getid3->info['avdataoffset']) && empty($info_mpeg_audio['VBR_frames'])) {
				$frame_byte_length = $this->FreeFormatFrameLength($offset, true);
				if ($frame_byte_length > 0) {
					$info_mpeg_audio['framelength'] = $frame_byte_length;
					if ($info_mpeg_audio['layer'] == '1') {
						// BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
						$getid3->info['audio']['bitrate'] = ((($frame_byte_length / 4) - intval($info_mpeg_audio['padding'])) * $info_mpeg_audio['sample_rate']) / 12;
					} else {
						// Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
						$getid3->info['audio']['bitrate'] = (($frame_byte_length - intval($info_mpeg_audio['padding'])) * $info_mpeg_audio['sample_rate']) / 144;
					}
				} else {
					throw new getid3_exception('Error calculating frame length of free-format MP3 without Xing/LAME header');
				}
			}
		}

		if (!empty($info_mpeg_audio['VBR_frames'])) {
			switch ($info_mpeg_audio['bitrate_mode']) {
				case 'vbr':
				case 'abr':
					if (($info_mpeg_audio['version'] == '1') && ($info_mpeg_audio['layer'] == 1)) {
						$info_mpeg_audio['VBR_bitrate'] = (($info_mpeg_audio['VBR_bytes'] / $info_mpeg_audio['VBR_frames']) * 8) * ($getid3->info['audio']['sample_rate'] / 384);
					} elseif ((($info_mpeg_audio['version'] == '2') || ($info_mpeg_audio['version'] == '2.5')) && ($info_mpeg_audio['layer'] == 3)) {
						$info_mpeg_audio['VBR_bitrate'] = (($info_mpeg_audio['VBR_bytes'] / $info_mpeg_audio['VBR_frames']) * 8) * ($getid3->info['audio']['sample_rate'] / 576);
					} else {
						$info_mpeg_audio['VBR_bitrate'] = (($info_mpeg_audio['VBR_bytes'] / $info_mpeg_audio['VBR_frames']) * 8) * ($getid3->info['audio']['sample_rate'] / 1152);
					}
					if ($info_mpeg_audio['VBR_bitrate'] > 0) {
						$getid3->info['audio']['bitrate']         = $info_mpeg_audio['VBR_bitrate'];
						$info_mpeg_audio['bitrate'] = $info_mpeg_audio['VBR_bitrate']; // to avoid confusion
					}
					break;
			}
		}

		// End variable-bitrate headers
		////////////////////////////////////////////////////////////////////////////////////

//		if ($recursive_search) {
//
//			if (!$this->RecursiveFrameScanning($offset, $next_frame_test_offset)) {
//				return false;
//			}
//
//		}


		return $info_mpeg_audio;

	}



//	private function GetOnlyMPEGaudioInfo($bitrate_histogram = false) {
//
//		$getid3 = $this->getid3;
//
//		$av_data_offset = $getid3->info['avdataoffset'];
//
//		// looks for synch, decodes MPEG audio header
//
//		fseek($getid3->fp, $av_data_offset, SEEK_SET);
//		$header = '';
//		$synch_seek_offset = 0;
//
//		static $mpeg_audio_version_lookup;
//		static $mpeg_audio_layer_lookup;
//		static $mpeg_audio_bitrate_lookup;
//
//		if (empty($mpeg_audio_version_lookup)) {
//			$mpeg_audio_version_lookup = getid3_mp3::MPEGaudioVersionArray();
//			$mpeg_audio_layer_lookup   = getid3_mp3::MPEGaudioLayerArray();
//			$mpeg_audio_bitrate_lookup = getid3_mp3::MPEGaudioBitrateArray();
//
//		}
//
//		$header_len = strlen($header) - intval(round(getid3::FREAD_BUFFER_SIZE / 2));
//		while (true) {
//
//			if (($synch_seek_offset > $header_len) && (($av_data_offset + $synch_seek_offset)  < $getid3->info['avdataend']) && !feof($getid3->fp)) {
//
//				// Synch's not found within the first 128k bytes, give up
//				if ($synch_seek_offset > 131072) {
//					throw new getid3_exception('could not find valid MPEG audio synch within the first 128k bytes');
//				}
//
//				// Sync found - read more
//				if ($header .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE)) {
//					$header_len = strlen($header) - intval(round(getid3::FREAD_BUFFER_SIZE / 2));
//				}
//
//				// Unable to read more
//				else {
//					throw new getid3_exception('could not find valid MPEG audio synch before end of file');
//				}
//			}
//
//			if (($synch_seek_offset + 1) >= strlen($header)) {
//				throw new getid3_exception('could not find valid MPEG synch before end of file');
//			}
//
//			if (($header[$synch_seek_offset] == "\xFF") && ($header[$synch_seek_offset + 1] > "\xE0")) { // synch detected
//
//				if (!isset($first_frame_info) && !isset($getid3->info['mpeg']['audio'])) {
//					$first_frame_info = $getid3->info;
//					$first_frame_av_data_offset = $av_data_offset + $synch_seek_offset;
//					if (!$this->DecodeMPEGaudioHeader($av_data_offset + $synch_seek_offset, false)) {
//						// if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
//						// garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
//						unset($first_frame_info);
//					}
//				}
//
//				$dummy = $getid3->info; // only overwrite real data if valid header found
//
//				if ($this->DecodeMPEGaudioHeader($av_data_offset + $synch_seek_offset, true)) {
//
//					$getid3->info = $dummy;
//					$getid3->info['avdataoffset'] = $av_data_offset + $synch_seek_offset;
//
//					switch ($getid3->info['fileformat']) {
//						case '':
//						case 'id3':
//						case 'ape':
//						case 'mp3':
//							$getid3->info['fileformat']          = 'mp3';
//							$getid3->info['audio']['dataformat'] = 'mp3';
//							break;
//					}
//					if (isset($first_frame_info['mpeg']['audio']['bitrate_mode']) && ($first_frame_info['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
//
//						if (!(abs($getid3->info['audio']['bitrate'] - $first_frame_info['audio']['bitrate']) <= 1)) {
//
//							// If there is garbage data between a valid VBR header frame and a sequence
//							// of valid MPEG-audio frames the VBR data is no longer discarded.
//							$getid3->info                        = $first_frame_info;
//							$getid3->info['avdataoffset']        = $first_frame_av_data_offset;
//							$getid3->info['fileformat']          = 'mp3';
//							$getid3->info['audio']['dataformat'] = 'mp3';
//							$dummy                               = $getid3->info;
//							unset($dummy['mpeg']['audio']);
//							$garbage_offset_start = $first_frame_av_data_offset + $first_frame_info['mpeg']['audio']['framelength'];
//							$garbage_offset_end   = $av_data_offset + $synch_seek_offset;
//
//							if ($this->DecodeMPEGaudioHeader($garbage_offset_end, true, true)) {
//
//								$getid3->info = $dummy;
//								$getid3->info['avdataoffset'] = $garbage_offset_end;
//								$getid3->warning('apparently-valid VBR header not used because could not find '.getid3_mp3::MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($garbage_offset_end - $garbage_offset_start).' bytes between '.$garbage_offset_start.' and '.$garbage_offset_end.'), but did find valid CBR stream starting at '.$garbage_offset_end);
//
//							} else {
//
//								$getid3->warning('using data from VBR header even though could not find '.getid3_mp3::MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($garbage_offset_end - $garbage_offset_start).' bytes between '.$garbage_offset_start.' and '.$garbage_offset_end.')');
//							}
//						}
//					}
//					if (isset($getid3->info['mpeg']['audio']['bitrate_mode']) && ($getid3->info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($getid3->info['mpeg']['audio']['VBR_method'])) {
//						// VBR file with no VBR header
//						$bitrate_histogram = true;
//					}
//
//					if ($bitrate_histogram) {
//
//						$getid3->info['mpeg']['audio']['stereo_distribution']  = array ('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0);
//						$getid3->info['mpeg']['audio']['version_distribution'] = array ('1'=>0, '2'=>0, '2.5'=>0);
//
//						if ($getid3->info['mpeg']['audio']['version'] == '1') {
//							if ($getid3->info['mpeg']['audio']['layer'] == 3) {
//								$getid3->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);
//							} elseif ($getid3->info['mpeg']['audio']['layer'] == 2) {
//								$getid3->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);
//							} elseif ($getid3->info['mpeg']['audio']['layer'] == 1) {
//								$getid3->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);
//							}
//						} elseif ($getid3->info['mpeg']['audio']['layer'] == 1) {
//							$getid3->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);
//						} else {
//							$getid3->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);
//						}
//
//						$dummy = array ('warning'=>$getid3->info['warning'], 'avdataend'=>$getid3->info['avdataend'], 'avdataoffset'=>$getid3->info['avdataoffset']);
//						$synch_start_offset = $getid3->info['avdataoffset'];
//
//						$fast_mode = false;
//						$synch_errors_found = 0;
//
//						while ($this->DecodeMPEGaudioHeader($synch_start_offset, false, $fast_mode)) {
//							$fast_mode = true;
//							$this_frame_bitrate = $mpeg_audio_bitrate_lookup[$mpeg_audio_version_lookup[$dummy['mpeg']['audio']['raw']['version']]][$mpeg_audio_layer_lookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
//
//							if (empty($dummy['mpeg']['audio']['framelength'])) {
//								$synch_errors_found++;
//							} else {
//								$getid3->info['mpeg']['audio']['bitrate_distribution'][$this_frame_bitrate]++;
//								$getid3->info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]++;
//								$getid3->info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]++;
//
//								$synch_start_offset += $dummy['mpeg']['audio']['framelength'];
//							}
//						}
//						if ($synch_errors_found > 0) {
//							$getid3->warning('Found '.$synch_errors_found.' synch errors in histogram analysis');
//							//return false;
//						}
//
//						$bit_total     = 0;
//						$frame_counter = 0;
//						foreach ($getid3->info['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitrate_count) {
//							$frame_counter += $bitrate_count;
//							if ($bitratevalue != 'free') {
//								$bit_total += ($bitratevalue * $bitrate_count);
//							}
//						}
//						$getid3->info['mpeg']['audio']['frame_count'] = $frame_counter;
//						$getid3->info['mpeg']['audio']['bitrate']     = ($bit_total / $frame_counter);
//
//						$getid3->info['audio']['bitrate'] = $getid3->info['mpeg']['audio']['bitrate'];
//
//
//						// Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
//						$distinct_bitrates = 0;
//						foreach ($getid3->info['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) {
//							if ($bitrate_count > 0) {
//								$distinct_bitrates++;
//							}
//						}
//
//						$getid3->info['mpeg']['audio']['bitrate_mode'] = $distinct_bitrates > 1 ? 'vbr' : 'cbr';
//
//						$getid3->info['audio']['bitrate_mode'] = $getid3->info['mpeg']['audio']['bitrate_mode'];
//
//					}
//
//					break; // exit while()
//				}
//			}
//
//
//			// End of file/data
//			if (($av_data_offset + $synch_seek_offset + 1) >= $getid3->info['avdataend']) {
//
//				if (empty($getid3->info['mpeg']['audio'])) {
//					throw new getid3_exception('could not find valid MPEG synch before end of file');
//				}
//
//				break; // exit while()
//			}
//		}
//
//		$getid3->info['audio']['channels']    = $getid3->info['mpeg']['audio']['channels'];
//		$getid3->info['audio']['channelmode'] = $getid3->info['mpeg']['audio']['channelmode'];
//		$getid3->info['audio']['sample_rate'] = $getid3->info['mpeg']['audio']['sample_rate'];
//		return true;
//	}



		private function GuessEncoderOptions() {

		$getid3 = $this->getid3;

		// shortcuts
		if (!empty($getid3->info['mpeg']['audio'])) {
			$info_mpeg_audio = &$getid3->info['mpeg']['audio'];
			if (!empty($info_mpeg_audio['LAME'])) {
				$info_mpeg_audio_lame = &$info_mpeg_audio['LAME'];
			}
		}

		$encoder_options = '';
		static $named_preset_bitrates = array (16, 24, 40, 56, 112, 128, 160, 192, 256);

		if ((@$info_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($info_mpeg_audio['VBR_quality'])) {

			$encoder_options = 'VBR q'.$info_mpeg_audio['VBR_quality'];

		} elseif (!empty($info_mpeg_audio_lame['preset_used']) && (!in_array($info_mpeg_audio_lame['preset_used_id'], $named_preset_bitrates))) {

			$encoder_options = $info_mpeg_audio_lame['preset_used'];

		} elseif (!empty($info_mpeg_audio_lame['vbr_quality'])) {

			static $known_encoder_values = array ();
			if (empty($known_encoder_values)) {

				//$known_encoder_values[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name';
				$known_encoder_values[0xFF][58][1][1][3][2][20500] = '--alt-preset insane';        // 3.90,   3.90.1, 3.92
				$known_encoder_values[0xFF][58][1][1][3][2][20600] = '--alt-preset insane';        // 3.90.2, 3.90.3, 3.91
				$known_encoder_values[0xFF][57][1][1][3][4][20500] = '--alt-preset insane';        // 3.94,   3.95
				$known_encoder_values['**'][78][3][2][3][2][19500] = '--alt-preset extreme';       // 3.90,   3.90.1, 3.92
				$known_encoder_values['**'][78][3][2][3][2][19600] = '--alt-preset extreme';       // 3.90.2, 3.91
				$known_encoder_values['**'][78][3][1][3][2][19600] = '--alt-preset extreme';       // 3.90.3
				$known_encoder_values['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme';  // 3.90,   3.90.1, 3.92
				$known_encoder_values['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme';  // 3.90.2, 3.90.3, 3.91
				$known_encoder_values['**'][78][3][2][3][4][19000] = '--alt-preset standard';      // 3.90,   3.90.1, 3.90.2, 3.91, 3.92
				$known_encoder_values['**'][78][3][1][3][4][19000] = '--alt-preset standard';      // 3.90.3
				$known_encoder_values['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90,   3.90.1, 3.90.2, 3.91, 3.92
				$known_encoder_values['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3
				$known_encoder_values['**'][88][4][1][3][3][19500] = '--r3mix';                    // 3.90,   3.90.1, 3.92
				$known_encoder_values['**'][88][4][1][3][3][19600] = '--r3mix';                    // 3.90.2, 3.90.3, 3.91
				$known_encoder_values['**'][67][4][1][3][4][18000] = '--r3mix';                    // 3.94,   3.95
				$known_encoder_values['**'][68][3][2][3][4][18000] = '--alt-preset medium';        // 3.90.3
				$known_encoder_values['**'][68][4][2][3][4][18000] = '--alt-preset fast medium';   // 3.90.3

				$known_encoder_values[0xFF][99][1][1][1][2][0]     = '--preset studio';            // 3.90,   3.90.1, 3.90.2, 3.91, 3.92
				$known_encoder_values[0xFF][58][2][1][3][2][20600] = '--preset studio';            // 3.90.3, 3.93.1
				$known_encoder_values[0xFF][58][2][1][3][2][20500] = '--preset studio';            // 3.93
				$known_encoder_values[0xFF][57][2][1][3][4][20500] = '--preset studio';            // 3.94,   3.95
				$known_encoder_values[0xC0][88][1][1][1][2][0]     = '--preset cd';                // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
				$known_encoder_values[0xC0][58][2][2][3][2][19600] = '--preset cd';                // 3.90.3, 3.93.1
				$known_encoder_values[0xC0][58][2][2][3][2][19500] = '--preset cd';                // 3.93
				$known_encoder_values[0xC0][57][2][1][3][4][19500] = '--preset cd';                // 3.94,   3.95
				$known_encoder_values[0xA0][78][1][1][3][2][18000] = '--preset hifi';              // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
				$known_encoder_values[0xA0][58][2][2][3][2][18000] = '--preset hifi';              // 3.90.3, 3.93,   3.93.1
				$known_encoder_values[0xA0][57][2][1][3][4][18000] = '--preset hifi';              // 3.94,   3.95
				$known_encoder_values[0x80][67][1][1][3][2][18000] = '--preset tape';              // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
				$known_encoder_values[0x80][67][1][1][3][2][15000] = '--preset radio';             // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
				$known_encoder_values[0x70][67][1][1][3][2][15000] = '--preset fm';                // 3.90,   3.90.1, 3.90.2,   3.91, 3.92
				$known_encoder_values[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm';     // 3.90.3, 3.93,   3.93.1
				$known_encoder_values[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm';     // 3.94,   3.95
				$known_encoder_values[0x38][58][2][2][0][2][10000] = '--preset voice';             // 3.90.3, 3.93,   3.93.1
				$known_encoder_values[0x38][57][2][1][0][4][15000] = '--preset voice';             // 3.94,   3.95
				$known_encoder_values[0x38][57][2][1][0][4][16000] = '--preset voice';             // 3.94a14
				$known_encoder_values[0x28][65][1][1][0][2][7500]  = '--preset mw-us';             // 3.90,   3.90.1, 3.92
				$known_encoder_values[0x28][65][1][1][0][2][7600]  = '--preset mw-us';             // 3.90.2, 3.91
				$known_encoder_values[0x28][58][2][2][0][2][7000]  = '--preset mw-us';             // 3.90.3, 3.93,   3.93.1
				$known_encoder_values[0x28][57][2][1][0][4][10500] = '--preset mw-us';             // 3.94,   3.95
				$known_encoder_values[0x28][57][2][1][0][4][11200] = '--preset mw-us';             // 3.94a14
				$known_encoder_values[0x28][57][2][1][0][4][8800]  = '--preset mw-us';             // 3.94a15
				$known_encoder_values[0x18][58][2][2][0][2][4000]  = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1
				$known_encoder_values[0x18][58][2][2][0][2][3900]  = '--preset phon+/lw/mw-eu/sw'; // 3.93
				$known_encoder_values[0x18][57][2][1][0][4][5900]  = '--preset phon+/lw/mw-eu/sw'; // 3.94,   3.95
				$known_encoder_values[0x18][57][2][1][0][4][6200]  = '--preset phon+/lw/mw-eu/sw'; // 3.94a14
				$known_encoder_values[0x18][57][2][1][0][4][3200]  = '--preset phon+/lw/mw-eu/sw'; // 3.94a15
				$known_encoder_values[0x10][58][2][2][0][2][3800]  = '--preset phone';             // 3.90.3, 3.93.1
				$known_encoder_values[0x10][58][2][2][0][2][3700]  = '--preset phone';             // 3.93
				$known_encoder_values[0x10][57][2][1][0][4][5600]  = '--preset phone';             // 3.94,   3.95
			}

			if (isset($known_encoder_values[$info_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$info_mpeg_audio_lame['vbr_quality']][$info_mpeg_audio_lame['raw']['vbr_method']][$info_mpeg_audio_lame['raw']['noise_shaping']][$info_mpeg_audio_lame['raw']['stereo_mode']][$info_mpeg_audio_lame['ath_type']][$info_mpeg_audio_lame['lowpass_frequency']])) {

				$encoder_options = $known_encoder_values[$info_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$info_mpeg_audio_lame['vbr_quality']][$info_mpeg_audio_lame['raw']['vbr_method']][$info_mpeg_audio_lame['raw']['noise_shaping']][$info_mpeg_audio_lame['raw']['stereo_mode']][$info_mpeg_audio_lame['ath_type']][$info_mpeg_audio_lame['lowpass_frequency']];

			} elseif (isset($known_encoder_values['**'][$info_mpeg_audio_lame['vbr_quality']][$info_mpeg_audio_lame['raw']['vbr_method']][$info_mpeg_audio_lame['raw']['noise_shaping']][$info_mpeg_audio_lame['raw']['stereo_mode']][$info_mpeg_audio_lame['ath_type']][$info_mpeg_audio_lame['lowpass_frequency']])) {

				$encoder_options = $known_encoder_values['**'][$info_mpeg_audio_lame['vbr_quality']][$info_mpeg_audio_lame['raw']['vbr_method']][$info_mpeg_audio_lame['raw']['noise_shaping']][$info_mpeg_audio_lame['raw']['stereo_mode']][$info_mpeg_audio_lame['ath_type']][$info_mpeg_audio_lame['lowpass_frequency']];

			} elseif ($getid3->info['audio']['bitrate_mode'] == 'vbr') {

				// http://gabriel.mp3-tech.org/mp3infotag.html
				// int    Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h

				$LAME_V_value = 10 - ceil($info_mpeg_audio_lame['vbr_quality'] / 10);
				$LAME_q_value = 100 - $info_mpeg_audio_lame['vbr_quality'] - ($LAME_V_value * 10);
				$encoder_options = '-V'.$LAME_V_value.' -q'.$LAME_q_value;

			} elseif ($getid3->info['audio']['bitrate_mode'] == 'cbr') {

				$encoder_options = strtoupper($getid3->info['audio']['bitrate_mode']).ceil($getid3->info['audio']['bitrate'] / 1000);

			} else {

				$encoder_options = strtoupper($getid3->info['audio']['bitrate_mode']);
			}

		} elseif (!empty($info_mpeg_audio_lame['bitrate_abr'])) {

			$encoder_options = 'ABR'.$info_mpeg_audio_lame['bitrate_abr'];

		} elseif (!empty($getid3->info['audio']['bitrate'])) {

			if ($getid3->info['audio']['bitrate_mode'] == 'cbr') {
				$encoder_options = strtoupper($getid3->info['audio']['bitrate_mode']).ceil($getid3->info['audio']['bitrate'] / 1000);
			} else {
				$encoder_options = strtoupper($getid3->info['audio']['bitrate_mode']);
			}

		}
		if (!empty($info_mpeg_audio_lame['bitrate_min'])) {
			$encoder_options .= ' -b'.$info_mpeg_audio_lame['bitrate_min'];
		}

		if (@$info_mpeg_audio_lame['encoding_flags']['nogap_prev'] || @$info_mpeg_audio_lame['encoding_flags']['nogap_next']) {
			$encoder_options .= ' --nogap';
		}

		if (!empty($info_mpeg_audio_lame['lowpass_frequency'])) {
			$exploded_options = explode(' ', $encoder_options, 4);
			if ($exploded_options[0] == '--r3mix') {
				$exploded_options[1] = 'r3mix';
			}
			switch ($exploded_options[0]) {
				case '--preset':
				case '--alt-preset':
				case '--r3mix':
					if ($exploded_options[1] == 'fast') {
						$exploded_options[1] .= ' '.$exploded_options[2];
					}
					switch ($exploded_options[1]) {
						case 'portable':
						case 'medium':
						case 'standard':
						case 'extreme':
						case 'insane':
						case 'fast portable':
						case 'fast medium':
						case 'fast standard':
						case 'fast extreme':
						case 'fast insane':
						case 'r3mix':
							static $expected_lowpass = array (
									'insane|20500'        => 20500,
									'insane|20600'        => 20600,  // 3.90.2, 3.90.3, 3.91
									'medium|18000'        => 18000,
									'fast medium|18000'   => 18000,
									'extreme|19500'       => 19500,  // 3.90,   3.90.1, 3.92, 3.95
									'extreme|19600'       => 19600,  // 3.90.2, 3.90.3, 3.91, 3.93.1
									'fast extreme|19500'  => 19500,  // 3.90,   3.90.1, 3.92, 3.95
									'fast extreme|19600'  => 19600,  // 3.90.2, 3.90.3, 3.91, 3.93.1
									'standard|19000'      => 19000,
									'fast standard|19000' => 19000,
									'r3mix|19500'         => 19500,  // 3.90,   3.90.1, 3.92
									'r3mix|19600'         => 19600,  // 3.90.2, 3.90.3, 3.91
									'r3mix|18000'         => 18000); // 3.94,   3.95
							if (!isset($expected_lowpass[$exploded_options[1].'|'.$info_mpeg_audio_lame['lowpass_frequency']])) {
								$encoder_options .= ' --lowpass '.$info_mpeg_audio_lame['lowpass_frequency'];
							}
							break;

						default:
							break;
					}
					break;
			}
		}

		if (isset($info_mpeg_audio_lame['raw']['source_sample_freq'])) {
			if (($info_mpeg_audio['sample_rate'] == 44100) && ($info_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) {
				$encoder_options .= ' --resample 44100';
			} elseif (($info_mpeg_audio['sample_rate'] == 48000) && ($info_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) {
				$encoder_options .= ' --resample 48000';
			} elseif ($info_mpeg_audio['sample_rate'] < 44100) {
				switch ($info_mpeg_audio_lame['raw']['source_sample_freq']) {
					case 0: // <= 32000
						// may or may not be same as source frequency - ignore
						break;
					case 1: // 44100
					case 2: // 48000
					case 3: // 48000+
						$exploded_options = explode(' ', $encoder_options, 4);
						switch ($exploded_options[0]) {
							case '--preset':
							case '--alt-preset':
								switch ($exploded_options[1]) {
									case 'fast':
									case 'portable':
									case 'medium':
									case 'standard':
									case 'extreme':
									case 'insane':
										$encoder_options .= ' --resample '.$info_mpeg_audio['sample_rate'];
										break;

									default:
										static $expected_resampled_rate = array (
												'phon+/lw/mw-eu/sw|16000' => 16000,
												'mw-us|24000'             => 24000, // 3.95
												'mw-us|32000'             => 32000, // 3.93
												'mw-us|16000'             => 16000, // 3.92
												'phone|16000'             => 16000,
												'phone|11025'             => 11025, // 3.94a15
												'radio|32000'             => 32000, // 3.94a15
												'fm/radio|32000'          => 32000, // 3.92
												'fm|32000'                => 32000, // 3.90
												'voice|32000'             => 32000);
										if (!isset($expected_resampled_rate[$exploded_options[1].'|'.$info_mpeg_audio['sample_rate']])) {
											$encoder_options .= ' --resample '.$info_mpeg_audio['sample_rate'];
										}
										break;
								}
								break;

							case '--r3mix':
							default:
								$encoder_options .= ' --resample '.$info_mpeg_audio['sample_rate'];
								break;
						}
						break;
				}
			}
		}
		if (empty($encoder_options) && !empty($getid3->info['audio']['bitrate']) && !empty($getid3->info['audio']['bitrate_mode'])) {
			//$encoder_options = strtoupper($getid3->info['audio']['bitrate_mode']).ceil($getid3->info['audio']['bitrate'] / 1000);
			$encoder_options = strtoupper($getid3->info['audio']['bitrate_mode']);
		}

		return $encoder_options;
	}



	private function FreeFormatFrameLength($offset, $deep_scan=false) {

		$getid3 = $this->getid3;

		fseek($getid3->fp, $offset, SEEK_SET);
		$mpeg_audio_data = fread($getid3->fp, 32768);

		$sync_pattern1 = substr($mpeg_audio_data, 0, 4);
		// may be different pattern due to padding
		$sync_pattern2 = $sync_pattern1{1}.$sync_pattern1{2}.chr(ord($sync_pattern1{2}) | 0x02).$sync_pattern1{3};
		if ($sync_pattern2 === $sync_pattern1) {
			$sync_pattern2 = $sync_pattern1{0}.$sync_pattern1{1}.chr(ord($sync_pattern1{2}) & 0xFD).$sync_pattern1{3};
		}

		$frame_length = false;
		$frame_length1 = strpos($mpeg_audio_data, $sync_pattern1, 4);
		$frame_length2 = strpos($mpeg_audio_data, $sync_pattern2, 4);
		if ($frame_length1 > 4) {
			$frame_length = $frame_length1;
		}
		if (($frame_length2 > 4) && ($frame_length2 < $frame_length1)) {
			$frame_length = $frame_length2;
		}
		if (!$frame_length) {

			// LAME 3.88 has a different value for modeextension on the first frame vs the rest
			$frame_length1 = strpos($mpeg_audio_data, substr($sync_pattern1, 0, 3), 4);
			$frame_length2 = strpos($mpeg_audio_data, substr($sync_pattern2, 0, 3), 4);

			if ($frame_length1 > 4) {
				$frame_length = $frame_length1;
			}
			if (($frame_length2 > 4) && ($frame_length2 < $frame_length1)) {
				$frame_length = $frame_length2;
			}
			if (!$frame_length) {
				throw new getid3_exception('Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($sync_pattern1).' or '.getid3_lib::PrintHexBytes($sync_pattern2).') after offset '.$offset);
			} else {
				$getid3->warning('ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)');
				$getid3->info['audio']['codec']   = 'LAME';
				$getid3->info['audio']['encoder'] = 'LAME3.88';
				$sync_pattern1 = substr($sync_pattern1, 0, 3);
				$sync_pattern2 = substr($sync_pattern2, 0, 3);
			}
		}

		if ($deep_scan) {

			$actual_frame_length_values = array ();
			$next_offset = $offset + $frame_length;
			while ($next_offset < ($getid3->info['avdataend'] - 6)) {
				fseek($getid3->fp, $next_offset - 1, SEEK_SET);
				$next_sync_pattern = fread($getid3->fp, 6);
				if ((substr($next_sync_pattern, 1, strlen($sync_pattern1)) == $sync_pattern1) || (substr($next_sync_pattern, 1, strlen($sync_pattern2)) == $sync_pattern2)) {
					// good - found where expected
					$actual_frame_length_values[] = $frame_length;
				} elseif ((substr($next_sync_pattern, 0, strlen($sync_pattern1)) == $sync_pattern1) || (substr($next_sync_pattern, 0, strlen($sync_pattern2)) == $sync_pattern2)) {
					// ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
					$actual_frame_length_values[] = ($frame_length - 1);
					$next_offset--;
				} elseif ((substr($next_sync_pattern, 2, strlen($sync_pattern1)) == $sync_pattern1) || (substr($next_sync_pattern, 2, strlen($sync_pattern2)) == $sync_pattern2)) {
					// ok - found one byte later than expected (last frame was padded, first frame wasn't)
					$actual_frame_length_values[] = ($frame_length + 1);
					$next_offset++;
				} else {
					throw new getid3_exception('Did not find expected free-format sync pattern at offset '.$next_offset);
				}
				$next_offset += $frame_length;
			}
			if (count($actual_frame_length_values) > 0) {
				$frame_length = intval(round(array_sum($actual_frame_length_values) / count($actual_frame_length_values)));
			}
		}
		return $frame_length;
	}



//	private function RecursiveFrameScanning(&$offset, &$next_frame_test_offset) {
//
//		$getid3 = $this->getid3;
//
//		$counter = 0;
//
//		for ($i = 0; $i < getid3_mp3::MP3_VALID_CHECK_FRAMES; $i++) {
//
//			// check next getid3_mp3::MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
//			if (($next_frame_test_offset + 4) >= $getid3->info['avdataend']) {
//				// end of file
//				return true;
//			}
//
//			$next_frame_test_array = array ('warning'=>'', 'avdataend'=>$getid3->info['avdataend'], 'avdataoffset'=>$getid3->info['avdataoffset']);
//			if ($this->DecodeMPEGaudioHeader($next_frame_test_offset, false)) {
//
//				// next frame is OK, get ready to check the one after that
//				if (isset($next_frame_test_array['mpeg']['audio']['framelength']) && ($next_frame_test_array['mpeg']['audio']['framelength'] > 0)) {
//					$next_frame_test_offset += $next_frame_test_array['mpeg']['audio']['framelength'];
//				} else {
//					throw new getid3_exception('Frame at offset ('.$offset.') is has an invalid frame length.');
//				}
//
//			} else {
//
//				// next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
//				throw new getid3_exception('Frame at offset ('.$offset.') is valid, but the next one at ('.$next_frame_test_offset.') is not.');
//			}
//		}
//		return true;
//	}



	public static function MPEGaudioVersionArray() {
		return array ('2.5', false, '2', '1');
	}



	public static function MPEGaudioLayerArray() {
		return array (false, 3, 2, 1);
	}



	public static function MPEGaudioBitrateArray() {

		static $mpeg_audio_bitrate;
		if (empty($mpeg_audio_bitrate)) {
			$mpeg_audio_bitrate = array (
				'1'  =>  array (1 => array ('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000),
								2 => array ('free', 32000, 48000, 56000,  64000,  80000,  96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000),
								3 => array ('free', 32000, 40000, 48000,  56000,  64000,  80000,  96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000)
							   ),

				'2'  =>  array (1 => array ('free', 32000, 48000, 56000,  64000,  80000,  96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000),
								2 => array ('free',  8000, 16000, 24000,  32000,  40000,  48000,  56000,  64000,  80000,  96000, 112000, 128000, 144000, 160000),
							   )
			);
			$mpeg_audio_bitrate['2'][3] = $mpeg_audio_bitrate['2'][2];
			$mpeg_audio_bitrate['2.5']  = $mpeg_audio_bitrate['2'];
		}
		return $mpeg_audio_bitrate;
	}



	public static function MPEGaudioFrequencyArray() {

		return array (
				'1'   => array (44100, 48000, 32000),
				'2'   => array (22050, 24000, 16000),
				'2.5' => array (11025, 12000,  8000)
				);
	}



	public static function MPEGaudioChannelModeArray() {

		return array ('stereo', 'joint stereo', 'dual channel', 'mono');
	}



	public static function MPEGaudioModeExtensionArray() {

		return array (
				1 => array ('4-31', '8-31', '12-31', '16-31'),
				2 => array ('4-31', '8-31', '12-31', '16-31'),
				3 => array ('', 'IS', 'MS', 'IS+MS')
			);
	}



	public static function MPEGaudioEmphasisArray() {

		return array ('none', '50/15ms', false, 'CCIT J.17');
	}



	public static function MPEGaudioHeaderBytesValid($head4, $allow_bitrate15=false) {
		return getid3_mp3::MPEGaudioHeaderValid(getid3_mp3::MPEGaudioHeaderDecode($head4), false, $allow_bitrate15);
	}



	public static function MPEGaudioHeaderValid($raw_array, $allow_bitrate15=false) {

		if (($raw_array['synch'] & 0x0FFE) != 0x0FFE) {
			return false;
		}

		static $mpeg_audio_version_lookup;
		static $mpeg_audio_layer_lookup;
		static $mpeg_audio_bitrate_lookup;
		static $mpeg_audio_frequency_lookup;
		static $mpeg_audio_channel_mode_lookup;
		static $mpeg_audio_extention_lookup;
		static $mpeg_audio_emphasis_lookup;

		if (empty($mpeg_audio_version_lookup)) {
			$mpeg_audio_version_lookup      = getid3_mp3::MPEGaudioVersionArray();
			$mpeg_audio_layer_lookup        = getid3_mp3::MPEGaudioLayerArray();
			$mpeg_audio_bitrate_lookup      = getid3_mp3::MPEGaudioBitrateArray();
			$mpeg_audio_frequency_lookup    = getid3_mp3::MPEGaudioFrequencyArray();
			$mpeg_audio_channel_mode_lookup = getid3_mp3::MPEGaudioChannelModeArray();
			$mpeg_audio_extention_lookup    = getid3_mp3::MPEGaudioModeExtensionArray();
			$mpeg_audio_emphasis_lookup     = getid3_mp3::MPEGaudioEmphasisArray();
		}

		if (!isset($mpeg_audio_version_lookup[$raw_array['version']])) {
			return false;
		}

		$decoded_version = $mpeg_audio_version_lookup[$raw_array['version']];

		if (!isset($mpeg_audio_layer_lookup[$raw_array['layer']])) {
			return false;
		}

		$decoded_layer = $mpeg_audio_layer_lookup[$raw_array['layer']];

		if (!isset($mpeg_audio_bitrate_lookup[$decoded_version][$decoded_layer][$raw_array['bitrate']])) {
			if ($raw_array['bitrate'] == 15) {
				// known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
				// let it go through here otherwise file will not be identified
				if (!$allow_bitrate15) {
					return false;
				}
			} else {
				return false;
			}
		}

		// These are just either set or not set, you can't mess that up :)
		// $raw_array['protection'];
		// $raw_array['padding'];
		// $raw_array['private'];
		// $raw_array['copyright'];
		// $raw_array['original'];

		return (isset($mpeg_audio_frequency_lookup[$decoded_version][$raw_array['sample_rate']])  &&
				isset($mpeg_audio_channel_mode_lookup[$raw_array['channelmode']])                 &&
				isset($mpeg_audio_extention_lookup[$decoded_layer][$raw_array['modeextension']])  &&
				isset($mpeg_audio_emphasis_lookup[$raw_array['emphasis']])
			   );
	}



	public static function MPEGaudioHeaderDecode($header_4bytes) {

		// AAAA AAAA  AAAB BCCD  EEEE FFGH  IIJJ KLMM
		// A - Frame sync (all bits set)
		// B - MPEG Audio version ID
		// C - Layer description
		// D - Protection bit
		// E - Bitrate index
		// F - Sampling rate frequency index
		// G - Padding bit
		// H - Private bit
		// I - Channel Mode
		// J - Mode extension (Only if Joint stereo)
		// K - Copyright
		// L - Original
		// M - Emphasis

		$raw_header['synch']         = (getid3_lib::BigEndian2Int(substr($header_4bytes, 0, 2)) & 0xFFE0) >> 4;
		$raw_header['version']       = (ord($header_4bytes{1}) & 0x18) >> 3; //    BB
		$raw_header['layer']         = (ord($header_4bytes{1}) & 0x06) >> 1; //      CC
		$raw_header['protection']    = (ord($header_4bytes{1}) & 0x01);      //        D
		$raw_header['bitrate']       = (ord($header_4bytes{2}) & 0xF0) >> 4; // EEEE
		$raw_header['sample_rate']   = (ord($header_4bytes{2}) & 0x0C) >> 2; //     FF
		$raw_header['padding']       = (ord($header_4bytes{2}) & 0x02) >> 1; //       G
		$raw_header['private']       = (ord($header_4bytes{2}) & 0x01);      //        H
		$raw_header['channelmode']   = (ord($header_4bytes{3}) & 0xC0) >> 6; // II
		$raw_header['modeextension'] = (ord($header_4bytes{3}) & 0x30) >> 4; //   JJ
		$raw_header['copyright']     = (ord($header_4bytes{3}) & 0x08) >> 3; //     K
		$raw_header['original']      = (ord($header_4bytes{3}) & 0x04) >> 2; //      L
		$raw_header['emphasis']      = (ord($header_4bytes{3}) & 0x03);      //       MM

		$raw_header['crc'] = (!$raw_header['protection'] ? getid3_lib::BigEndian2Int(substr($header_4bytes, 4, 2)) : null);

		return $raw_header;
	}



	public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$sample_rate) {

		static $cache = array ();

		if (!isset($cache[$bitrate][$version][$layer][$padding][$sample_rate])) {

			$cache[$bitrate][$version][$layer][$padding][$sample_rate] = false;
			if ($bitrate != 'free') {

				if ($version == '1') {

					if ($layer == '1') {

						// For Layer I slot is 32 bits long
						$frame_length_coefficient = 48;
						$slot_length = 4;

					} else { // Layer 2 / 3

						// for Layer 2 and Layer 3 slot is 8 bits long.
						$frame_length_coefficient = 144;
						$slot_length = 1;

					}

				} else { // MPEG-2 / MPEG-2.5

					if ($layer == '1') {

						// For Layer I slot is 32 bits long
						$frame_length_coefficient = 24;
						$slot_length = 4;

					} elseif ($layer == '2') {

						// for Layer 2 and Layer 3 slot is 8 bits long.
						$frame_length_coefficient = 144;
						$slot_length = 1;

					} else { // layer 3

						// for Layer 2 and Layer 3 slot is 8 bits long.
						$frame_length_coefficient = 72;
						$slot_length = 1;

					}

				}

				// FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
				if ($sample_rate > 0) {
					$new_frame_length  = ($frame_length_coefficient * $bitrate) / $sample_rate;
					$new_frame_length  = floor($new_frame_length / $slot_length) * $slot_length; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I)
					if ($padding) {
						$new_frame_length += $slot_length;
					}
					$cache[$bitrate][$version][$layer][$padding][$sample_rate] = (int)$new_frame_length;
				}
			}
		}
		return $cache[$bitrate][$version][$layer][$padding][$sample_rate];
	}



	public static function ClosestStandardMP3Bitrate($bitrate) {

		static $standard_bitrates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
		static $bitrate_table     = array (0=>'-');
		$round_bitrate = intval(round($bitrate, -3));
		if (!isset($bitrate_table[$round_bitrate])) {
			if ($round_bitrate > 320000) {
				$bitrate_table[$round_bitrate] = round($bitrate, -4);
			} else {
				$last_bitrate = 320000;
				foreach ($standard_bitrates as $standard_bitrate) {
					$bitrate_table[$round_bitrate] = $standard_bitrate;
					if ($round_bitrate >= $standard_bitrate - (($last_bitrate - $standard_bitrate) / 2)) {
						break;
					}
					$last_bitrate = $standard_bitrate;
				}
			}
		}
		return $bitrate_table[$round_bitrate];
	}



	public static function XingVBRidOffset($version, $channel_mode) {

		static $lookup = array (
			'1'   => array ('mono'          => 0x15, // 4 + 17 = 21
							'stereo'        => 0x24, // 4 + 32 = 36
							'joint stereo'  => 0x24,
							'dual channel'  => 0x24
						   ),

			'2'   => array ('mono'          => 0x0D, // 4 +  9 = 13
							'stereo'        => 0x15, // 4 + 17 = 21
							'joint stereo'  => 0x15,
							'dual channel'  => 0x15
						   ),

			'2.5' => array ('mono'          => 0x15,
							'stereo'        => 0x15,
							'joint stereo'  => 0x15,
							'dual channel'  => 0x15
						   )
		);
		return $lookup[$version][$channel_mode];
	}



	public static function LAMEvbrMethodLookup($vbr_method_id) {

		static $lookup = array (
			0x00 => 'unknown',
			0x01 => 'cbr',
			0x02 => 'abr',
			0x03 => 'vbr-old / vbr-rh',
			0x04 => 'vbr-new / vbr-mtrh',
			0x05 => 'vbr-mt',
			0x06 => 'Full VBR Method 4',
			0x08 => 'constant bitrate 2 pass',
			0x09 => 'abr 2 pass',
			0x0F => 'reserved'
		);
		return (isset($lookup[$vbr_method_id]) ? $lookup[$vbr_method_id] : '');
	}



	public static function LAMEmiscStereoModeLookup($stereo_mode_id) {

		static $lookup = array (
			0 => 'mono',
			1 => 'stereo',
			2 => 'dual mono',
			3 => 'joint stereo',
			4 => 'forced stereo',
			5 => 'auto',
			6 => 'intensity stereo',
			7 => 'other'
		);
		return (isset($lookup[$stereo_mode_id]) ? $lookup[$stereo_mode_id] : '');
	}



	public static function LAMEmiscSourceSampleFrequencyLookup($source_sample_frequency_id) {

		static $lookup = array (
			0 => '<= 32 kHz',
			1 => '44.1 kHz',
			2 => '48 kHz',
			3 => '> 48kHz'
		);
		return (isset($lookup[$source_sample_frequency_id]) ? $lookup[$source_sample_frequency_id] : '');
	}



	public static function LAMEsurroundInfoLookup($surround_info_id) {

		static $lookup = array (
			0 => 'no surround info',
			1 => 'DPL encoding',
			2 => 'DPL2 encoding',
			3 => 'Ambisonic encoding'
		);
		return (isset($lookup[$surround_info_id]) ? $lookup[$surround_info_id] : 'reserved');
	}



	public static function LAMEpresetUsedLookup($lame_tag) {

		if ($lame_tag['preset_used_id'] == 0) {
			// no preset used (LAME >=3.93)
			// no preset recorded (LAME <3.93)
			return '';
		}

		static $lookup = array ();
		if (empty($lookup)) {
			for ($i = 8; $i <= 320; $i++) {
				switch ($lame_tag['vbr_method']) {
					case 'cbr':
						$lookup[$i] = '--alt-preset '.$lame_tag['vbr_method'].' '.$i;
						break;
					case 'abr':
					default: // other VBR modes shouldn't be here(?)
						$lookup[$i] = '--alt-preset '.$i;
						break;
				}
			}

			// named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()

			// named alt-presets
			$lookup[1000] = '--r3mix';
			$lookup[1001] = '--alt-preset standard';
			$lookup[1002] = '--alt-preset extreme';
			$lookup[1003] = '--alt-preset insane';
			$lookup[1004] = '--alt-preset fast standard';
			$lookup[1005] = '--alt-preset fast extreme';
			$lookup[1006] = '--alt-preset medium';
			$lookup[1007] = '--alt-preset fast medium';

			// LAME 3.94 additions/changes
			$lookup[1010] = '--preset portable';                                                            // 3.94a15 Oct 21 2003
			$lookup[1015] = '--preset radio';                                                               // 3.94a15 Oct 21 2003

			$lookup[320]  = '--preset insane';                                                              // 3.94a15 Nov 12 2003
			$lookup[430]  = '--preset radio';                                                               // 3.94a15 Nov 12 2003
			$lookup[450]  = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable';  // 3.94a15 Nov 12 2003
			$lookup[460]  = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium';    // 3.94a15 Nov 12 2003
			$lookup[470]  = '--r3mix';                                                                      // 3.94b1  Dec 18 2003
			$lookup[480]  = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard';  // 3.94a15 Nov 12 2003
			$lookup[500]  = '--preset '.(($lame_tag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme';   // 3.94a15 Nov 12 2003
		}
		return (isset($lookup[$lame_tag['preset_used_id']]) ? $lookup[$lame_tag['preset_used_id']] : 'new/unknown preset: '.$lame_tag['preset_used_id'].' - report to hide@address.com');
	}

}

?>
Return current item: mediaIndex