22 $info = &$this->getid3->info;
24 $info[
'mpc'][
'header'] = array();
25 $thisfile_mpc_header = &
$info[
'mpc'][
'header'];
27 $info[
'fileformat'] =
'mpc';
28 $info[
'audio'][
'dataformat'] =
'mpc';
29 $info[
'audio'][
'bitrate_mode'] =
'vbr';
30 $info[
'audio'][
'channels'] = 2;
31 $info[
'audio'][
'lossless'] =
false;
34 $MPCheaderData = $this->
fread(4);
35 $info[
'mpc'][
'header'][
'preamble'] = substr($MPCheaderData, 0, 4);
36 if (preg_match(
'#^MPCK#',
$info[
'mpc'][
'header'][
'preamble'])) {
41 } elseif (preg_match(
'#^MP\+#',
$info[
'mpc'][
'header'][
'preamble'])) {
46 } elseif (preg_match(
'/^[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]/s', $MPCheaderData)) {
54 unset(
$info[
'fileformat']);
67 $info = &$this->getid3->info;
68 $thisfile_mpc_header = &
$info[
'mpc'][
'header'];
71 $maxHandledPacketLength = 9;
73 $offset = $this->
ftell();
74 while ($offset <
$info[
'avdataend']) {
75 $thisPacket = array();
76 $thisPacket[
'offset'] = $offset;
81 $MPCheaderData = $this->
fread($keyNameSize + $maxHandledPacketLength);
82 $packet_offset += $keyNameSize;
83 $thisPacket[
'key'] = substr($MPCheaderData, 0, $keyNameSize);
85 if ($thisPacket[
'key'] == $thisPacket[
'key_name']) {
86 $this->
error(
'Found unexpected key value "'.$thisPacket[
'key'].
'" at offset '.$thisPacket[
'offset']);
91 if ($thisPacket[
'packet_size'] ===
false) {
92 $this->
error(
'Did not find expected packet length within '.$maxHandledPacketLength.
' bytes at offset '.($thisPacket[
'offset'] + $keyNameSize));
95 $packet_offset += $packetLength;
96 $offset += $thisPacket[
'packet_size'];
98 switch ($thisPacket[
'key']) {
100 $moreBytesToRead = $thisPacket[
'packet_size'] - $keyNameSize - $maxHandledPacketLength;
101 if ($moreBytesToRead > 0) {
102 $MPCheaderData .= $this->
fread($moreBytesToRead);
110 $thisPacket[
'sample_count'] = $this->
SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
111 $packet_offset += $packetLength;
114 $thisPacket[
'beginning_silence'] = $this->
SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
115 $packet_offset += $packetLength;
119 $thisPacket[
'sample_frequency_raw'] = (($otherUsefulData & 0xE000) >> 13);
120 $thisPacket[
'max_bands_used'] = (($otherUsefulData & 0x1F00) >> 8);
121 $thisPacket[
'channels'] = (($otherUsefulData & 0x00F0) >> 4) + 1;
122 $thisPacket[
'ms_used'] = (bool) (($otherUsefulData & 0x0008) >> 3);
123 $thisPacket[
'audio_block_frames'] = (($otherUsefulData & 0x0007) >> 0);
124 $thisPacket[
'sample_frequency'] = $this->
MPCfrequencyLookup($thisPacket[
'sample_frequency_raw']);
126 $thisfile_mpc_header[
'mid_side_stereo'] = $thisPacket[
'ms_used'];
127 $thisfile_mpc_header[
'sample_rate'] = $thisPacket[
'sample_frequency'];
128 $thisfile_mpc_header[
'samples'] = $thisPacket[
'sample_count'];
129 $thisfile_mpc_header[
'stream_version_major'] = $thisPacket[
'stream_version'];
131 $info[
'audio'][
'channels'] = $thisPacket[
'channels'];
132 $info[
'audio'][
'sample_rate'] = $thisPacket[
'sample_frequency'];
133 $info[
'playtime_seconds'] = $thisPacket[
'sample_count'] / $thisPacket[
'sample_frequency'];
134 $info[
'audio'][
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
138 $moreBytesToRead = $thisPacket[
'packet_size'] - $keyNameSize - $maxHandledPacketLength;
139 if ($moreBytesToRead > 0) {
140 $MPCheaderData .= $this->
fread($moreBytesToRead);
153 if ($thisPacket[
'replaygain_title_gain']) {
$info[
'replay_gain'][
'title'][
'gain'] = $thisPacket[
'replaygain_title_gain']; }
154 if ($thisPacket[
'replaygain_title_peak']) {
$info[
'replay_gain'][
'title'][
'peak'] = $thisPacket[
'replaygain_title_peak']; }
155 if ($thisPacket[
'replaygain_album_gain']) {
$info[
'replay_gain'][
'album'][
'gain'] = $thisPacket[
'replaygain_album_gain']; }
156 if ($thisPacket[
'replaygain_album_peak']) {
$info[
'replay_gain'][
'album'][
'peak'] = $thisPacket[
'replaygain_album_peak']; }
160 $moreBytesToRead = $thisPacket[
'packet_size'] - $keyNameSize - $maxHandledPacketLength;
161 if ($moreBytesToRead > 0) {
162 $MPCheaderData .= $this->
fread($moreBytesToRead);
166 $quality_int = (($profile_pns & 0xF0) >> 4);
167 $quality_dec = (($profile_pns & 0x0E) >> 3);
168 $thisPacket[
'quality'] = (float) $quality_int + ($quality_dec / 8);
169 $thisPacket[
'pns_tool'] = (bool) (($profile_pns & 0x01) >> 0);
176 $thisPacket[
'version'] = $thisPacket[
'version_major'].
'.'.$thisPacket[
'version_minor'].
'.'.$thisPacket[
'version_build'];
178 $info[
'audio'][
'encoder'] =
'MPC v'.$thisPacket[
'version'].
' ('.(($thisPacket[
'version_minor'] % 2) ?
'unstable' :
'stable').
')';
179 $thisfile_mpc_header[
'encoder_version'] =
$info[
'audio'][
'encoder'];
181 $thisfile_mpc_header[
'quality'] = (float) ($thisPacket[
'quality'] - 5);
186 $thisPacket[
'seek_table_offset'] = $thisPacket[
'offset'] + $this->
SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength);
187 $packet_offset += $packetLength;
194 $thisPacket = array();
198 $this->
error(
'Found unhandled key type "'.$thisPacket[
'key'].
'" at offset '.$thisPacket[
'offset']);
202 if (!empty($thisPacket)) {
203 $info[
'mpc'][
'packets'][] = $thisPacket;
205 $this->
fseek($offset);
207 $thisfile_mpc_header[
'size'] = $offset;
215 $info = &$this->getid3->info;
216 $thisfile_mpc_header = &
$info[
'mpc'][
'header'];
219 $thisfile_mpc_header[
'size'] = 28;
220 $MPCheaderData =
$info[
'mpc'][
'header'][
'preamble'];
221 $MPCheaderData .= $this->
fread($thisfile_mpc_header[
'size'] - strlen(
$info[
'mpc'][
'header'][
'preamble']));
222 $offset = strlen(
'MP+');
226 $thisfile_mpc_header[
'stream_version_major'] = ($StreamVersionByte & 0x0F) >> 0;
227 $thisfile_mpc_header[
'stream_version_minor'] = ($StreamVersionByte & 0xF0) >> 4;
231 if ($thisfile_mpc_header[
'stream_version_major'] != 7) {
232 $this->
error(
'Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header[
'stream_version_major'].
')');
238 $thisfile_mpc_header[
'intensity_stereo'] = (bool) (($FlagsDWORD1 & 0x80000000) >> 31);
239 $thisfile_mpc_header[
'mid_side_stereo'] = (bool) (($FlagsDWORD1 & 0x40000000) >> 30);
240 $thisfile_mpc_header[
'max_subband'] = ($FlagsDWORD1 & 0x3F000000) >> 24;
241 $thisfile_mpc_header[
'raw'][
'profile'] = ($FlagsDWORD1 & 0x00F00000) >> 20;
242 $thisfile_mpc_header[
'begin_loud'] = (bool) (($FlagsDWORD1 & 0x00080000) >> 19);
243 $thisfile_mpc_header[
'end_loud'] = (bool) (($FlagsDWORD1 & 0x00040000) >> 18);
244 $thisfile_mpc_header[
'raw'][
'sample_rate'] = ($FlagsDWORD1 & 0x00030000) >> 16;
245 $thisfile_mpc_header[
'max_level'] = ($FlagsDWORD1 & 0x0000FFFF);
259 $thisfile_mpc_header[
'true_gapless'] = (bool) (($FlagsDWORD2 & 0x80000000) >> 31);
260 $thisfile_mpc_header[
'last_frame_length'] = ($FlagsDWORD2 & 0x7FF00000) >> 20;
268 $thisfile_mpc_header[
'profile'] = $this->
MPCprofileNameLookup($thisfile_mpc_header[
'raw'][
'profile']);
269 $thisfile_mpc_header[
'sample_rate'] = $this->
MPCfrequencyLookup($thisfile_mpc_header[
'raw'][
'sample_rate']);
270 if ($thisfile_mpc_header[
'sample_rate'] == 0) {
271 $this->
error(
'Corrupt MPC file: frequency == zero');
274 $info[
'audio'][
'sample_rate'] = $thisfile_mpc_header[
'sample_rate'];
275 $thisfile_mpc_header[
'samples'] = ((($thisfile_mpc_header[
'frame_count'] - 1) * 1152) + $thisfile_mpc_header[
'last_frame_length']) *
$info[
'audio'][
'channels'];
277 $info[
'playtime_seconds'] = ($thisfile_mpc_header[
'samples'] /
$info[
'audio'][
'channels']) /
$info[
'audio'][
'sample_rate'];
278 if (
$info[
'playtime_seconds'] == 0) {
279 $this->
error(
'Corrupt MPC file: playtime_seconds == zero');
284 $info[
'avdataoffset'] += $thisfile_mpc_header[
'size'];
286 $info[
'audio'][
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
288 $thisfile_mpc_header[
'title_peak'] = $thisfile_mpc_header[
'raw'][
'title_peak'];
289 $thisfile_mpc_header[
'title_peak_db'] = $this->
MPCpeakDBLookup($thisfile_mpc_header[
'title_peak']);
290 if ($thisfile_mpc_header[
'raw'][
'title_gain'] < 0) {
291 $thisfile_mpc_header[
'title_gain_db'] = (float) (32768 + $thisfile_mpc_header[
'raw'][
'title_gain']) / -100;
293 $thisfile_mpc_header[
'title_gain_db'] = (float) $thisfile_mpc_header[
'raw'][
'title_gain'] / 100;
296 $thisfile_mpc_header[
'album_peak'] = $thisfile_mpc_header[
'raw'][
'album_peak'];
297 $thisfile_mpc_header[
'album_peak_db'] = $this->
MPCpeakDBLookup($thisfile_mpc_header[
'album_peak']);
298 if ($thisfile_mpc_header[
'raw'][
'album_gain'] < 0) {
299 $thisfile_mpc_header[
'album_gain_db'] = (float) (32768 + $thisfile_mpc_header[
'raw'][
'album_gain']) / -100;
301 $thisfile_mpc_header[
'album_gain_db'] = (float) $thisfile_mpc_header[
'raw'][
'album_gain'] / 100;;
303 $thisfile_mpc_header[
'encoder_version'] = $this->
MPCencoderVersionLookup($thisfile_mpc_header[
'raw'][
'encoder_version']);
305 $info[
'replay_gain'][
'track'][
'adjustment'] = $thisfile_mpc_header[
'title_gain_db'];
306 $info[
'replay_gain'][
'album'][
'adjustment'] = $thisfile_mpc_header[
'album_gain_db'];
308 if ($thisfile_mpc_header[
'title_peak'] > 0) {
309 $info[
'replay_gain'][
'track'][
'peak'] = $thisfile_mpc_header[
'title_peak'];
310 } elseif (round($thisfile_mpc_header[
'max_level'] * 1.18) > 0) {
313 if ($thisfile_mpc_header[
'album_peak'] > 0) {
314 $info[
'replay_gain'][
'album'][
'peak'] = $thisfile_mpc_header[
'album_peak'];
318 $info[
'audio'][
'encoder'] = $thisfile_mpc_header[
'encoder_version'];
319 $info[
'audio'][
'encoder_options'] = $thisfile_mpc_header[
'profile'];
320 $thisfile_mpc_header[
'quality'] = (float) ($thisfile_mpc_header[
'raw'][
'profile'] - 5);
328 $info = &$this->getid3->info;
329 $thisfile_mpc_header = &
$info[
'mpc'][
'header'];
332 $thisfile_mpc_header[
'size'] = 8;
334 $MPCheaderData = $this->
fread($thisfile_mpc_header[
'size']);
337 $info[
'avdataoffset'] += $thisfile_mpc_header[
'size'];
354 $thisfile_mpc_header[
'target_bitrate'] = (($HeaderDWORD[0] & 0xFF800000) >> 23);
355 $thisfile_mpc_header[
'intensity_stereo'] = (bool) (($HeaderDWORD[0] & 0x00400000) >> 22);
356 $thisfile_mpc_header[
'mid_side_stereo'] = (bool) (($HeaderDWORD[0] & 0x00200000) >> 21);
357 $thisfile_mpc_header[
'stream_version_major'] = ($HeaderDWORD[0] & 0x001FF800) >> 11;
358 $thisfile_mpc_header[
'stream_version_minor'] = 0;
359 $thisfile_mpc_header[
'max_band'] = ($HeaderDWORD[0] & 0x000007C0) >> 6;
360 $thisfile_mpc_header[
'block_size'] = ($HeaderDWORD[0] & 0x0000003F);
362 switch ($thisfile_mpc_header[
'stream_version_major']) {
364 $thisfile_mpc_header[
'frame_count'] = ($HeaderDWORD[1] >> 16);
369 $thisfile_mpc_header[
'frame_count'] = $HeaderDWORD[1];
373 $info[
'error'] =
'Expecting 4, 5 or 6 in version field, found '.$thisfile_mpc_header[
'stream_version_major'].
' instead';
379 if (($thisfile_mpc_header[
'stream_version_major'] > 4) && ($thisfile_mpc_header[
'block_size'] != 1)) {
380 $this->
warning(
'Block size expected to be 1, actual value found: '.$thisfile_mpc_header[
'block_size']);
383 $thisfile_mpc_header[
'sample_rate'] = 44100;
384 $info[
'audio'][
'sample_rate'] = $thisfile_mpc_header[
'sample_rate'];
385 $thisfile_mpc_header[
'samples'] = $thisfile_mpc_header[
'frame_count'] * 1152 *
$info[
'audio'][
'channels'];
387 if ($thisfile_mpc_header[
'target_bitrate'] == 0) {
388 $info[
'audio'][
'bitrate_mode'] =
'vbr';
390 $info[
'audio'][
'bitrate_mode'] =
'cbr';
393 $info[
'mpc'][
'bitrate'] = ($info[
'avdataend'] - $info[
'avdataoffset']) * 8 * 44100 / $thisfile_mpc_header[
'frame_count'] / 1152;
394 $info[
'audio'][
'bitrate'] = $info[
'mpc'][
'bitrate'];
395 $info[
'audio'][
'encoder'] =
'SV'.$thisfile_mpc_header[
'stream_version_major'];
402 static $MPCprofileNameLookup = array(
408 5 =>
'below Telephone (q = 0.0)',
409 6 =>
'below Telephone (q = 1.0)',
410 7 =>
'Telephone (q = 2.0)',
411 8 =>
'Thumb (q = 3.0)',
412 9 =>
'Radio (q = 4.0)',
413 10 =>
'Standard (q = 5.0)',
414 11 =>
'Extreme (q = 6.0)',
415 12 =>
'Insane (q = 7.0)',
416 13 =>
'BrainDead (q = 8.0)',
417 14 =>
'above BrainDead (q = 9.0)',
418 15 =>
'above BrainDead (q = 10.0)' 420 return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] :
'invalid');
424 static $MPCfrequencyLookup = array(
430 return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] :
'invalid');
435 return ((log10($intvalue) / log10(2)) - 15) * 6;
446 if ($encoderversion == 0) {
448 return 'Buschmann v1.7.0-v1.7.9 or Klemm v0.90-v1.05';
451 if (($encoderversion % 10) == 0) {
454 return number_format($encoderversion / 100, 2);
456 } elseif (($encoderversion % 2) == 0) {
459 return number_format($encoderversion / 100, 2).
' beta';
464 return number_format($encoderversion / 100, 2).
' alpha';
469 for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) {
477 $thisbyte = ord(substr(
$data, ($packetLength - 1), 1));
479 $packet_size = ($packet_size << 7);
480 $packet_size = ($packet_size | ($thisbyte & 0x7F));
481 if (($thisbyte & 0x80) === 0) {
484 if ($packetLength >= $maxHandledPacketLength) {
492 static $MPCsv8PacketName = array();
493 if (empty($MPCsv8PacketName)) {
494 $MPCsv8PacketName = array(
495 'AP' =>
'Audio Packet',
496 'CT' =>
'Chapter Tag',
497 'EI' =>
'Encoder Info',
498 'RG' =>
'Replay Gain',
499 'SE' =>
'Stream End',
500 'SH' =>
'Stream Header',
501 'SO' =>
'Seek Table Offset',
502 'ST' =>
'Seek Table',
505 return (isset($MPCsv8PacketName[$packetKey]) ? $MPCsv8PacketName[$packetKey] : $packetKey);
SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9)
getID3() by James Heinrich info@getid3.org //
MPCencoderVersionLookup($encoderversion)
static LittleEndian2Int($byteword, $signed=false)
MPCsv8PacketName($packetKey)
static CastAsInt($floatnum)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
MPCpeakDBLookup($intvalue)
fseek($bytes, $whence=SEEK_SET)
MPCfrequencyLookup($frequencyid)
MPCprofileNameLookup($profileid)
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)