37 {
38 $info = &$this->getid3->info;
39
40
41
42
43 $info[
'fileformat'] =
'mac';
44 $info[
'audio'][
'dataformat'] =
'mac';
45 $info[
'audio'][
'bitrate_mode'] =
'vbr';
46 $info[
'audio'][
'lossless'] =
true;
47
48 $info[
'monkeys_audio'][
'raw'] = array();
49 $thisfile_monkeysaudio = &
$info[
'monkeys_audio'];
50 $thisfile_monkeysaudio_raw = &$thisfile_monkeysaudio['raw'];
51
52 fseek($this->getid3->fp,
$info[
'avdataoffset'], SEEK_SET);
53 $MACheaderData =
fread($this->getid3->fp, 74);
54
55 $thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4);
56 $magic = 'MAC ';
57 if ($thisfile_monkeysaudio_raw['magic'] != $magic) {
58 $info[
'error'][] =
'Expecting "'.Helper::PrintHexBytes($magic).
'" at offset '.
$info[
'avdataoffset'].
', found "'.
Helper::PrintHexBytes($thisfile_monkeysaudio_raw[
'magic']).
'"';
59 unset(
$info[
'fileformat']);
60
61 return false;
62 }
64
65 if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
76 $offset = 8;
77 } else {
78 $offset = 8;
79
81 $offset += 4;
83 $offset += 4;
85 $offset += 4;
87 $offset += 4;
89 $offset += 4;
91 $offset += 4;
93 $offset += 4;
94 $thisfile_monkeysaudio_raw['cFileMD5'] = substr($MACheaderData, $offset, 16);
95 $offset += 16;
96
97
99 $offset += 2;
101 $offset += 2;
103 $offset += 4;
105 $offset += 4;
107 $offset += 4;
109 $offset += 2;
111 $offset += 2;
113 $offset += 4;
114 }
115
116 $thisfile_monkeysaudio['flags']['8-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0001);
117 $thisfile_monkeysaudio['flags']['crc-32'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0002);
118 $thisfile_monkeysaudio['flags']['peak_level'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0004);
119 $thisfile_monkeysaudio['flags']['24-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0008);
120 $thisfile_monkeysaudio['flags']['seek_elements'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0010);
121 $thisfile_monkeysaudio['flags']['no_wav_header'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0020);
122 $thisfile_monkeysaudio['version'] = $thisfile_monkeysaudio_raw['nVersion'] / 1000;
124 if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) {
125 $thisfile_monkeysaudio[
'samples_per_frame'] = $this->
MonkeySamplesPerFrame($thisfile_monkeysaudio_raw[
'nVersion'], $thisfile_monkeysaudio_raw[
'nCompressionLevel']);
126 }
127 $thisfile_monkeysaudio['bits_per_sample'] = ($thisfile_monkeysaudio['flags']['24-bit'] ? 24 : ($thisfile_monkeysaudio['flags']['8-bit'] ? 8 : 16));
128 $thisfile_monkeysaudio['channels'] = $thisfile_monkeysaudio_raw['nChannels'];
129 $info[
'audio'][
'channels'] = $thisfile_monkeysaudio[
'channels'];
130 $thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate'];
131 if ($thisfile_monkeysaudio['sample_rate'] == 0) {
132 $info[
'error'][] =
'Corrupt MAC file: frequency == zero';
133
134 return false;
135 }
136 $info[
'audio'][
'sample_rate'] = $thisfile_monkeysaudio[
'sample_rate'];
137 if ($thisfile_monkeysaudio['flags']['peak_level']) {
138 $thisfile_monkeysaudio['peak_level'] = $thisfile_monkeysaudio_raw['nPeakLevel'];
139 $thisfile_monkeysaudio['peak_ratio'] = $thisfile_monkeysaudio['peak_level'] / pow(2, $thisfile_monkeysaudio['bits_per_sample'] - 1);
140 }
141 if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
142 $thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio_raw['nBlocksPerFrame']) + $thisfile_monkeysaudio_raw['nFinalFrameBlocks'];
143 } else {
144 $thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio['samples_per_frame']) + $thisfile_monkeysaudio_raw['nFinalFrameSamples'];
145 }
146 $thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate'];
147 if ($thisfile_monkeysaudio['playtime'] == 0) {
148 $info[
'error'][] =
'Corrupt MAC file: playtime == zero';
149
150 return false;
151 }
152 $info[
'playtime_seconds'] = $thisfile_monkeysaudio[
'playtime'];
153 $thisfile_monkeysaudio[
'compressed_size'] =
$info[
'avdataend'] -
$info[
'avdataoffset'];
154 $thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8);
155 if ($thisfile_monkeysaudio['uncompressed_size'] == 0) {
156 $info[
'error'][] =
'Corrupt MAC file: uncompressed_size == zero';
157
158 return false;
159 }
160 $thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']);
161 $thisfile_monkeysaudio['bitrate'] = (($thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * $thisfile_monkeysaudio['bits_per_sample']) / $thisfile_monkeysaudio['playtime']) * $thisfile_monkeysaudio['compression_ratio'];
162 $info[
'audio'][
'bitrate'] = $thisfile_monkeysaudio[
'bitrate'];
163
164
165 if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
166 $info[
'avdataoffset'] += $thisfile_monkeysaudio_raw[
'nDescriptorBytes'];
167 $info[
'avdataoffset'] += $thisfile_monkeysaudio_raw[
'nHeaderBytes'];
168 $info[
'avdataoffset'] += $thisfile_monkeysaudio_raw[
'nSeekTableBytes'];
169 $info[
'avdataoffset'] += $thisfile_monkeysaudio_raw[
'nHeaderDataBytes'];
170
171 $info[
'avdataend'] -= $thisfile_monkeysaudio_raw[
'nTerminatingDataBytes'];
172 } else {
173 $info[
'avdataoffset'] += $offset;
174 }
175
176 if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) {
177 if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) {
178
179 } else {
180 $info[
'md5_data_source'] =
'';
181 $md5 = $thisfile_monkeysaudio_raw['cFileMD5'];
182 for ($i = 0; $i < strlen($md5); $i++) {
183 $info[
'md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2,
'00', STR_PAD_LEFT);
184 }
185 if (!preg_match(
'/^[0-9a-f]{32}$/',
$info[
'md5_data_source'])) {
186 unset(
$info[
'md5_data_source']);
187 }
188 }
189 }
190
191 $info[
'audio'][
'bits_per_sample'] = $thisfile_monkeysaudio[
'bits_per_sample'];
192 $info[
'audio'][
'encoder'] =
'MAC v'.number_format($thisfile_monkeysaudio[
'version'], 2);
193 $info[
'audio'][
'encoder_options'] = ucfirst($thisfile_monkeysaudio[
'compression']).
' compression';
194
195 return true;
196 }
fseek($bytes, $whence=SEEK_SET)
static LittleEndian2Int($byteword, $signed=false)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
MonkeySamplesPerFrame($versionid, $compressionlevel)
MonkeyCompressionLevelNameLookup($compressionlevel)
@staticvar array $MonkeyCompressionLevelNameLookup