Total Complexity | 84 |
Total Lines | 349 |
Duplicated Lines | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Complex classes like getid3_wavpack often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use getid3_wavpack, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
24 | class getid3_wavpack extends getid3_handler |
||
25 | { |
||
26 | |||
27 | public function Analyze() |
||
28 | { |
||
29 | $getid3 = $this->getid3; |
||
30 | |||
31 | $getid3->include_module('audio-video.riff'); |
||
32 | |||
33 | $getid3->info['wavpack'] = []; |
||
34 | $info_wavpack = &$getid3->info['wavpack']; |
||
35 | |||
36 | fseek($getid3->fp, $getid3->info['avdataoffset'], SEEK_SET); |
||
37 | |||
38 | while (true) { |
||
39 | $wavpack_header = fread($getid3->fp, 32); |
||
40 | |||
41 | if (ftell($getid3->fp) >= $getid3->info['avdataend']) { |
||
42 | break; |
||
43 | } elseif (feof($getid3->fp)) { |
||
44 | break; |
||
45 | } elseif ((@$info_wavpack_blockheader['total_samples'] > 0) |
||
|
|||
46 | && (@$info_wavpack_blockheader['block_samples'] > 0) |
||
47 | && (!isset($info_wavpack['riff_trailer_size']) || ($info_wavpack['riff_trailer_size'] <= 0)) |
||
48 | && ((false === @$info_wavpack['config_flags']['md5_checksum']) || !empty($getid3->info['md5_data_source']))) { |
||
49 | break; |
||
50 | } |
||
51 | |||
52 | $block_header_offset = ftell($getid3->fp) - 32; |
||
53 | $block_header_magic = substr($wavpack_header, 0, 4); |
||
54 | $block_header_size = getid3_lib::LittleEndian2Int(substr($wavpack_header, 4, 4)); |
||
55 | |||
56 | if ('wvpk' != $block_header_magic) { |
||
57 | throw new getid3_exception('Expecting "wvpk" at offset ' . $block_header_offset . ', found "' . $block_header_magic . '"'); |
||
58 | } |
||
59 | |||
60 | if ((@$info_wavpack_blockheader['block_samples'] <= 0) || (@$info_wavpack_blockheader['total_samples'] <= 0)) { |
||
61 | // Also, it is possible that the first block might not have |
||
62 | // any samples (block_samples == 0) and in this case you should skip blocks |
||
63 | // until you find one with samples because the other information (like |
||
64 | // total_samples) are not guaranteed to be correct until (block_samples > 0) |
||
65 | |||
66 | // Finally, I have defined a format for files in which the length is not known |
||
67 | // (for example when raw files are created using pipes). In these cases |
||
68 | // total_samples will be -1 and you must seek to the final block to determine |
||
69 | // the total number of samples. |
||
70 | |||
71 | $getid3->info['audio']['dataformat'] = 'wavpack'; |
||
72 | $getid3->info['fileformat'] = 'wavpack'; |
||
73 | $getid3->info['audio']['lossless'] = true; |
||
74 | $getid3->info['audio']['bitrate_mode'] = 'vbr'; |
||
75 | |||
76 | $info_wavpack['blockheader']['offset'] = $block_header_offset; |
||
77 | $info_wavpack['blockheader']['magic'] = $block_header_magic; |
||
78 | $info_wavpack['blockheader']['size'] = $block_header_size; |
||
79 | $info_wavpack_blockheader = &$info_wavpack['blockheader']; |
||
80 | |||
81 | if ($info_wavpack_blockheader['size'] >= 0x100000) { |
||
82 | throw new getid3_exception('Expecting WavPack block size less than "0x100000", found "' . $info_wavpack_blockheader['size'] . '" at offset ' . $info_wavpack_blockheader['offset']); |
||
83 | } |
||
84 | |||
85 | $info_wavpack_blockheader['minor_version'] = ord($wavpack_header{8}); |
||
86 | $info_wavpack_blockheader['major_version'] = ord($wavpack_header{9}); |
||
87 | |||
88 | if ((4 != $info_wavpack_blockheader['major_version']) |
||
89 | || (($info_wavpack_blockheader['minor_version'] < 4) |
||
90 | && ($info_wavpack_blockheader['minor_version'] > 16))) { |
||
91 | throw new getid3_exception('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']); |
||
92 | } |
||
93 | |||
94 | $info_wavpack_blockheader['track_number'] = ord($wavpack_header{10}); // unused |
||
95 | $info_wavpack_blockheader['index_number'] = ord($wavpack_header{11}); // unused |
||
96 | |||
97 | getid3_lib::ReadSequence( |
||
98 | 'LittleEndian2Int', |
||
99 | $info_wavpack_blockheader, |
||
100 | $wavpack_header, |
||
101 | 12, |
||
102 | [ |
||
103 | 'total_samples' => 4, |
||
104 | 'block_index' => 4, |
||
105 | 'block_samples' => 4, |
||
106 | 'flags_raw' => 4, |
||
107 | 'crc' => 4 |
||
108 | ] |
||
109 | ); |
||
110 | |||
111 | $info_wavpack_blockheader['flags']['bytes_per_sample'] = 1 + ($info_wavpack_blockheader['flags_raw'] & 0x00000003); |
||
112 | $info_wavpack_blockheader['flags']['mono'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000004); |
||
113 | $info_wavpack_blockheader['flags']['hybrid'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000008); |
||
114 | $info_wavpack_blockheader['flags']['joint_stereo'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000010); |
||
115 | $info_wavpack_blockheader['flags']['cross_decorrelation'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000020); |
||
116 | $info_wavpack_blockheader['flags']['hybrid_noiseshape'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000040); |
||
117 | $info_wavpack_blockheader['flags']['ieee_32bit_float'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000080); |
||
118 | $info_wavpack_blockheader['flags']['int_32bit'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000100); |
||
119 | $info_wavpack_blockheader['flags']['hybrid_bitrate_noise'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000200); |
||
120 | $info_wavpack_blockheader['flags']['hybrid_balance_noise'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000400); |
||
121 | $info_wavpack_blockheader['flags']['multichannel_initial'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00000800); |
||
122 | $info_wavpack_blockheader['flags']['multichannel_final'] = (bool)($info_wavpack_blockheader['flags_raw'] & 0x00001000); |
||
123 | |||
124 | $getid3->info['audio']['lossless'] = !$info_wavpack_blockheader['flags']['hybrid']; |
||
125 | } |
||
126 | |||
127 | while (!feof($getid3->fp) && (ftell($getid3->fp) < ($block_header_offset + $block_header_size + 8))) { |
||
128 | $metablock = ['offset' => ftell($getid3->fp)]; |
||
129 | $metablockheader = fread($getid3->fp, 2); |
||
130 | if (feof($getid3->fp)) { |
||
131 | break; |
||
132 | } |
||
133 | $metablock['id'] = ord($metablockheader{0}); |
||
134 | $metablock['function_id'] = ($metablock['id'] & 0x3F); |
||
135 | $metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']); |
||
136 | |||
137 | // The 0x20 bit in the id of the meta subblocks (which is defined as |
||
138 | // ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that |
||
139 | // if a decoder encounters an id that it does not know about, it uses |
||
140 | // that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set |
||
141 | // then the decoder simply ignores the metadata, but if it is zero |
||
142 | // then the decoder should quit because it means that an understanding |
||
143 | // of the metadata is required to correctly decode the audio. |
||
144 | |||
145 | $metablock['non_decoder'] = (bool)($metablock['id'] & 0x20); |
||
146 | $metablock['padded_data'] = (bool)($metablock['id'] & 0x40); |
||
147 | $metablock['large_block'] = (bool)($metablock['id'] & 0x80); |
||
148 | if ($metablock['large_block']) { |
||
149 | $metablockheader .= fread($getid3->fp, 2); |
||
150 | } |
||
151 | $metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words |
||
152 | $metablock['data'] = null; |
||
153 | |||
154 | if ($metablock['size'] > 0) { |
||
155 | switch ($metablock['function_id']) { |
||
156 | case 0x21: // ID_RIFF_HEADER |
||
157 | case 0x22: // ID_RIFF_TRAILER |
||
158 | case 0x23: // ID_REPLAY_GAIN |
||
159 | case 0x24: // ID_CUESHEET |
||
160 | case 0x25: // ID_CONFIG_BLOCK |
||
161 | case 0x26: // ID_MD5_CHECKSUM |
||
162 | $metablock['data'] = fread($getid3->fp, $metablock['size']); |
||
163 | |||
164 | if ($metablock['padded_data']) { |
||
165 | // padded to the nearest even byte |
||
166 | $metablock['size']--; |
||
167 | $metablock['data'] = substr($metablock['data'], 0, -1); |
||
168 | } |
||
169 | break; |
||
170 | |||
171 | case 0x00: // ID_DUMMY |
||
172 | case 0x01: // ID_ENCODER_INFO |
||
173 | case 0x02: // ID_DECORR_TERMS |
||
174 | case 0x03: // ID_DECORR_WEIGHTS |
||
175 | case 0x04: // ID_DECORR_SAMPLES |
||
176 | case 0x05: // ID_ENTROPY_VARS |
||
177 | case 0x06: // ID_HYBRID_PROFILE |
||
178 | case 0x07: // ID_SHAPING_WEIGHTS |
||
179 | case 0x08: // ID_FLOAT_INFO |
||
180 | case 0x09: // ID_INT32_INFO |
||
181 | case 0x0A: // ID_WV_BITSTREAM |
||
182 | case 0x0B: // ID_WVC_BITSTREAM |
||
183 | case 0x0C: // ID_WVX_BITSTREAM |
||
184 | case 0x0D: // ID_CHANNEL_INFO |
||
185 | fseek($getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); |
||
186 | break; |
||
187 | |||
188 | default: |
||
189 | $getid3->warning('Unexpected metablock type "0x' . str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT) . '" at offset ' . $metablock['offset']); |
||
190 | fseek($getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); |
||
191 | break; |
||
192 | } |
||
193 | |||
194 | switch ($metablock['function_id']) { |
||
195 | case 0x21: // ID_RIFF_HEADER |
||
196 | |||
197 | $original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4)); |
||
198 | |||
199 | // Clone getid3 |
||
200 | $clone = clone $getid3; |
||
201 | |||
202 | // Analyze clone by string |
||
203 | $riff = new getid3_riff($clone); |
||
204 | $riff->AnalyzeString($metablock['data']); |
||
205 | |||
206 | // Import from clone and destroy |
||
207 | $metablock['riff'] = $clone->info['riff']; |
||
208 | $getid3->warnings($clone->warnings()); |
||
209 | unset($clone); |
||
210 | |||
211 | // Save RIFF header - we may need it later for RIFF footer parsing |
||
212 | $this->riff_header = $metablock['data']; |
||
213 | |||
214 | $metablock['riff']['original_filesize'] = $original_wav_filesize; |
||
215 | $info_wavpack['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size']; |
||
216 | |||
217 | $getid3->info['audio']['sample_rate'] = $metablock['riff']['raw']['fmt ']['nSamplesPerSec']; |
||
218 | $getid3->info['playtime_seconds'] = $info_wavpack_blockheader['total_samples'] / $getid3->info['audio']['sample_rate']; |
||
219 | |||
220 | // Safe RIFF header in case there's a RIFF footer later |
||
221 | $metablock_riff_header = $metablock['data']; |
||
222 | break; |
||
223 | |||
224 | case 0x22: // ID_RIFF_TRAILER |
||
225 | |||
226 | $metablock_riff_footer = $metablock_riff_header . $metablock['data']; |
||
227 | |||
228 | $start_offset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2); |
||
229 | |||
230 | $ftell_old = ftell($getid3->fp); |
||
231 | |||
232 | // Clone getid3 |
||
233 | $clone = clone $getid3; |
||
234 | |||
235 | // Call public method that really should be private |
||
236 | $riff = new getid3_riff($clone); |
||
237 | $metablock['riff'] = $riff->ParseRIFF($start_offset, $start_offset + $metablock['size']); |
||
238 | unset($clone); |
||
239 | |||
240 | fseek($getid3->fp, $ftell_old, SEEK_SET); |
||
241 | |||
242 | if (!empty($metablock['riff']['INFO'])) { |
||
243 | getid3_riff::RIFFCommentsParse($metablock['riff']['INFO'], $metablock['comments']); |
||
244 | $getid3->info['tags']['riff'] = $metablock['comments']; |
||
245 | } |
||
246 | break; |
||
247 | |||
248 | case 0x23: // ID_REPLAY_GAIN |
||
249 | $getid3->warning('WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset ' . $metablock['offset']); |
||
250 | break; |
||
251 | |||
252 | case 0x24: // ID_CUESHEET |
||
253 | $getid3->warning('WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset ' . $metablock['offset']); |
||
254 | break; |
||
255 | |||
256 | case 0x25: // ID_CONFIG_BLOCK |
||
257 | $metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3)); |
||
258 | |||
259 | $metablock['flags']['adobe_mode'] = (bool)($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats |
||
260 | $metablock['flags']['fast_flag'] = (bool)($metablock['flags_raw'] & 0x000002); // fast mode |
||
261 | $metablock['flags']['very_fast_flag'] = (bool)($metablock['flags_raw'] & 0x000004); // double fast |
||
262 | $metablock['flags']['high_flag'] = (bool)($metablock['flags_raw'] & 0x000008); // high quality mode |
||
263 | $metablock['flags']['very_high_flag'] = (bool)($metablock['flags_raw'] & 0x000010); // double high (not used yet) |
||
264 | $metablock['flags']['bitrate_kbps'] = (bool)($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample |
||
265 | $metablock['flags']['auto_shaping'] = (bool)($metablock['flags_raw'] & 0x000040); // automatic noise shaping |
||
266 | $metablock['flags']['shape_override'] = (bool)($metablock['flags_raw'] & 0x000080); // shaping mode specified |
||
267 | $metablock['flags']['joint_override'] = (bool)($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified |
||
268 | $metablock['flags']['copy_time'] = (bool)($metablock['flags_raw'] & 0x000200); // copy file-time from source |
||
269 | $metablock['flags']['create_exe'] = (bool)($metablock['flags_raw'] & 0x000400); // create executable |
||
270 | $metablock['flags']['create_wvc'] = (bool)($metablock['flags_raw'] & 0x000800); // create correction file |
||
271 | $metablock['flags']['optimize_wvc'] = (bool)($metablock['flags_raw'] & 0x001000); // maximize bybrid compression |
||
272 | $metablock['flags']['quality_mode'] = (bool)($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode |
||
273 | $metablock['flags']['raw_flag'] = (bool)($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet) |
||
274 | $metablock['flags']['calc_noise'] = (bool)($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode |
||
275 | $metablock['flags']['lossy_mode'] = (bool)($metablock['flags_raw'] & 0x010000); // obsolete (for information) |
||
276 | $metablock['flags']['extra_mode'] = (bool)($metablock['flags_raw'] & 0x020000); // extra processing mode |
||
277 | $metablock['flags']['skip_wvx'] = (bool)($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints |
||
278 | $metablock['flags']['md5_checksum'] = (bool)($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature |
||
279 | $metablock['flags']['quiet_mode'] = (bool)($metablock['flags_raw'] & 0x100000); // don't report progress % |
||
280 | |||
281 | $info_wavpack['config_flags'] = $metablock['flags']; |
||
282 | |||
283 | $getid3->info['audio']['encoder_options'] = trim( |
||
284 | ($info_wavpack_blockheader['flags']['hybrid'] ? ' -b???' : '') |
||
285 | . ($metablock['flags']['adobe_mode'] ? ' -a' : '') |
||
286 | . ($metablock['flags']['optimize_wvc'] ? ' -cc' : '') |
||
287 | . ($metablock['flags']['create_exe'] ? ' -e' : '') |
||
288 | . ($metablock['flags']['fast_flag'] ? ' -f' : '') |
||
289 | . ($metablock['flags']['joint_override'] ? ' -j?' : '') |
||
290 | . ($metablock['flags']['high_flag'] ? ' -h' : '') |
||
291 | . ($metablock['flags']['md5_checksum'] ? ' -m' : '') |
||
292 | . ($metablock['flags']['calc_noise'] ? ' -n' : '') |
||
293 | . ($metablock['flags']['shape_override'] ? ' -s?' : '') |
||
294 | . ($metablock['flags']['extra_mode'] ? ' -x?' : '') |
||
295 | ); |
||
296 | if (!$getid3->info['audio']['encoder_options']) { |
||
297 | unset($getid3->info['audio']['encoder_options']); |
||
298 | } |
||
299 | break; |
||
300 | |||
301 | case 0x26: // ID_MD5_CHECKSUM |
||
302 | if (16 == strlen($metablock['data'])) { |
||
303 | $getid3->info['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false)); |
||
304 | } else { |
||
305 | $getid3->warning('Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset ' . $metablock['offset'] . ', but found ' . strlen($metablock['data']) . ' bytes'); |
||
306 | } |
||
307 | break; |
||
308 | |||
309 | case 0x00: // ID_DUMMY |
||
310 | case 0x01: // ID_ENCODER_INFO |
||
311 | case 0x02: // ID_DECORR_TERMS |
||
312 | case 0x03: // ID_DECORR_WEIGHTS |
||
313 | case 0x04: // ID_DECORR_SAMPLES |
||
314 | case 0x05: // ID_ENTROPY_VARS |
||
315 | case 0x06: // ID_HYBRID_PROFILE |
||
316 | case 0x07: // ID_SHAPING_WEIGHTS |
||
317 | case 0x08: // ID_FLOAT_INFO |
||
318 | case 0x09: // ID_INT32_INFO |
||
319 | case 0x0A: // ID_WV_BITSTREAM |
||
320 | case 0x0B: // ID_WVC_BITSTREAM |
||
321 | case 0x0C: // ID_WVX_BITSTREAM |
||
322 | case 0x0D: // ID_CHANNEL_INFO |
||
323 | unset($metablock); |
||
324 | break; |
||
325 | } |
||
326 | } |
||
327 | |||
328 | if (!empty($metablock)) { |
||
329 | $info_wavpack['metablocks'][] = $metablock; |
||
330 | } |
||
331 | } |
||
332 | } |
||
333 | |||
334 | $getid3->info['audio']['encoder'] = 'WavPack v' . $info_wavpack_blockheader['major_version'] . '.' . str_pad($info_wavpack_blockheader['minor_version'], 2, '0', STR_PAD_LEFT); |
||
335 | $getid3->info['audio']['bits_per_sample'] = $info_wavpack_blockheader['flags']['bytes_per_sample'] * 8; |
||
336 | $getid3->info['audio']['channels'] = ($info_wavpack_blockheader['flags']['mono'] ? 1 : 2); |
||
337 | |||
338 | if (@$getid3->info['playtime_seconds']) { |
||
339 | $getid3->info['audio']['bitrate'] = (($getid3->info['avdataend'] - $getid3->info['avdataoffset']) * 8) / $getid3->info['playtime_seconds']; |
||
340 | } else { |
||
341 | $getid3->info['audio']['dataformat'] = 'wvc'; |
||
342 | } |
||
343 | |||
344 | return true; |
||
345 | } |
||
346 | |||
347 | public static function WavPackMetablockNameLookup($id) |
||
373 | } |
||
374 | |||
378 |