Mercurial > judyates
diff e2gallerypro/e2upload/Backend/Assets/getid3/module.audio.xiph.php @ 3:3f6b44aa6b35 judyates
[svn r4] added ability to buy stuff, from a Prints page, but it doesn't work well with the css, and it also has not been fitted into the perl make system.
author | rlm |
---|---|
date | Mon, 22 Feb 2010 08:02:39 -0500 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/e2gallerypro/e2upload/Backend/Assets/getid3/module.audio.xiph.php Mon Feb 22 08:02:39 2010 -0500 1.3 @@ -0,0 +1,952 @@ 1.4 +<?php 1.5 +// +----------------------------------------------------------------------+ 1.6 +// | PHP version 5 | 1.7 +// +----------------------------------------------------------------------+ 1.8 +// | Copyright (c) 2002-2006 James Heinrich, Allan Hansen | 1.9 +// +----------------------------------------------------------------------+ 1.10 +// | This source file is subject to version 2 of the GPL license, | 1.11 +// | that is bundled with this package in the file license.txt and is | 1.12 +// | available through the world-wide-web at the following url: | 1.13 +// | http://www.gnu.org/copyleft/gpl.html | 1.14 +// +----------------------------------------------------------------------+ 1.15 +// | getID3() - http://getid3.sourceforge.net or http://www.getid3.org | 1.16 +// +----------------------------------------------------------------------+ 1.17 +// | Authors: James Heinrich <infoØgetid3*org> | 1.18 +// | Allan Hansen <ahØartemis*dk> | 1.19 +// +----------------------------------------------------------------------+ 1.20 +// | module.audio.xiph.php | 1.21 +// | Module for analyzing Xiph.org audio file formats: | 1.22 +// | Ogg Vorbis, FLAC, OggFLAC and Speex - not Ogg Theora | 1.23 +// | dependencies: module.lib.image_size.php (optional) | 1.24 +// +----------------------------------------------------------------------+ 1.25 +// 1.26 +// $Id: module.audio.xiph.php,v 1.5 2006/12/03 21:12:43 ah Exp $ 1.27 + 1.28 + 1.29 + 1.30 +class getid3_xiph extends getid3_handler 1.31 +{ 1.32 + 1.33 + public function Analyze() { 1.34 + 1.35 + $getid3 = $this->getid3; 1.36 + 1.37 + if ($getid3->option_tags_images) { 1.38 + $getid3->include_module('lib.image_size'); 1.39 + } 1.40 + 1.41 + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); 1.42 + 1.43 + $magic = fread($getid3->fp, 4); 1.44 + 1.45 + if ($magic == 'OggS') { 1.46 + return $this->ParseOgg(); 1.47 + } 1.48 + 1.49 + if ($magic == 'fLaC') { 1.50 + return $this->ParseFLAC(); 1.51 + } 1.52 + 1.53 + } 1.54 + 1.55 + 1.56 + 1.57 + private function ParseOgg() { 1.58 + 1.59 + $getid3 = $this->getid3; 1.60 + 1.61 + fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); 1.62 + 1.63 + $getid3->info['audio'] = $getid3->info['ogg'] = array (); 1.64 + $info_ogg = &$getid3->info['ogg']; 1.65 + $info_audio = &$getid3->info['audio']; 1.66 + 1.67 + $getid3->info['fileformat'] = 'ogg'; 1.68 + 1.69 + 1.70 + //// Page 1 - Stream Header 1.71 + 1.72 + $ogg_page_info = $this->ParseOggPageHeader(); 1.73 + $info_ogg['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; 1.74 + 1.75 + if (ftell($getid3->fp) >= getid3::FREAD_BUFFER_SIZE) { 1.76 + throw new getid3_exception('Could not find start of Ogg page in the first '.getid3::FREAD_BUFFER_SIZE.' bytes (this might not be an Ogg file?)'); 1.77 + } 1.78 + 1.79 + $file_data = fread($getid3->fp, $ogg_page_info['page_length']); 1.80 + $file_data_offset = 0; 1.81 + 1.82 + 1.83 + // OggFLAC 1.84 + if (substr($file_data, 0, 4) == 'fLaC') { 1.85 + 1.86 + $info_audio['dataformat'] = 'flac'; 1.87 + $info_audio['bitrate_mode'] = 'vbr'; 1.88 + $info_audio['lossless'] = true; 1.89 + 1.90 + } 1.91 + 1.92 + 1.93 + // Ogg Vorbis 1.94 + elseif (substr($file_data, 1, 6) == 'vorbis') { 1.95 + 1.96 + $info_audio['dataformat'] = 'vorbis'; 1.97 + $info_audio['lossless'] = false; 1.98 + 1.99 + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int($file_data[0]); 1.100 + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['stream_type'] = substr($file_data, 1, 6); // hard-coded to 'vorbis' 1.101 + 1.102 + getid3_lib::ReadSequence('LittleEndian2Int', $info_ogg, $file_data, 7, 1.103 + array ( 1.104 + 'bitstreamversion' => 4, 1.105 + 'numberofchannels' => 1, 1.106 + 'samplerate' => 4, 1.107 + 'bitrate_max' => 4, 1.108 + 'bitrate_nominal' => 4, 1.109 + 'bitrate_min' => 4 1.110 + ) 1.111 + ); 1.112 + 1.113 + $n28 = getid3_lib::LittleEndian2Int($file_data{28}); 1.114 + $info_ogg['blocksize_small'] = pow(2, $n28 & 0x0F); 1.115 + $info_ogg['blocksize_large'] = pow(2, ($n28 & 0xF0) >> 4); 1.116 + $info_ogg['stop_bit'] = $n28; 1.117 + 1.118 + $info_audio['channels'] = $info_ogg['numberofchannels']; 1.119 + $info_audio['sample_rate'] = $info_ogg['samplerate']; 1.120 + 1.121 + $info_audio['bitrate_mode'] = 'vbr'; // overridden if actually abr 1.122 + 1.123 + if ($info_ogg['bitrate_max'] == 0xFFFFFFFF) { 1.124 + unset($info_ogg['bitrate_max']); 1.125 + $info_audio['bitrate_mode'] = 'abr'; 1.126 + } 1.127 + 1.128 + if ($info_ogg['bitrate_nominal'] == 0xFFFFFFFF) { 1.129 + unset($info_ogg['bitrate_nominal']); 1.130 + } 1.131 + 1.132 + if ($info_ogg['bitrate_min'] == 0xFFFFFFFF) { 1.133 + unset($info_ogg['bitrate_min']); 1.134 + $info_audio['bitrate_mode'] = 'abr'; 1.135 + } 1.136 + } 1.137 + 1.138 + 1.139 + // Speex 1.140 + elseif (substr($file_data, 0, 8) == 'Speex ') { 1.141 + 1.142 + // http://www.speex.org/manual/node10.html 1.143 + 1.144 + $info_audio['dataformat'] = 'speex'; 1.145 + $getid3->info['mime_type'] = 'audio/speex'; 1.146 + $info_audio['bitrate_mode'] = 'abr'; 1.147 + $info_audio['lossless'] = false; 1.148 + 1.149 + getid3_lib::ReadSequence('LittleEndian2Int', $info_ogg['pageheader'][$ogg_page_info['page_seqno']], $file_data, 0, 1.150 + array ( 1.151 + 'speex_string' => -8, // hard-coded to 'Speex ' 1.152 + 'speex_version' => -20, // string 1.153 + 'speex_version_id' => 4, 1.154 + 'header_size' => 4, 1.155 + 'rate' => 4, 1.156 + 'mode' => 4, 1.157 + 'mode_bitstream_version' => 4, 1.158 + 'nb_channels' => 4, 1.159 + 'bitrate' => 4, 1.160 + 'framesize' => 4, 1.161 + 'vbr' => 4, 1.162 + 'frames_per_packet' => 4, 1.163 + 'extra_headers' => 4, 1.164 + 'reserved1' => 4, 1.165 + 'reserved2' => 4 1.166 + ) 1.167 + ); 1.168 + 1.169 + $getid3->info['speex']['speex_version'] = trim($info_ogg['pageheader'][$ogg_page_info['page_seqno']]['speex_version']); 1.170 + $getid3->info['speex']['sample_rate'] = $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['rate']; 1.171 + $getid3->info['speex']['channels'] = $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['nb_channels']; 1.172 + $getid3->info['speex']['vbr'] = (bool)$info_ogg['pageheader'][$ogg_page_info['page_seqno']]['vbr']; 1.173 + $getid3->info['speex']['band_type'] = getid3_xiph::SpeexBandModeLookup($info_ogg['pageheader'][$ogg_page_info['page_seqno']]['mode']); 1.174 + 1.175 + $info_audio['sample_rate'] = $getid3->info['speex']['sample_rate']; 1.176 + $info_audio['channels'] = $getid3->info['speex']['channels']; 1.177 + 1.178 + if ($getid3->info['speex']['vbr']) { 1.179 + $info_audio['bitrate_mode'] = 'vbr'; 1.180 + } 1.181 + } 1.182 + 1.183 + // Unsupported Ogg file 1.184 + else { 1.185 + 1.186 + throw new getid3_exception('Expecting either "Speex " or "vorbis" identifier strings, found neither'); 1.187 + } 1.188 + 1.189 + 1.190 + //// Page 2 - Comment Header 1.191 + 1.192 + $ogg_page_info = $this->ParseOggPageHeader(); 1.193 + $info_ogg['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; 1.194 + 1.195 + switch ($info_audio['dataformat']) { 1.196 + 1.197 + case 'vorbis': 1.198 + $file_data = fread($getid3->fp, $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['page_length']); 1.199 + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($file_data, 0, 1)); 1.200 + $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['stream_type'] = substr($file_data, 1, 6); // hard-coded to 'vorbis' 1.201 + $this->ParseVorbisCommentsFilepointer(); 1.202 + break; 1.203 + 1.204 + case 'flac': 1.205 + if (!$this->FLACparseMETAdata()) { 1.206 + throw new getid3_exception('Failed to parse FLAC headers'); 1.207 + } 1.208 + break; 1.209 + 1.210 + case 'speex': 1.211 + fseek($getid3->fp, $info_ogg['pageheader'][$ogg_page_info['page_seqno']]['page_length'], SEEK_CUR); 1.212 + $this->ParseVorbisCommentsFilepointer(); 1.213 + break; 1.214 + } 1.215 + 1.216 + 1.217 + //// Last Page - Number of Samples 1.218 + 1.219 + fseek($getid3->fp, max($getid3->info['avdataend'] - getid3::FREAD_BUFFER_SIZE, 0), SEEK_SET); 1.220 + $last_chunk_of_ogg = strrev(fread($getid3->fp, getid3::FREAD_BUFFER_SIZE)); 1.221 + 1.222 + if ($last_OggS_postion = strpos($last_chunk_of_ogg, 'SggO')) { 1.223 + fseek($getid3->fp, $getid3->info['avdataend'] - ($last_OggS_postion + strlen('SggO')), SEEK_SET); 1.224 + $getid3->info['avdataend'] = ftell($getid3->fp); 1.225 + $info_ogg['pageheader']['eos'] = $this->ParseOggPageHeader(); 1.226 + $info_ogg['samples'] = $info_ogg['pageheader']['eos']['pcm_abs_position']; 1.227 + $info_ogg['bitrate_average'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / ($info_ogg['samples'] / $info_audio['sample_rate']); 1.228 + } 1.229 + 1.230 + if (!empty($info_ogg['bitrate_average'])) { 1.231 + $info_audio['bitrate'] = $info_ogg['bitrate_average']; 1.232 + } elseif (!empty($info_ogg['bitrate_nominal'])) { 1.233 + $info_audio['bitrate'] = $info_ogg['bitrate_nominal']; 1.234 + } elseif (!empty($info_ogg['bitrate_min']) && !empty($info_ogg['bitrate_max'])) { 1.235 + $info_audio['bitrate'] = ($info_ogg['bitrate_min'] + $info_ogg['bitrate_max']) / 2; 1.236 + } 1.237 + if (isset($info_audio['bitrate']) && !isset($getid3->info['playtime_seconds'])) { 1.238 + $getid3->info['playtime_seconds'] = (float)((($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $info_audio['bitrate']); 1.239 + } 1.240 + 1.241 + if (isset($info_ogg['vendor'])) { 1.242 + $info_audio['encoder'] = preg_replace('/^Encoded with /', '', $info_ogg['vendor']); 1.243 + 1.244 + // Vorbis only 1.245 + if ($info_audio['dataformat'] == 'vorbis') { 1.246 + 1.247 + // Vorbis 1.0 starts with Xiph.Org 1.248 + if (preg_match('/^Xiph.Org/', $info_audio['encoder'])) { 1.249 + 1.250 + if ($info_audio['bitrate_mode'] == 'abr') { 1.251 + 1.252 + // Set -b 128 on abr files 1.253 + $info_audio['encoder_options'] = '-b '.round($info_ogg['bitrate_nominal'] / 1000); 1.254 + 1.255 + } elseif (($info_audio['bitrate_mode'] == 'vbr') && ($info_audio['channels'] == 2) && ($info_audio['sample_rate'] >= 44100) && ($info_audio['sample_rate'] <= 48000)) { 1.256 + // Set -q N on vbr files 1.257 + $info_audio['encoder_options'] = '-q '.getid3_xiph::GetQualityFromNominalBitrate($info_ogg['bitrate_nominal']); 1.258 + } 1.259 + } 1.260 + 1.261 + if (empty($info_audio['encoder_options']) && !empty($info_ogg['bitrate_nominal'])) { 1.262 + $info_audio['encoder_options'] = 'Nominal bitrate: '.intval(round($info_ogg['bitrate_nominal'] / 1000)).'kbps'; 1.263 + } 1.264 + } 1.265 + } 1.266 + 1.267 + return true; 1.268 + } 1.269 + 1.270 + 1.271 + 1.272 + private function ParseOggPageHeader() { 1.273 + 1.274 + $getid3 = $this->getid3; 1.275 + 1.276 + // http://xiph.org/ogg/vorbis/doc/framing.html 1.277 + $ogg_header['page_start_offset'] = ftell($getid3->fp); // where we started from in the file 1.278 + 1.279 + $file_data = fread($getid3->fp, getid3::FREAD_BUFFER_SIZE); 1.280 + $file_data_offset = 0; 1.281 + 1.282 + while ((substr($file_data, $file_data_offset++, 4) != 'OggS')) { 1.283 + if ((ftell($getid3->fp) - $ogg_header['page_start_offset']) >= getid3::FREAD_BUFFER_SIZE) { 1.284 + // should be found before here 1.285 + return false; 1.286 + } 1.287 + if ((($file_data_offset + 28) > strlen($file_data)) || (strlen($file_data) < 28)) { 1.288 + if (feof($getid3->fp) || (($file_data .= fread($getid3->fp, getid3::FREAD_BUFFER_SIZE)) === false)) { 1.289 + // get some more data, unless eof, in which case fail 1.290 + return false; 1.291 + } 1.292 + } 1.293 + } 1.294 + 1.295 + $file_data_offset += 3; // page, delimited by 'OggS' 1.296 + 1.297 + getid3_lib::ReadSequence('LittleEndian2Int', $ogg_header, $file_data, $file_data_offset, 1.298 + array ( 1.299 + 'stream_structver' => 1, 1.300 + 'flags_raw' => 1, 1.301 + 'pcm_abs_position' => 8, 1.302 + 'stream_serialno' => 4, 1.303 + 'page_seqno' => 4, 1.304 + 'page_checksum' => 4, 1.305 + 'page_segments' => 1 1.306 + ) 1.307 + ); 1.308 + 1.309 + $file_data_offset += 23; 1.310 + 1.311 + $ogg_header['flags']['fresh'] = (bool)($ogg_header['flags_raw'] & 0x01); // fresh packet 1.312 + $ogg_header['flags']['bos'] = (bool)($ogg_header['flags_raw'] & 0x02); // first page of logical bitstream (bos) 1.313 + $ogg_header['flags']['eos'] = (bool)($ogg_header['flags_raw'] & 0x04); // last page of logical bitstream (eos) 1.314 + 1.315 + $ogg_header['page_length'] = 0; 1.316 + for ($i = 0; $i < $ogg_header['page_segments']; $i++) { 1.317 + $ogg_header['segment_table'][$i] = getid3_lib::LittleEndian2Int($file_data{$file_data_offset++}); 1.318 + $ogg_header['page_length'] += $ogg_header['segment_table'][$i]; 1.319 + } 1.320 + $ogg_header['header_end_offset'] = $ogg_header['page_start_offset'] + $file_data_offset; 1.321 + $ogg_header['page_end_offset'] = $ogg_header['header_end_offset'] + $ogg_header['page_length']; 1.322 + fseek($getid3->fp, $ogg_header['header_end_offset'], SEEK_SET); 1.323 + 1.324 + return $ogg_header; 1.325 + } 1.326 + 1.327 + 1.328 + 1.329 + private function ParseVorbisCommentsFilepointer() { 1.330 + 1.331 + $getid3 = $this->getid3; 1.332 + 1.333 + $original_offset = ftell($getid3->fp); 1.334 + $comment_start_offset = $original_offset; 1.335 + $comment_data_offset = 0; 1.336 + $vorbis_comment_page = 1; 1.337 + 1.338 + switch ($getid3->info['audio']['dataformat']) { 1.339 + 1.340 + case 'vorbis': 1.341 + $comment_start_offset = $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_start_offset']; // Second Ogg page, after header block 1.342 + fseek($getid3->fp, $comment_start_offset, SEEK_SET); 1.343 + $comment_data_offset = 27 + $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_segments']; 1.344 + $comment_data = fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1) + $comment_data_offset); 1.345 + $comment_data_offset += (strlen('vorbis') + 1); 1.346 + break; 1.347 + 1.348 + 1.349 + case 'flac': 1.350 + fseek($getid3->fp, $getid3->info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4, SEEK_SET); 1.351 + $comment_data = fread($getid3->fp, $getid3->info['flac']['VORBIS_COMMENT']['raw']['block_length']); 1.352 + break; 1.353 + 1.354 + 1.355 + case 'speex': 1.356 + $comment_start_offset = $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_start_offset']; // Second Ogg page, after header block 1.357 + fseek($getid3->fp, $comment_start_offset, SEEK_SET); 1.358 + $comment_data_offset = 27 + $getid3->info['ogg']['pageheader'][$vorbis_comment_page]['page_segments']; 1.359 + $comment_data = fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1) + $comment_data_offset); 1.360 + break; 1.361 + 1.362 + 1.363 + default: 1.364 + return false; 1.365 + } 1.366 + 1.367 + $vendor_size = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4)); 1.368 + $comment_data_offset += 4; 1.369 + 1.370 + $getid3->info['ogg']['vendor'] = substr($comment_data, $comment_data_offset, $vendor_size); 1.371 + $comment_data_offset += $vendor_size; 1.372 + 1.373 + $comments_count = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4)); 1.374 + $comment_data_offset += 4; 1.375 + 1.376 + $getid3->info['avdataoffset'] = $comment_start_offset + $comment_data_offset; 1.377 + 1.378 + for ($i = 0; $i < $comments_count; $i++) { 1.379 + 1.380 + $getid3->info['ogg']['comments_raw'][$i]['dataoffset'] = $comment_start_offset + $comment_data_offset; 1.381 + 1.382 + if (ftell($getid3->fp) < ($getid3->info['ogg']['comments_raw'][$i]['dataoffset'] + 4)) { 1.383 + $vorbis_comment_page++; 1.384 + 1.385 + $ogg_page_info = $this->ParseOggPageHeader(); 1.386 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; 1.387 + 1.388 + // First, save what we haven't read yet 1.389 + $as_yet_unused_data = substr($comment_data, $comment_data_offset); 1.390 + 1.391 + // Then take that data off the end 1.392 + $comment_data = substr($comment_data, 0, $comment_data_offset); 1.393 + 1.394 + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct 1.395 + $comment_data .= str_repeat("\x00", 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); 1.396 + $comment_data_offset += (27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); 1.397 + 1.398 + // Finally, stick the unused data back on the end 1.399 + $comment_data .= $as_yet_unused_data; 1.400 + 1.401 + $comment_data .= fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1)); 1.402 + } 1.403 + $getid3->info['ogg']['comments_raw'][$i]['size'] = getid3_lib::LittleEndian2Int(substr($comment_data, $comment_data_offset, 4)); 1.404 + 1.405 + // replace avdataoffset with position just after the last vorbiscomment 1.406 + $getid3->info['avdataoffset'] = $getid3->info['ogg']['comments_raw'][$i]['dataoffset'] + $getid3->info['ogg']['comments_raw'][$i]['size'] + 4; 1.407 + 1.408 + $comment_data_offset += 4; 1.409 + while ((strlen($comment_data) - $comment_data_offset) < $getid3->info['ogg']['comments_raw'][$i]['size']) { 1.410 + 1.411 + if (($getid3->info['ogg']['comments_raw'][$i]['size'] > $getid3->info['avdataend']) || ($getid3->info['ogg']['comments_raw'][$i]['size'] < 0)) { 1.412 + throw new getid3_exception('Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($getid3->info['ogg']['comments_raw'][$i]['size']).' bytes) - aborting reading comments'); 1.413 + } 1.414 + 1.415 + $vorbis_comment_page++; 1.416 + 1.417 + $ogg_page_info = $this->ParseOggPageHeader(); 1.418 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']] = $ogg_page_info; 1.419 + 1.420 + // First, save what we haven't read yet 1.421 + $as_yet_unused_data = substr($comment_data, $comment_data_offset); 1.422 + 1.423 + // Then take that data off the end 1.424 + $comment_data = substr($comment_data, 0, $comment_data_offset); 1.425 + 1.426 + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct 1.427 + $comment_data .= str_repeat("\x00", 27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); 1.428 + $comment_data_offset += (27 + $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_segments']); 1.429 + 1.430 + // Finally, stick the unused data back on the end 1.431 + $comment_data .= $as_yet_unused_data; 1.432 + 1.433 + //$comment_data .= fread($getid3->fp, $getid3->info['ogg']['pageheader'][$ogg_page_info['page_seqno']]['page_length']); 1.434 + $comment_data .= fread($getid3->fp, getid3_xiph::OggPageSegmentLength($getid3->info['ogg']['pageheader'][$vorbis_comment_page], 1)); 1.435 + 1.436 + //$filebaseoffset += $ogg_page_info['header_end_offset'] - $ogg_page_info['page_start_offset']; 1.437 + } 1.438 + $comment_string = substr($comment_data, $comment_data_offset, $getid3->info['ogg']['comments_raw'][$i]['size']); 1.439 + $comment_data_offset += $getid3->info['ogg']['comments_raw'][$i]['size']; 1.440 + 1.441 + if (!$comment_string) { 1.442 + 1.443 + // no comment? 1.444 + $getid3->warning('Blank Ogg comment ['.$i.']'); 1.445 + 1.446 + } elseif (strstr($comment_string, '=')) { 1.447 + 1.448 + $comment_exploded = explode('=', $comment_string, 2); 1.449 + $getid3->info['ogg']['comments_raw'][$i]['key'] = strtoupper($comment_exploded[0]); 1.450 + $getid3->info['ogg']['comments_raw'][$i]['value'] = @$comment_exploded[1]; 1.451 + $getid3->info['ogg']['comments_raw'][$i]['data'] = base64_decode($getid3->info['ogg']['comments_raw'][$i]['value']); 1.452 + 1.453 + $getid3->info['ogg']['comments'][strtolower($getid3->info['ogg']['comments_raw'][$i]['key'])][] = $getid3->info['ogg']['comments_raw'][$i]['value']; 1.454 + 1.455 + if ($getid3->option_tags_images) { 1.456 + $image_chunk_check = getid3_lib_image_size::get($getid3->info['ogg']['comments_raw'][$i]['data']); 1.457 + $getid3->info['ogg']['comments_raw'][$i]['image_mime'] = image_type_to_mime_type($image_chunk_check[2]); 1.458 + } 1.459 + 1.460 + if (!@$getid3->info['ogg']['comments_raw'][$i]['image_mime'] || ($getid3->info['ogg']['comments_raw'][$i]['image_mime'] == 'application/octet-stream')) { 1.461 + unset($getid3->info['ogg']['comments_raw'][$i]['image_mime']); 1.462 + unset($getid3->info['ogg']['comments_raw'][$i]['data']); 1.463 + } 1.464 + 1.465 + 1.466 + } else { 1.467 + 1.468 + $getid3->warning('[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$comment_string); 1.469 + } 1.470 + } 1.471 + 1.472 + 1.473 + // Replay Gain Adjustment 1.474 + // http://privatewww.essex.ac.uk/~djmrob/replaygain/ 1.475 + if (isset($getid3->info['ogg']['comments']) && is_array($getid3->info['ogg']['comments'])) { 1.476 + foreach ($getid3->info['ogg']['comments'] as $index => $commentvalue) { 1.477 + switch ($index) { 1.478 + case 'rg_audiophile': 1.479 + case 'replaygain_album_gain': 1.480 + $getid3->info['replay_gain']['album']['adjustment'] = (float)$commentvalue[0]; 1.481 + unset($getid3->info['ogg']['comments'][$index]); 1.482 + break; 1.483 + 1.484 + case 'rg_radio': 1.485 + case 'replaygain_track_gain': 1.486 + $getid3->info['replay_gain']['track']['adjustment'] = (float)$commentvalue[0]; 1.487 + unset($getid3->info['ogg']['comments'][$index]); 1.488 + break; 1.489 + 1.490 + case 'replaygain_album_peak': 1.491 + $getid3->info['replay_gain']['album']['peak'] = (float)$commentvalue[0]; 1.492 + unset($getid3->info['ogg']['comments'][$index]); 1.493 + break; 1.494 + 1.495 + case 'rg_peak': 1.496 + case 'replaygain_track_peak': 1.497 + $getid3->info['replay_gain']['track']['peak'] = (float)$commentvalue[0]; 1.498 + unset($getid3->info['ogg']['comments'][$index]); 1.499 + break; 1.500 + 1.501 + case 'replaygain_reference_loudness': 1.502 + $getid3->info['replay_gain']['reference_volume'] = (float)$commentvalue[0]; 1.503 + unset($getid3->info['ogg']['comments'][$index]); 1.504 + break; 1.505 + } 1.506 + } 1.507 + } 1.508 + 1.509 + fseek($getid3->fp, $original_offset, SEEK_SET); 1.510 + 1.511 + return true; 1.512 + } 1.513 + 1.514 + 1.515 + 1.516 + private function ParseFLAC() { 1.517 + 1.518 + $getid3 = $this->getid3; 1.519 + 1.520 + // http://flac.sourceforge.net/format.html 1.521 + 1.522 + $getid3->info['fileformat'] = 'flac'; 1.523 + $getid3->info['audio']['dataformat'] = 'flac'; 1.524 + $getid3->info['audio']['bitrate_mode'] = 'vbr'; 1.525 + $getid3->info['audio']['lossless'] = true; 1.526 + 1.527 + return $this->FLACparseMETAdata(); 1.528 + } 1.529 + 1.530 + 1.531 + 1.532 + private function FLACparseMETAdata() { 1.533 + 1.534 + $getid3 = $this->getid3; 1.535 + 1.536 + do { 1.537 + 1.538 + $meta_data_block_offset = ftell($getid3->fp); 1.539 + $meta_data_block_header = fread($getid3->fp, 4); 1.540 + $meta_data_last_block_flag = (bool)(getid3_lib::BigEndian2Int($meta_data_block_header[0]) & 0x80); 1.541 + $meta_data_block_type = getid3_lib::BigEndian2Int($meta_data_block_header[0]) & 0x7F; 1.542 + $meta_data_block_length = getid3_lib::BigEndian2Int(substr($meta_data_block_header, 1, 3)); 1.543 + $meta_data_block_type_text = getid3_xiph::FLACmetaBlockTypeLookup($meta_data_block_type); 1.544 + 1.545 + if ($meta_data_block_length < 0) { 1.546 + throw new getid3_exception('corrupt or invalid METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$meta_data_block_type.') at offset '.$meta_data_block_offset); 1.547 + } 1.548 + 1.549 + $getid3->info['flac'][$meta_data_block_type_text]['raw'] = array ( 1.550 + 'offset' => $meta_data_block_offset, 1.551 + 'last_meta_block' => $meta_data_last_block_flag, 1.552 + 'block_type' => $meta_data_block_type, 1.553 + 'block_type_text' => $meta_data_block_type_text, 1.554 + 'block_length' => $meta_data_block_length, 1.555 + 'block_data' => @fread($getid3->fp, $meta_data_block_length) 1.556 + ); 1.557 + $getid3->info['avdataoffset'] = ftell($getid3->fp); 1.558 + 1.559 + switch ($meta_data_block_type_text) { 1.560 + 1.561 + case 'STREAMINFO': 1.562 + if (!$this->FLACparseSTREAMINFO($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { 1.563 + return false; 1.564 + } 1.565 + break; 1.566 + 1.567 + case 'PADDING': 1.568 + // ignore 1.569 + break; 1.570 + 1.571 + case 'APPLICATION': 1.572 + if (!$this->FLACparseAPPLICATION($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { 1.573 + return false; 1.574 + } 1.575 + break; 1.576 + 1.577 + case 'SEEKTABLE': 1.578 + if (!$this->FLACparseSEEKTABLE($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { 1.579 + return false; 1.580 + } 1.581 + break; 1.582 + 1.583 + case 'VORBIS_COMMENT': 1.584 + $old_offset = ftell($getid3->fp); 1.585 + fseek($getid3->fp, 0 - $meta_data_block_length, SEEK_CUR); 1.586 + $this->ParseVorbisCommentsFilepointer($getid3->fp, $getid3->info); 1.587 + fseek($getid3->fp, $old_offset, SEEK_SET); 1.588 + break; 1.589 + 1.590 + case 'CUESHEET': 1.591 + if (!$this->FLACparseCUESHEET($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { 1.592 + return false; 1.593 + } 1.594 + break; 1.595 + 1.596 + case 'PICTURE': 1.597 + if (!$this->FLACparsePICTURE($getid3->info['flac'][$meta_data_block_type_text]['raw']['block_data'])) { 1.598 + return false; 1.599 + } 1.600 + break; 1.601 + 1.602 + default: 1.603 + $getid3->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$meta_data_block_type.') at offset '.$meta_data_block_offset); 1.604 + } 1.605 + 1.606 + } while ($meta_data_last_block_flag === false); 1.607 + 1.608 + 1.609 + if (isset($getid3->info['flac']['STREAMINFO'])) { 1.610 + $getid3->info['flac']['compressed_audio_bytes'] = $getid3->info['avdataend'] - $getid3->info['avdataoffset']; 1.611 + $getid3->info['flac']['uncompressed_audio_bytes'] = $getid3->info['flac']['STREAMINFO']['samples_stream'] * $getid3->info['flac']['STREAMINFO']['channels'] * ($getid3->info['flac']['STREAMINFO']['bits_per_sample'] / 8); 1.612 + $getid3->info['flac']['compression_ratio'] = $getid3->info['flac']['compressed_audio_bytes'] / $getid3->info['flac']['uncompressed_audio_bytes']; 1.613 + } 1.614 + 1.615 + // set md5_data_source - built into flac 0.5+ 1.616 + if (isset($getid3->info['flac']['STREAMINFO']['audio_signature'])) { 1.617 + 1.618 + if ($getid3->info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) { 1.619 + $getid3->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)'); 1.620 + 1.621 + } else { 1.622 + 1.623 + $getid3->info['md5_data_source'] = ''; 1.624 + $md5 = $getid3->info['flac']['STREAMINFO']['audio_signature']; 1.625 + for ($i = 0; $i < strlen($md5); $i++) { 1.626 + $getid3->info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT); 1.627 + } 1.628 + if (!preg_match('/^[0-9a-f]{32}$/', $getid3->info['md5_data_source'])) { 1.629 + unset($getid3->info['md5_data_source']); 1.630 + } 1.631 + 1.632 + } 1.633 + 1.634 + } 1.635 + 1.636 + $getid3->info['audio']['bits_per_sample'] = $getid3->info['flac']['STREAMINFO']['bits_per_sample']; 1.637 + if ($getid3->info['audio']['bits_per_sample'] == 8) { 1.638 + // special case 1.639 + // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value 1.640 + // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed 1.641 + $getid3->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file'); 1.642 + } 1.643 + if (!empty($getid3->info['ogg']['vendor'])) { 1.644 + $getid3->info['audio']['encoder'] = $getid3->info['ogg']['vendor']; 1.645 + } 1.646 + 1.647 + return true; 1.648 + } 1.649 + 1.650 + 1.651 + 1.652 + private function FLACparseSTREAMINFO($meta_data_block_data) { 1.653 + 1.654 + $getid3 = $this->getid3; 1.655 + 1.656 + getid3_lib::ReadSequence('BigEndian2Int', $getid3->info['flac']['STREAMINFO'], $meta_data_block_data, 0, 1.657 + array ( 1.658 + 'min_block_size' => 2, 1.659 + 'max_block_size' => 2, 1.660 + 'min_frame_size' => 3, 1.661 + 'max_frame_size' => 3 1.662 + ) 1.663 + ); 1.664 + 1.665 + $sample_rate_channels_sample_bits_stream_samples = getid3_lib::BigEndian2Bin(substr($meta_data_block_data, 10, 8)); 1.666 + 1.667 + $getid3->info['flac']['STREAMINFO']['sample_rate'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 0, 20)); 1.668 + $getid3->info['flac']['STREAMINFO']['channels'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 20, 3)) + 1; 1.669 + $getid3->info['flac']['STREAMINFO']['bits_per_sample'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 23, 5)) + 1; 1.670 + $getid3->info['flac']['STREAMINFO']['samples_stream'] = bindec(substr($sample_rate_channels_sample_bits_stream_samples, 28, 36)); // bindec() returns float in case of int overrun 1.671 + $getid3->info['flac']['STREAMINFO']['audio_signature'] = substr($meta_data_block_data, 18, 16); 1.672 + 1.673 + if (!empty($getid3->info['flac']['STREAMINFO']['sample_rate'])) { 1.674 + 1.675 + $getid3->info['audio']['bitrate_mode'] = 'vbr'; 1.676 + $getid3->info['audio']['sample_rate'] = $getid3->info['flac']['STREAMINFO']['sample_rate']; 1.677 + $getid3->info['audio']['channels'] = $getid3->info['flac']['STREAMINFO']['channels']; 1.678 + $getid3->info['audio']['bits_per_sample'] = $getid3->info['flac']['STREAMINFO']['bits_per_sample']; 1.679 + $getid3->info['playtime_seconds'] = $getid3->info['flac']['STREAMINFO']['samples_stream'] / $getid3->info['flac']['STREAMINFO']['sample_rate']; 1.680 + $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; 1.681 + 1.682 + } else { 1.683 + 1.684 + throw new getid3_exception('Corrupt METAdata block: STREAMINFO'); 1.685 + } 1.686 + 1.687 + unset($getid3->info['flac']['STREAMINFO']['raw']); 1.688 + 1.689 + return true; 1.690 + } 1.691 + 1.692 + 1.693 + 1.694 + private function FLACparseAPPLICATION($meta_data_block_data) { 1.695 + 1.696 + $getid3 = $this->getid3; 1.697 + 1.698 + $application_id = getid3_lib::BigEndian2Int(substr($meta_data_block_data, 0, 4)); 1.699 + 1.700 + $getid3->info['flac']['APPLICATION'][$application_id]['name'] = getid3_xiph::FLACapplicationIDLookup($application_id); 1.701 + $getid3->info['flac']['APPLICATION'][$application_id]['data'] = substr($meta_data_block_data, 4); 1.702 + 1.703 + unset($getid3->info['flac']['APPLICATION']['raw']); 1.704 + 1.705 + return true; 1.706 + } 1.707 + 1.708 + 1.709 + 1.710 + private function FLACparseSEEKTABLE($meta_data_block_data) { 1.711 + 1.712 + $getid3 = $this->getid3; 1.713 + 1.714 + $offset = 0; 1.715 + $meta_data_block_length = strlen($meta_data_block_data); 1.716 + while ($offset < $meta_data_block_length) { 1.717 + $sample_number_string = substr($meta_data_block_data, $offset, 8); 1.718 + $offset += 8; 1.719 + if ($sample_number_string == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF") { 1.720 + 1.721 + // placeholder point 1.722 + @$getid3->info['flac']['SEEKTABLE']['placeholders']++; 1.723 + $offset += 10; 1.724 + 1.725 + } else { 1.726 + 1.727 + $sample_number = getid3_lib::BigEndian2Int($sample_number_string); 1.728 + 1.729 + $getid3->info['flac']['SEEKTABLE'][$sample_number]['offset'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 8)); 1.730 + $offset += 8; 1.731 + 1.732 + $getid3->info['flac']['SEEKTABLE'][$sample_number]['samples'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 2)); 1.733 + $offset += 2; 1.734 + 1.735 + } 1.736 + } 1.737 + 1.738 + unset($getid3->info['flac']['SEEKTABLE']['raw']); 1.739 + 1.740 + return true; 1.741 + } 1.742 + 1.743 + 1.744 + 1.745 + private function FLACparseCUESHEET($meta_data_block_data) { 1.746 + 1.747 + $getid3 = $this->getid3; 1.748 + 1.749 + $getid3->info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($meta_data_block_data, 0, 128), "\0"); 1.750 + $getid3->info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, 128, 8)); 1.751 + $getid3->info['flac']['CUESHEET']['flags']['is_cd'] = (bool)(getid3_lib::BigEndian2Int($meta_data_block_data[136]) & 0x80); 1.752 + $getid3->info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int($meta_data_block_data[395]); 1.753 + 1.754 + $offset = 396; 1.755 + 1.756 + for ($track = 0; $track < $getid3->info['flac']['CUESHEET']['number_tracks']; $track++) { 1.757 + 1.758 + $track_sample_offset = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 8)); 1.759 + $offset += 8; 1.760 + 1.761 + $track_number = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); 1.762 + 1.763 + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['sample_offset'] = $track_sample_offset; 1.764 + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['isrc'] = substr($meta_data_block_data, $offset, 12); 1.765 + $offset += 12; 1.766 + 1.767 + $track_flags_raw = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); 1.768 + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['flags']['is_audio'] = (bool)($track_flags_raw & 0x80); 1.769 + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['flags']['pre_emphasis'] = (bool)($track_flags_raw & 0x40); 1.770 + 1.771 + $offset += 13; // reserved 1.772 + 1.773 + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['index_points'] = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); 1.774 + 1.775 + for ($index = 0; $index < $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['index_points']; $index++) { 1.776 + 1.777 + $index_sample_offset = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 8)); 1.778 + $offset += 8; 1.779 + 1.780 + $index_number = getid3_lib::BigEndian2Int($meta_data_block_data{$offset++}); 1.781 + $getid3->info['flac']['CUESHEET']['tracks'][$track_number]['indexes'][$index_number] = $index_sample_offset; 1.782 + 1.783 + $offset += 3; // reserved 1.784 + } 1.785 + } 1.786 + 1.787 + unset($getid3->info['flac']['CUESHEET']['raw']); 1.788 + 1.789 + return true; 1.790 + } 1.791 + 1.792 + 1.793 + 1.794 + private function FLACparsePICTURE($meta_data_block_data) { 1.795 + 1.796 + $getid3 = $this->getid3; 1.797 + 1.798 + $picture = &$getid3->info['flac']['PICTURE'][sizeof($getid3->info['flac']['PICTURE']) - 1]; 1.799 + 1.800 + $offset = 0; 1.801 + 1.802 + $picture['type'] = $this->FLACpictureTypeLookup(getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4))); 1.803 + $offset += 4; 1.804 + 1.805 + $length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)); 1.806 + $offset += 4; 1.807 + 1.808 + $picture['mime_type'] = substr($meta_data_block_data, $offset, $length); 1.809 + $offset += $length; 1.810 + 1.811 + $length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)); 1.812 + $offset += 4; 1.813 + 1.814 + $picture['description'] = substr($meta_data_block_data, $offset, $length); 1.815 + $offset += $length; 1.816 + 1.817 + $picture['width'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)); 1.818 + $offset += 4; 1.819 + 1.820 + $picture['height'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)); 1.821 + $offset += 4; 1.822 + 1.823 + $picture['color_depth'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)); 1.824 + $offset += 4; 1.825 + 1.826 + $picture['colors_indexed'] = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)); 1.827 + $offset += 4; 1.828 + 1.829 + $length = getid3_lib::BigEndian2Int(substr($meta_data_block_data, $offset, 4)); 1.830 + $offset += 4; 1.831 + 1.832 + $picture['image_data'] = substr($meta_data_block_data, $offset, $length); 1.833 + $offset += $length; 1.834 + 1.835 + unset($getid3->info['flac']['PICTURE']['raw']); 1.836 + 1.837 + return true; 1.838 + } 1.839 + 1.840 + 1.841 + 1.842 + public static function SpeexBandModeLookup($mode) { 1.843 + 1.844 + static $lookup = array ( 1.845 + 0 => 'narrow', 1.846 + 1 => 'wide', 1.847 + 2 => 'ultra-wide' 1.848 + ); 1.849 + return (isset($lookup[$mode]) ? $lookup[$mode] : null); 1.850 + } 1.851 + 1.852 + 1.853 + 1.854 + public static function OggPageSegmentLength($ogg_info_array, $segment_number=1) { 1.855 + 1.856 + for ($i = 0; $i < $segment_number; $i++) { 1.857 + $segment_length = 0; 1.858 + foreach ($ogg_info_array['segment_table'] as $key => $value) { 1.859 + $segment_length += $value; 1.860 + if ($value < 255) { 1.861 + break; 1.862 + } 1.863 + } 1.864 + } 1.865 + return $segment_length; 1.866 + } 1.867 + 1.868 + 1.869 + 1.870 + public static function GetQualityFromNominalBitrate($nominal_bitrate) { 1.871 + 1.872 + // decrease precision 1.873 + $nominal_bitrate = $nominal_bitrate / 1000; 1.874 + 1.875 + if ($nominal_bitrate < 128) { 1.876 + // q-1 to q4 1.877 + $qval = ($nominal_bitrate - 64) / 16; 1.878 + } elseif ($nominal_bitrate < 256) { 1.879 + // q4 to q8 1.880 + $qval = $nominal_bitrate / 32; 1.881 + } elseif ($nominal_bitrate < 320) { 1.882 + // q8 to q9 1.883 + $qval = ($nominal_bitrate + 256) / 64; 1.884 + } else { 1.885 + // q9 to q10 1.886 + $qval = ($nominal_bitrate + 1300) / 180; 1.887 + } 1.888 + return round($qval, 1); // 5 or 4.9 1.889 + } 1.890 + 1.891 + 1.892 + 1.893 + public static function FLACmetaBlockTypeLookup($block_type) { 1.894 + 1.895 + static $lookup = array ( 1.896 + 0 => 'STREAMINFO', 1.897 + 1 => 'PADDING', 1.898 + 2 => 'APPLICATION', 1.899 + 3 => 'SEEKTABLE', 1.900 + 4 => 'VORBIS_COMMENT', 1.901 + 5 => 'CUESHEET', 1.902 + 6 => 'PICTURE' 1.903 + ); 1.904 + return (isset($lookup[$block_type]) ? $lookup[$block_type] : 'reserved'); 1.905 + } 1.906 + 1.907 + 1.908 + 1.909 + public static function FLACapplicationIDLookup($application_id) { 1.910 + 1.911 + // http://flac.sourceforge.net/id.html 1.912 + 1.913 + static $lookup = array ( 1.914 + 0x46746F6C => 'flac-tools', // 'Ftol' 1.915 + 0x46746F6C => 'Sound Font FLAC', // 'SFFL' 1.916 + 0x7065656D => 'Parseable Embedded Extensible Metadata (specification)', // 'peem' 1.917 + 0x786D6364 => 'xmcd' 1.918 + 1.919 + ); 1.920 + return (isset($lookup[$application_id]) ? $lookup[$application_id] : 'reserved'); 1.921 + } 1.922 + 1.923 + 1.924 + public static function FLACpictureTypeLookup($type_id) { 1.925 + 1.926 + static $lookup = array ( 1.927 + 1.928 + 0 => 'Other', 1.929 + 1 => "32x32 pixels 'file icon' (PNG only)", 1.930 + 2 => 'Other file icon', 1.931 + 3 => 'Cover (front)', 1.932 + 4 => 'Cover (back)', 1.933 + 5 => 'Leaflet page', 1.934 + 6 => 'Media (e.g. label side of CD)', 1.935 + 7 => 'Lead artist/lead performer/soloist', 1.936 + 8 => 'Artist/performer', 1.937 + 9 => 'Conductor', 1.938 + 10 => 'Band/Orchestra', 1.939 + 11 => 'Composer', 1.940 + 12 => 'Lyricist/text writer', 1.941 + 13 => 'Recording Location', 1.942 + 14 => 'During recording', 1.943 + 15 => 'During performance', 1.944 + 16 => 'Movie/video screen capture', 1.945 + 17 => 'A bright coloured fish', 1.946 + 18 => 'Illustration', 1.947 + 19 => 'Band/artist logotype', 1.948 + 20 => 'Publisher/Studio logotype' 1.949 + ); 1.950 + return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved'); 1.951 + } 1.952 + 1.953 +} 1.954 + 1.955 +?> 1.956 \ No newline at end of file