wp/wp-includes/ID3/module.audio.ac3.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     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.ac3.php                                        //
       
    11 // module for analyzing AC-3 (aka Dolby Digital) audio files   //
       
    12 // dependencies: NONE                                          //
       
    13 //                                                            ///
       
    14 /////////////////////////////////////////////////////////////////
       
    15 
       
    16 
       
    17 class getid3_ac3 extends getid3_handler
       
    18 {
       
    19     private $AC3header = array();
       
    20     private $BSIoffset = 0;
       
    21 
       
    22     const syncword = "\x0B\x77";
       
    23 
       
    24 	public function Analyze() {
       
    25 		$info = &$this->getid3->info;
       
    26 
       
    27 		///AH
       
    28 		$info['ac3']['raw']['bsi'] = array();
       
    29 		$thisfile_ac3              = &$info['ac3'];
       
    30 		$thisfile_ac3_raw          = &$thisfile_ac3['raw'];
       
    31 		$thisfile_ac3_raw_bsi      = &$thisfile_ac3_raw['bsi'];
       
    32 
       
    33 
       
    34 		// http://www.atsc.org/standards/a_52a.pdf
       
    35 
       
    36 		$info['fileformat'] = 'ac3';
       
    37 
       
    38 		// An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames
       
    39 		// Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256
       
    40 		// new audio samples per channel. A synchronization information (SI) header at the beginning
       
    41 		// of each frame contains information needed to acquire and maintain synchronization. A
       
    42 		// bit stream information (BSI) header follows SI, and contains parameters describing the coded
       
    43 		// audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the
       
    44 		// end of each frame is an error check field that includes a CRC word for error detection. An
       
    45 		// additional CRC word is located in the SI header, the use of which, by a decoder, is optional.
       
    46 		//
       
    47 		// syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC
       
    48 
       
    49 		// syncinfo() {
       
    50 		// 	 syncword    16
       
    51 		// 	 crc1        16
       
    52 		// 	 fscod        2
       
    53 		// 	 frmsizecod   6
       
    54 		// } /* end of syncinfo */
       
    55 
       
    56 		$this->fseek($info['avdataoffset']);
       
    57 		$this->AC3header['syncinfo'] = $this->fread(5);
       
    58 
       
    59 		if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) {
       
    60 			$thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword;
       
    61 			$offset = 2;
       
    62 		} else {
       
    63 			if (!$this->isDependencyFor('matroska')) {
       
    64 				unset($info['fileformat'], $info['ac3']);
       
    65 				return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"');
       
    66 			}
       
    67 			$offset = 0;
       
    68 			$this->fseek(-2, SEEK_CUR);
       
    69 		}
       
    70 
       
    71 		$info['audio']['dataformat']   = 'ac3';
       
    72 		$info['audio']['bitrate_mode'] = 'cbr';
       
    73 		$info['audio']['lossless']     = false;
       
    74 
       
    75 		$thisfile_ac3_raw['synchinfo']['crc1']       = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2));
       
    76 		$ac3_synchinfo_fscod_frmsizecod              = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1));
       
    77 		$thisfile_ac3_raw['synchinfo']['fscod']      = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6;
       
    78 		$thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F);
       
    79 
       
    80 		$thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
       
    81 		if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
       
    82 			$info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
       
    83 		}
       
    84 
       
    85 		$thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
       
    86 		$thisfile_ac3['bitrate']      = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
       
    87 		$info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
       
    88 
       
    89 		$this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15));
       
    90 		$ac3_bsi_offset = 0;
       
    91 
       
    92 		$thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5);
       
    93 		if ($thisfile_ac3_raw_bsi['bsid'] > 8) {
       
    94 			// Decoders which can decode version 8 will thus be able to decode version numbers less than 8.
       
    95 			// If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used.
       
    96 			// Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8.
       
    97 			$this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8');
       
    98 		    unset($info['ac3']);
       
    99 			return false;
       
   100 		}
       
   101 
       
   102 		$thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
       
   103 		$thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
       
   104 
       
   105 		$thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
       
   106 		$ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
       
   107 		foreach($ac3_coding_mode as $key => $value) {
       
   108 			$thisfile_ac3[$key] = $value;
       
   109 		}
       
   110 		switch ($thisfile_ac3_raw_bsi['acmod']) {
       
   111 			case 0:
       
   112 			case 1:
       
   113 				$info['audio']['channelmode'] = 'mono';
       
   114 				break;
       
   115 			case 3:
       
   116 			case 4:
       
   117 				$info['audio']['channelmode'] = 'stereo';
       
   118 				break;
       
   119 			default:
       
   120 				$info['audio']['channelmode'] = 'surround';
       
   121 				break;
       
   122 		}
       
   123 		$info['audio']['channels'] = $thisfile_ac3['num_channels'];
       
   124 
       
   125 		if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
       
   126 			// If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
       
   127 			$thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
       
   128 			$thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
       
   129 		}
       
   130 
       
   131 		if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
       
   132 			// If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
       
   133 			$thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
       
   134 			$thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
       
   135 		}
       
   136 
       
   137 		if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
       
   138 			// When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
       
   139 			$thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
       
   140 			$thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
       
   141 		}
       
   142 
       
   143 		$thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1);
       
   144 		$thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
       
   145 		if ($thisfile_ac3_raw_bsi['lfeon']) {
       
   146 			//$info['audio']['channels']++;
       
   147 			$info['audio']['channels'] .= '.1';
       
   148 		}
       
   149 
       
   150 		$thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']);
       
   151 
       
   152 		// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
       
   153 		// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
       
   154 		$thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
       
   155 		$thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
       
   156 
       
   157 		$thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1);
       
   158 		if ($thisfile_ac3_raw_bsi['compre_flag']) {
       
   159 			$thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
       
   160 			$thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
       
   161 		}
       
   162 
       
   163 		$thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1);
       
   164 		if ($thisfile_ac3_raw_bsi['langcode_flag']) {
       
   165 			$thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8);
       
   166 		}
       
   167 
       
   168 		$thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1);
       
   169 		if ($thisfile_ac3_raw_bsi['audprodie']) {
       
   170 			$thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
       
   171 			$thisfile_ac3_raw_bsi['roomtyp']  = $this->readHeaderBSI(2);
       
   172 
       
   173 			$thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
       
   174 			$thisfile_ac3['room_type']    = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
       
   175 		}
       
   176 
       
   177 		if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) {
       
   178 			// If acmod is 0, then two completely independent program channels (dual mono)
       
   179 			// are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,
       
   180 			// a number of additional items are present in BSI or audblk to fully describe Ch2.
       
   181 
       
   182 			// This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
       
   183 			// The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
       
   184 			$thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
       
   185 			$thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';
       
   186 
       
   187 			$thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1);
       
   188 			if ($thisfile_ac3_raw_bsi['compre_flag2']) {
       
   189 				$thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
       
   190 				$thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
       
   191 			}
       
   192 
       
   193 			$thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1);
       
   194 			if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
       
   195 				$thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8);
       
   196 			}
       
   197 
       
   198 			$thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1);
       
   199 			if ($thisfile_ac3_raw_bsi['audprodie2']) {
       
   200 				$thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
       
   201 				$thisfile_ac3_raw_bsi['roomtyp2']  = $this->readHeaderBSI(2);
       
   202 
       
   203 				$thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
       
   204 				$thisfile_ac3['room_type2']    = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
       
   205 			}
       
   206 
       
   207 		}
       
   208 
       
   209 		$thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1);
       
   210 
       
   211 		$thisfile_ac3_raw_bsi['original']  = (bool) $this->readHeaderBSI(1);
       
   212 
       
   213 		$thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1);
       
   214 		if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
       
   215 			$thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14);
       
   216 		}
       
   217 
       
   218 		$thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1);
       
   219 		if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
       
   220 			$thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14);
       
   221 		}
       
   222 
       
   223 		$thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1);
       
   224 		if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
       
   225 			$thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6);
       
   226 
       
   227 			$this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
       
   228 
       
   229 			$thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
       
   230 			$this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
       
   231 		}
       
   232 
       
   233 		return true;
       
   234 	}
       
   235 
       
   236 	private function readHeaderBSI($length) {
       
   237 		$data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
       
   238 		$this->BSIoffset += $length;
       
   239 
       
   240 		return bindec($data);
       
   241 	}
       
   242 
       
   243 	public static function sampleRateCodeLookup($fscod) {
       
   244 		static $sampleRateCodeLookup = array(
       
   245 			0 => 48000,
       
   246 			1 => 44100,
       
   247 			2 => 32000,
       
   248 			3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
       
   249 		);
       
   250 		return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
       
   251 	}
       
   252 
       
   253 	public static function serviceTypeLookup($bsmod, $acmod) {
       
   254 		static $serviceTypeLookup = array();
       
   255 		if (empty($serviceTypeLookup)) {
       
   256 			for ($i = 0; $i <= 7; $i++) {
       
   257 				$serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)';
       
   258 				$serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)';
       
   259 				$serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)';
       
   260 				$serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)';
       
   261 				$serviceTypeLookup[4][$i] = 'associated service: dialogue (D)';
       
   262 				$serviceTypeLookup[5][$i] = 'associated service: commentary (C)';
       
   263 				$serviceTypeLookup[6][$i] = 'associated service: emergency (E)';
       
   264 			}
       
   265 
       
   266 			$serviceTypeLookup[7][1]      = 'associated service: voice over (VO)';
       
   267 			for ($i = 2; $i <= 7; $i++) {
       
   268 				$serviceTypeLookup[7][$i] = 'main audio service: karaoke';
       
   269 			}
       
   270 		}
       
   271 		return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
       
   272 	}
       
   273 
       
   274 	public static function audioCodingModeLookup($acmod) {
       
   275 		// array(channel configuration, # channels (not incl LFE), channel order)
       
   276 		static $audioCodingModeLookup = array (
       
   277 			0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'),
       
   278 			1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'),
       
   279 			2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'),
       
   280 			3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'),
       
   281 			4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'),
       
   282 			5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'),
       
   283 			6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'),
       
   284 			7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'),
       
   285 		);
       
   286 		return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
       
   287 	}
       
   288 
       
   289 	public static function centerMixLevelLookup($cmixlev) {
       
   290 		static $centerMixLevelLookup;
       
   291 		if (empty($centerMixLevelLookup)) {
       
   292 			$centerMixLevelLookup = array(
       
   293 				0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB)
       
   294 				1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB)
       
   295 				2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB)
       
   296 				3 => 'reserved'
       
   297 			);
       
   298 		}
       
   299 		return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
       
   300 	}
       
   301 
       
   302 	public static function surroundMixLevelLookup($surmixlev) {
       
   303 		static $surroundMixLevelLookup;
       
   304 		if (empty($surroundMixLevelLookup)) {
       
   305 			$surroundMixLevelLookup = array(
       
   306 				0 => pow(2, -3.0 / 6),
       
   307 				1 => pow(2, -6.0 / 6),
       
   308 				2 => 0,
       
   309 				3 => 'reserved'
       
   310 			);
       
   311 		}
       
   312 		return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
       
   313 	}
       
   314 
       
   315 	public static function dolbySurroundModeLookup($dsurmod) {
       
   316 		static $dolbySurroundModeLookup = array(
       
   317 			0 => 'not indicated',
       
   318 			1 => 'Not Dolby Surround encoded',
       
   319 			2 => 'Dolby Surround encoded',
       
   320 			3 => 'reserved'
       
   321 		);
       
   322 		return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
       
   323 	}
       
   324 
       
   325 	public static function channelsEnabledLookup($acmod, $lfeon) {
       
   326 		$lookup = array(
       
   327 			'ch1'=>(bool) ($acmod == 0),
       
   328 			'ch2'=>(bool) ($acmod == 0),
       
   329 			'left'=>(bool) ($acmod > 1),
       
   330 			'right'=>(bool) ($acmod > 1),
       
   331 			'center'=>(bool) ($acmod & 0x01),
       
   332 			'surround_mono'=>false,
       
   333 			'surround_left'=>false,
       
   334 			'surround_right'=>false,
       
   335 			'lfe'=>$lfeon);
       
   336 		switch ($acmod) {
       
   337 			case 4:
       
   338 			case 5:
       
   339 				$lookup['surround_mono']  = true;
       
   340 				break;
       
   341 			case 6:
       
   342 			case 7:
       
   343 				$lookup['surround_left']  = true;
       
   344 				$lookup['surround_right'] = true;
       
   345 				break;
       
   346 		}
       
   347 		return $lookup;
       
   348 	}
       
   349 
       
   350 	public static function heavyCompression($compre) {
       
   351 		// The first four bits indicate gain changes in 6.02dB increments which can be
       
   352 		// implemented with an arithmetic shift operation. The following four bits
       
   353 		// indicate linear gain changes, and require a 5-bit multiply.
       
   354 		// We will represent the two 4-bit fields of compr as follows:
       
   355 		//   X0 X1 X2 X3 . Y4 Y5 Y6 Y7
       
   356 		// The meaning of the X values is most simply described by considering X to represent a 4-bit
       
   357 		// signed integer with values from -8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The
       
   358 		// following table shows this in detail.
       
   359 
       
   360 		// Meaning of 4 msb of compr
       
   361 		//  7    +48.16 dB
       
   362 		//  6    +42.14 dB
       
   363 		//  5    +36.12 dB
       
   364 		//  4    +30.10 dB
       
   365 		//  3    +24.08 dB
       
   366 		//  2    +18.06 dB
       
   367 		//  1    +12.04 dB
       
   368 		//  0     +6.02 dB
       
   369 		// -1         0 dB
       
   370 		// -2     -6.02 dB
       
   371 		// -3    -12.04 dB
       
   372 		// -4    -18.06 dB
       
   373 		// -5    -24.08 dB
       
   374 		// -6    -30.10 dB
       
   375 		// -7    -36.12 dB
       
   376 		// -8    -42.14 dB
       
   377 
       
   378 		$fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
       
   379 		if ($fourbit{0} == '1') {
       
   380 			$log_gain = -8 + bindec(substr($fourbit, 1));
       
   381 		} else {
       
   382 			$log_gain = bindec(substr($fourbit, 1));
       
   383 		}
       
   384 		$log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2);
       
   385 
       
   386 		// The value of Y is a linear representation of a gain change of up to -6 dB. Y is considered to
       
   387 		// be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can
       
   388 		// represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain
       
   389 		// changes from -0.28 dB to -6.02 dB.
       
   390 
       
   391 		$lin_gain = (16 + ($compre & 0x0F)) / 32;
       
   392 
       
   393 		// The combination of X and Y values allows compr to indicate gain changes from
       
   394 		//  48.16 - 0.28 = +47.89 dB, to
       
   395 		// -42.14 - 6.02 = -48.16 dB.
       
   396 
       
   397 		return $log_gain - $lin_gain;
       
   398 	}
       
   399 
       
   400 	public static function roomTypeLookup($roomtyp) {
       
   401 		static $roomTypeLookup = array(
       
   402 			0 => 'not indicated',
       
   403 			1 => 'large room, X curve monitor',
       
   404 			2 => 'small room, flat monitor',
       
   405 			3 => 'reserved'
       
   406 		);
       
   407 		return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
       
   408 	}
       
   409 
       
   410 	public static function frameSizeLookup($frmsizecod, $fscod) {
       
   411 		$padding     = (bool) ($frmsizecod % 2);
       
   412 		$framesizeid =   floor($frmsizecod / 2);
       
   413 
       
   414 		static $frameSizeLookup = array();
       
   415 		if (empty($frameSizeLookup)) {
       
   416 			$frameSizeLookup = array (
       
   417 				0  => array(128, 138, 192),
       
   418 				1  => array(40, 160, 174, 240),
       
   419 				2  => array(48, 192, 208, 288),
       
   420 				3  => array(56, 224, 242, 336),
       
   421 				4  => array(64, 256, 278, 384),
       
   422 				5  => array(80, 320, 348, 480),
       
   423 				6  => array(96, 384, 416, 576),
       
   424 				7  => array(112, 448, 486, 672),
       
   425 				8  => array(128, 512, 556, 768),
       
   426 				9  => array(160, 640, 696, 960),
       
   427 				10 => array(192, 768, 834, 1152),
       
   428 				11 => array(224, 896, 974, 1344),
       
   429 				12 => array(256, 1024, 1114, 1536),
       
   430 				13 => array(320, 1280, 1392, 1920),
       
   431 				14 => array(384, 1536, 1670, 2304),
       
   432 				15 => array(448, 1792, 1950, 2688),
       
   433 				16 => array(512, 2048, 2228, 3072),
       
   434 				17 => array(576, 2304, 2506, 3456),
       
   435 				18 => array(640, 2560, 2786, 3840)
       
   436 			);
       
   437 		}
       
   438 		if (($fscod == 1) && $padding) {
       
   439 			// frame lengths are padded by 1 word (16 bits) at 44100
       
   440 			$frameSizeLookup[$frmsizecod] += 2;
       
   441 		}
       
   442 		return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
       
   443 	}
       
   444 
       
   445 	public static function bitrateLookup($frmsizecod) {
       
   446 		$framesizeid =   floor($frmsizecod / 2);
       
   447 
       
   448 		static $bitrateLookup = array(
       
   449 			0  => 32000,
       
   450 			1  => 40000,
       
   451 			2  => 48000,
       
   452 			3  => 56000,
       
   453 			4  => 64000,
       
   454 			5  => 80000,
       
   455 			6  => 96000,
       
   456 			7  => 112000,
       
   457 			8  => 128000,
       
   458 			9  => 160000,
       
   459 			10 => 192000,
       
   460 			11 => 224000,
       
   461 			12 => 256000,
       
   462 			13 => 320000,
       
   463 			14 => 384000,
       
   464 			15 => 448000,
       
   465 			16 => 512000,
       
   466 			17 => 576000,
       
   467 			18 => 640000
       
   468 		);
       
   469 		return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
       
   470 	}
       
   471 
       
   472 
       
   473 }