2011-07-22 08:30:52 +04:00
< ? php
/////////////////////////////////////////////////////////////////
/// getID3() by James Heinrich <info@getid3.org> //
// available at http://getid3.sourceforge.net //
// or http://www.getid3.org //
/////////////////////////////////////////////////////////////////
// See readme.txt for more details //
/////////////////////////////////////////////////////////////////
// //
// module.audio.vqf.php //
// module for analyzing VQF audio files //
// dependencies: NONE //
// ///
/////////////////////////////////////////////////////////////////
2012-04-03 01:33:18 +04:00
class getid3_vqf extends getid3_handler
2011-07-22 08:30:52 +04:00
{
2012-04-03 01:33:18 +04:00
function Analyze () {
$info = & $this -> getid3 -> info ;
2011-07-22 08:30:52 +04:00
// based loosely on code from TTwinVQ by Jurgen Faul <jfaul<75> gmx*de>
// http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html
2012-04-03 01:33:18 +04:00
$info [ 'fileformat' ] = 'vqf' ;
$info [ 'audio' ][ 'dataformat' ] = 'vqf' ;
$info [ 'audio' ][ 'bitrate_mode' ] = 'cbr' ;
$info [ 'audio' ][ 'lossless' ] = false ;
2011-07-22 08:30:52 +04:00
// shortcut
2012-04-03 01:33:18 +04:00
$info [ 'vqf' ][ 'raw' ] = array ();
$thisfile_vqf = & $info [ 'vqf' ];
2011-07-22 08:30:52 +04:00
$thisfile_vqf_raw = & $thisfile_vqf [ 'raw' ];
2012-04-03 01:33:18 +04:00
fseek ( $this -> getid3 -> fp , $info [ 'avdataoffset' ], SEEK_SET );
$VQFheaderData = fread ( $this -> getid3 -> fp , 16 );
2011-07-22 08:30:52 +04:00
$offset = 0 ;
2012-04-03 01:33:18 +04:00
$thisfile_vqf_raw [ 'header_tag' ] = substr ( $VQFheaderData , $offset , 4 );
$magic = 'TWIN' ;
if ( $thisfile_vqf_raw [ 'header_tag' ] != $magic ) {
$info [ 'error' ][] = 'Expecting "' . getid3_lib :: PrintHexBytes ( $magic ) . '" at offset ' . $info [ 'avdataoffset' ] . ', found "' . getid3_lib :: PrintHexBytes ( $thisfile_vqf_raw [ 'header_tag' ]) . '"' ;
unset ( $info [ 'vqf' ]);
unset ( $info [ 'fileformat' ]);
2011-07-22 08:30:52 +04:00
return false ;
}
$offset += 4 ;
2012-04-03 01:33:18 +04:00
$thisfile_vqf_raw [ 'version' ] = substr ( $VQFheaderData , $offset , 8 );
2011-07-22 08:30:52 +04:00
$offset += 8 ;
2012-04-03 01:33:18 +04:00
$thisfile_vqf_raw [ 'size' ] = getid3_lib :: BigEndian2Int ( substr ( $VQFheaderData , $offset , 4 ));
2011-07-22 08:30:52 +04:00
$offset += 4 ;
2012-04-03 01:33:18 +04:00
while ( ftell ( $this -> getid3 -> fp ) < $info [ 'avdataend' ]) {
2011-07-22 08:30:52 +04:00
2012-04-03 01:33:18 +04:00
$ChunkBaseOffset = ftell ( $this -> getid3 -> fp );
2011-07-22 08:30:52 +04:00
$chunkoffset = 0 ;
2012-04-03 01:33:18 +04:00
$ChunkData = fread ( $this -> getid3 -> fp , 8 );
2011-07-22 08:30:52 +04:00
$ChunkName = substr ( $ChunkData , $chunkoffset , 4 );
if ( $ChunkName == 'DATA' ) {
2012-04-03 01:33:18 +04:00
$info [ 'avdataoffset' ] = $ChunkBaseOffset ;
2011-07-22 08:30:52 +04:00
break ;
}
$chunkoffset += 4 ;
$ChunkSize = getid3_lib :: BigEndian2Int ( substr ( $ChunkData , $chunkoffset , 4 ));
$chunkoffset += 4 ;
2012-04-03 01:33:18 +04:00
if ( $ChunkSize > ( $info [ 'avdataend' ] - ftell ( $this -> getid3 -> fp ))) {
$info [ 'error' ][] = 'Invalid chunk size (' . $ChunkSize . ') for chunk "' . $ChunkName . '" at offset ' . $ChunkBaseOffset ;
2011-07-22 08:30:52 +04:00
break ;
}
if ( $ChunkSize > 0 ) {
2012-04-03 01:33:18 +04:00
$ChunkData .= fread ( $this -> getid3 -> fp , $ChunkSize );
2011-07-22 08:30:52 +04:00
}
switch ( $ChunkName ) {
case 'COMM' :
// shortcut
$thisfile_vqf [ 'COMM' ] = array ();
$thisfile_vqf_COMM = & $thisfile_vqf [ 'COMM' ];
$thisfile_vqf_COMM [ 'channel_mode' ] = getid3_lib :: BigEndian2Int ( substr ( $ChunkData , $chunkoffset , 4 ));
$chunkoffset += 4 ;
$thisfile_vqf_COMM [ 'bitrate' ] = getid3_lib :: BigEndian2Int ( substr ( $ChunkData , $chunkoffset , 4 ));
$chunkoffset += 4 ;
$thisfile_vqf_COMM [ 'sample_rate' ] = getid3_lib :: BigEndian2Int ( substr ( $ChunkData , $chunkoffset , 4 ));
$chunkoffset += 4 ;
$thisfile_vqf_COMM [ 'security_level' ] = getid3_lib :: BigEndian2Int ( substr ( $ChunkData , $chunkoffset , 4 ));
$chunkoffset += 4 ;
2012-04-03 01:33:18 +04:00
$info [ 'audio' ][ 'channels' ] = $thisfile_vqf_COMM [ 'channel_mode' ] + 1 ;
$info [ 'audio' ][ 'sample_rate' ] = $this -> VQFchannelFrequencyLookup ( $thisfile_vqf_COMM [ 'sample_rate' ]);
$info [ 'audio' ][ 'bitrate' ] = $thisfile_vqf_COMM [ 'bitrate' ] * 1000 ;
$info [ 'audio' ][ 'encoder_options' ] = 'CBR' . ceil ( $info [ 'audio' ][ 'bitrate' ] / 1000 );
2011-07-22 08:30:52 +04:00
2012-04-03 01:33:18 +04:00
if ( $info [ 'audio' ][ 'bitrate' ] == 0 ) {
$info [ 'error' ][] = 'Corrupt VQF file: bitrate_audio == zero' ;
2011-07-22 08:30:52 +04:00
return false ;
}
break ;
case 'NAME' :
case 'AUTH' :
case '(c) ' :
case 'FILE' :
case 'COMT' :
case 'ALBM' :
$thisfile_vqf [ 'comments' ][ $this -> VQFcommentNiceNameLookup ( $ChunkName )][] = trim ( substr ( $ChunkData , 8 ));
break ;
case 'DSIZ' :
$thisfile_vqf [ 'DSIZ' ] = getid3_lib :: BigEndian2Int ( substr ( $ChunkData , 8 , 4 ));
break ;
default :
2012-04-03 01:33:18 +04:00
$info [ 'warning' ][] = 'Unhandled chunk type "' . $ChunkName . '" at offset ' . $ChunkBaseOffset ;
2011-07-22 08:30:52 +04:00
break ;
}
}
2012-04-03 01:33:18 +04:00
$info [ 'playtime_seconds' ] = (( $info [ 'avdataend' ] - $info [ 'avdataoffset' ]) * 8 ) / $info [ 'audio' ][ 'bitrate' ];
2011-07-22 08:30:52 +04:00
2012-04-03 01:33:18 +04:00
if ( isset ( $thisfile_vqf [ 'DSIZ' ]) && (( $thisfile_vqf [ 'DSIZ' ] != ( $info [ 'avdataend' ] - $info [ 'avdataoffset' ] - strlen ( 'DATA' ))))) {
2011-07-22 08:30:52 +04:00
switch ( $thisfile_vqf [ 'DSIZ' ]) {
case 0 :
case 1 :
2012-04-03 01:33:18 +04:00
$info [ 'warning' ][] = 'Invalid DSIZ value "' . $thisfile_vqf [ 'DSIZ' ] . '". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v' . ( $thisfile_vqf [ 'DSIZ' ] + 1 ) . '.0' ;
$info [ 'audio' ][ 'encoder' ] = 'Ahead Nero' ;
2011-07-22 08:30:52 +04:00
break ;
default :
2012-04-03 01:33:18 +04:00
$info [ 'warning' ][] = 'Probable corrupted file - should be ' . $thisfile_vqf [ 'DSIZ' ] . ' bytes, actually ' . ( $info [ 'avdataend' ] - $info [ 'avdataoffset' ] - strlen ( 'DATA' ));
2011-07-22 08:30:52 +04:00
break ;
}
}
return true ;
}
function VQFchannelFrequencyLookup ( $frequencyid ) {
static $VQFchannelFrequencyLookup = array (
11 => 11025 ,
22 => 22050 ,
44 => 44100
);
return ( isset ( $VQFchannelFrequencyLookup [ $frequencyid ]) ? $VQFchannelFrequencyLookup [ $frequencyid ] : $frequencyid * 1000 );
}
function VQFcommentNiceNameLookup ( $shortname ) {
static $VQFcommentNiceNameLookup = array (
'NAME' => 'title' ,
'AUTH' => 'artist' ,
'(c) ' => 'copyright' ,
'FILE' => 'filename' ,
'COMT' => 'comment' ,
'ALBM' => 'album'
);
return ( isset ( $VQFcommentNiceNameLookup [ $shortname ]) ? $VQFcommentNiceNameLookup [ $shortname ] : $shortname );
}
}
?>