39 {
40 $info = &$this->getid3->info;
41
42 fseek($this->getid3->fp,
$info[
'avdataoffset'], SEEK_SET);
43
44 while (true) {
45
46 $wavpackheader =
fread($this->getid3->fp, 32);
47
48 if (
ftell($this->getid3->fp) >=
$info[
'avdataend']) {
49 break;
50 } elseif (
feof($this->getid3->fp)) {
51 break;
52 } elseif (
53 isset(
$info[
'wavpack'][
'blockheader'][
'total_samples']) &&
54 isset(
$info[
'wavpack'][
'blockheader'][
'block_samples']) &&
55 (
$info[
'wavpack'][
'blockheader'][
'total_samples'] > 0) &&
56 (
$info[
'wavpack'][
'blockheader'][
'block_samples'] > 0) &&
57 (!isset(
$info[
'wavpack'][
'riff_trailer_size']) || (
$info[
'wavpack'][
'riff_trailer_size'] <= 0)) &&
58 ((isset(
$info[
'wavpack'][
'config_flags'][
'md5_checksum']) && (
$info[
'wavpack'][
'config_flags'][
'md5_checksum'] ===
false)) || !empty(
$info[
'md5_data_source']))) {
59 break;
60 }
61
62 $blockheader_offset =
ftell($this->getid3->fp) - 32;
63 $blockheader_magic = substr($wavpackheader, 0, 4);
65
66 $magic = 'wvpk';
67 if ($blockheader_magic != $magic) {
68 $info[
'error'][] =
'Expecting "'.Helper::PrintHexBytes($magic).
'" at offset '.$blockheader_offset.
', found "'.
Helper::PrintHexBytes($blockheader_magic).
'"';
69 switch (isset(
$info[
'audio'][
'dataformat']) ?
$info[
'audio'][
'dataformat'] :
'') {
70 case 'wavpack':
71 case 'wvc':
72 break;
73 default:
74 unset(
$info[
'fileformat']);
75 unset(
$info[
'audio']);
76 unset(
$info[
'wavpack']);
77 break;
78 }
79
80 return false;
81 }
82
83 if (empty(
$info[
'wavpack'][
'blockheader'][
'block_samples']) ||
84 empty(
$info[
'wavpack'][
'blockheader'][
'total_samples']) ||
85 (
$info[
'wavpack'][
'blockheader'][
'block_samples'] <= 0) ||
86 (
$info[
'wavpack'][
'blockheader'][
'total_samples'] <= 0)) {
87
88
89
90
91
92
93
94
95
96
97 $info[
'audio'][
'dataformat'] =
'wavpack';
98 $info[
'fileformat'] =
'wavpack';
99 $info[
'audio'][
'lossless'] =
true;
100 $info[
'audio'][
'bitrate_mode'] =
'vbr';
101
102 $info[
'wavpack'][
'blockheader'][
'offset'] = $blockheader_offset;
103 $info[
'wavpack'][
'blockheader'][
'magic'] = $blockheader_magic;
104 $info[
'wavpack'][
'blockheader'][
'size'] = $blockheader_size;
105
106 if (
$info[
'wavpack'][
'blockheader'][
'size'] >= 0x100000) {
107 $info[
'error'][] =
'Expecting WavPack block size less than "0x100000", found "'.$info[
'wavpack'][
'blockheader'][
'size'].
'" at offset '.
$info[
'wavpack'][
'blockheader'][
'offset'];
108 switch (isset(
$info[
'audio'][
'dataformat']) ?
$info[
'audio'][
'dataformat'] :
'') {
109 case 'wavpack':
110 case 'wvc':
111 break;
112 default:
113 unset(
$info[
'fileformat']);
114 unset(
$info[
'audio']);
115 unset(
$info[
'wavpack']);
116 break;
117 }
118
119 return false;
120 }
121
122 $info[
'wavpack'][
'blockheader'][
'minor_version'] = ord($wavpackheader{8});
123 $info[
'wavpack'][
'blockheader'][
'major_version'] = ord($wavpackheader{9});
124
125 if ((
$info[
'wavpack'][
'blockheader'][
'major_version'] != 4) ||
126 ((
$info[
'wavpack'][
'blockheader'][
'minor_version'] < 4) &&
127 (
$info[
'wavpack'][
'blockheader'][
'minor_version'] > 16))) {
128 $info[
'error'][] =
'Expecting WavPack version between "4.2" and "4.16", found version "'.$info[
'wavpack'][
'blockheader'][
'major_version'].
'.'.
$info[
'wavpack'][
'blockheader'][
'minor_version'].
'" at offset '.
$info[
'wavpack'][
'blockheader'][
'offset'];
129 switch (isset(
$info[
'audio'][
'dataformat']) ?
$info[
'audio'][
'dataformat'] :
'') {
130 case 'wavpack':
131 case 'wvc':
132 break;
133 default:
134 unset(
$info[
'fileformat']);
135 unset(
$info[
'audio']);
136 unset(
$info[
'wavpack']);
137 break;
138 }
139
140 return false;
141 }
142
143 $info[
'wavpack'][
'blockheader'][
'track_number'] = ord($wavpackheader{10});
144 $info[
'wavpack'][
'blockheader'][
'index_number'] = ord($wavpackheader{11});
150
151 $info[
'wavpack'][
'blockheader'][
'flags'][
'bytes_per_sample'] = 1 + (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000003);
152 $info[
'wavpack'][
'blockheader'][
'flags'][
'mono'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000004);
153 $info[
'wavpack'][
'blockheader'][
'flags'][
'hybrid'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000008);
154 $info[
'wavpack'][
'blockheader'][
'flags'][
'joint_stereo'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000010);
155 $info[
'wavpack'][
'blockheader'][
'flags'][
'cross_decorrelation'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000020);
156 $info[
'wavpack'][
'blockheader'][
'flags'][
'hybrid_noiseshape'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000040);
157 $info[
'wavpack'][
'blockheader'][
'flags'][
'ieee_32bit_float'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000080);
158 $info[
'wavpack'][
'blockheader'][
'flags'][
'int_32bit'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000100);
159 $info[
'wavpack'][
'blockheader'][
'flags'][
'hybrid_bitrate_noise'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000200);
160 $info[
'wavpack'][
'blockheader'][
'flags'][
'hybrid_balance_noise'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000400);
161 $info[
'wavpack'][
'blockheader'][
'flags'][
'multichannel_initial'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00000800);
162 $info[
'wavpack'][
'blockheader'][
'flags'][
'multichannel_final'] = (bool) (
$info[
'wavpack'][
'blockheader'][
'flags_raw'] & 0x00001000);
163
164 $info[
'audio'][
'lossless'] = !
$info[
'wavpack'][
'blockheader'][
'flags'][
'hybrid'];
165 }
166
167 while (!
feof($this->getid3->fp) && (
ftell($this->getid3->fp) < ($blockheader_offset + $blockheader_size + 8))) {
168
169 $metablock = array(
'offset'=>
ftell($this->getid3->fp));
170 $metablockheader =
fread($this->getid3->fp, 2);
171 if (
feof($this->getid3->fp)) {
172 break;
173 }
174 $metablock['id'] = ord($metablockheader{0});
175 $metablock['function_id'] = ($metablock['id'] & 0x3F);
177
178
179
180
181
182
183
184
185 $metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20);
186
187 $metablock['padded_data'] = (bool) ($metablock['id'] & 0x40);
188 $metablock['large_block'] = (bool) ($metablock['id'] & 0x80);
189 if ($metablock['large_block']) {
190 $metablockheader .=
fread($this->getid3->fp, 2);
191 }
193 $metablock['data'] = null;
194
195 if ($metablock['size'] > 0) {
196
197 switch ($metablock['function_id']) {
198 case 0x21:
199 case 0x22:
200 case 0x23:
201 case 0x24:
202 case 0x25:
203 case 0x26:
204 $metablock[
'data'] =
fread($this->getid3->fp, $metablock[
'size']);
205
206 if ($metablock['padded_data']) {
207
208 $metablock['size']--;
209 $metablock['data'] = substr($metablock['data'], 0, -1);
210 }
211 break;
212
213 case 0x00:
214 case 0x01:
215 case 0x02:
216 case 0x03:
217 case 0x04:
218 case 0x05:
219 case 0x06:
220 case 0x07:
221 case 0x08:
222 case 0x09:
223 case 0x0A:
224 case 0x0B:
225 case 0x0C:
226 case 0x0D:
227 fseek($this->getid3->fp, $metablock[
'offset'] + ($metablock[
'large_block'] ? 4 : 2) + $metablock[
'size'], SEEK_SET);
228 break;
229
230 default:
231 $info[
'warning'][] =
'Unexpected metablock type "0x'.str_pad(dechex($metablock[
'function_id']), 2,
'0', STR_PAD_LEFT).
'" at offset '.$metablock[
'offset'];
232 fseek($this->getid3->fp, $metablock[
'offset'] + ($metablock[
'large_block'] ? 4 : 2) + $metablock[
'size'], SEEK_SET);
233 break;
234 }
235
236 switch ($metablock['function_id']) {
237 case 0x21:
239
240 $getid3_temp = new GetId3Core();
241 $getid3_temp->openfile($this->getid3->filename);
242 $getid3_riff = new Riff($getid3_temp);
243 $getid3_riff->ParseRIFFdata($metablock['data']);
244 $metablock['riff'] = $getid3_temp->info['riff'];
245 $info[
'audio'][
'sample_rate'] = $getid3_temp->info[
'riff'][
'raw'][
'fmt '][
'nSamplesPerSec'];
246 unset($getid3_riff, $getid3_temp);
247
248 $metablock['riff']['original_filesize'] = $original_wav_filesize;
249 $info[
'wavpack'][
'riff_trailer_size'] = $original_wav_filesize - $metablock[
'riff'][
'WAVE'][
'data'][0][
'size'] - $metablock[
'riff'][
'header_size'];
250 $info[
'playtime_seconds'] =
$info[
'wavpack'][
'blockheader'][
'total_samples'] /
$info[
'audio'][
'sample_rate'];
251
252
253 $metablockRIFFheader = $metablock['data'];
254 break;
255
256
257 case 0x22:
258 $metablockRIFFfooter = $metablockRIFFheader.$metablock['data'];
259
260 $startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2);
261 $getid3_temp = new GetId3Core();
262 $getid3_temp->openfile($this->getid3->filename);
263 $getid3_temp->info[
'avdataend'] =
$info[
'avdataend'];
264 $getid3_temp->info['fileformat'] = 'riff';
265 $getid3_riff = new Riff($getid3_temp);
266 $metablock['riff'] = $getid3_riff->ParseRIFF($startoffset, $startoffset + $metablock['size']);
267
268 if (!empty($metablock['riff']['INFO'])) {
269 $getid3_riff->RIFFcommentsParse($metablock['riff']['INFO'], $metablock['comments']);
270 $info[
'tags'][
'riff'] = $metablock[
'comments'];
271 }
272 unset($getid3_temp, $getid3_riff);
273 break;
274
275
276 case 0x23:
277 $info[
'warning'][] =
'WavPack "Replay Gain" contents not yet handled by GetId3Core() in metablock at offset '.$metablock[
'offset'];
278 break;
279
280
281 case 0x24:
282 $info[
'warning'][] =
'WavPack "Cuesheet" contents not yet handled by GetId3Core() in metablock at offset '.$metablock[
'offset'];
283 break;
284
285
286 case 0x25:
288
289 $metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001);
290 $metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002);
291 $metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004);
292 $metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008);
293 $metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010);
294 $metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020);
295 $metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040);
296 $metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080);
297 $metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100);
298 $metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200);
299 $metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400);
300 $metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800);
301 $metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000);
302 $metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000);
303 $metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000);
304 $metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000);
305 $metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000);
306 $metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000);
307 $metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000);
308 $metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000);
309 $metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000);
310
311 $info[
'wavpack'][
'config_flags'] = $metablock[
'flags'];
312
313 $info[
'audio'][
'encoder_options'] =
'';
314 if (
$info[
'wavpack'][
'blockheader'][
'flags'][
'hybrid']) {
315 $info[
'audio'][
'encoder_options'] .=
' -b???';
316 }
317 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'adobe_mode'] ?
' -a' :
'');
318 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'optimize_wvc'] ?
' -cc' :
'');
319 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'create_exe'] ?
' -e' :
'');
320 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'fast_flag'] ?
' -f' :
'');
321 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'joint_override'] ?
' -j?' :
'');
322 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'high_flag'] ?
' -h' :
'');
323 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'md5_checksum'] ?
' -m' :
'');
324 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'calc_noise'] ?
' -n' :
'');
325 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'shape_override'] ?
' -s?' :
'');
326 $info[
'audio'][
'encoder_options'] .= ($metablock[
'flags'][
'extra_mode'] ?
' -x?' :
'');
327 if (!empty(
$info[
'audio'][
'encoder_options'])) {
328 $info[
'audio'][
'encoder_options'] = trim(
$info[
'audio'][
'encoder_options']);
329 } elseif (isset(
$info[
'audio'][
'encoder_options'])) {
330 unset(
$info[
'audio'][
'encoder_options']);
331 }
332 break;
333
334 case 0x26:
335 if (strlen($metablock['data']) == 16) {
337 } else {
338 $info[
'warning'][] =
'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock[
'offset'].
', but found '.strlen($metablock[
'data']).
' bytes';
339 }
340 break;
341
342 case 0x00:
343 case 0x01:
344 case 0x02:
345 case 0x03:
346 case 0x04:
347 case 0x05:
348 case 0x06:
349 case 0x07:
350 case 0x08:
351 case 0x09:
352 case 0x0A:
353 case 0x0B:
354 case 0x0C:
355 case 0x0D:
356 unset($metablock);
357 break;
358 }
359
360 }
361 if (!empty($metablock)) {
362 $info[
'wavpack'][
'metablocks'][] = $metablock;
363 }
364
365 }
366
367 }
368
369 $info[
'audio'][
'encoder'] =
'WavPack v'.$info[
'wavpack'][
'blockheader'][
'major_version'].
'.'.str_pad(
$info[
'wavpack'][
'blockheader'][
'minor_version'], 2,
'0', STR_PAD_LEFT);
370 $info[
'audio'][
'bits_per_sample'] =
$info[
'wavpack'][
'blockheader'][
'flags'][
'bytes_per_sample'] * 8;
371 $info[
'audio'][
'channels'] = (
$info[
'wavpack'][
'blockheader'][
'flags'][
'mono'] ? 1 : 2);
372
373 if (!empty(
$info[
'playtime_seconds'])) {
374
375 $info[
'audio'][
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
376
377 } else {
378
379 $info[
'audio'][
'dataformat'] =
'wvc';
380
381 }
382
383 return true;
384 }
fseek($bytes, $whence=SEEK_SET)
static LittleEndian2Int($byteword, $signed=false)
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
WavPackMetablockNameLookup(&$id)
@staticvar array $WavPackMetablockNameLookup