[SPIP] v3.2.1-->v3.2.3
[lhc/web/www.git] / www / plugins-dist / medias / lib / getid3 / module.audio.dsf.php
1 <?php
2
3 /////////////////////////////////////////////////////////////////
4 /// getID3() by James Heinrich <info@getid3.org> //
5 // available at https://github.com/JamesHeinrich/getID3 //
6 // or https://www.getid3.org //
7 // or http://getid3.sourceforge.net //
8 // see readme.txt for more details //
9 /////////////////////////////////////////////////////////////////
10 // //
11 // module.audio.dsf.php //
12 // module for analyzing dsf/DSF Audio files //
13 // dependencies: module.tag.id3v2.php //
14 // ///
15 /////////////////////////////////////////////////////////////////
16
17 getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
18
19 class getid3_dsf extends getid3_handler
20 {
21 /**
22 * @return bool
23 */
24 public function Analyze() {
25 $info = &$this->getid3->info;
26
27 $info['fileformat'] = 'dsf';
28 $info['audio']['dataformat'] = 'dsf';
29 $info['audio']['lossless'] = true;
30 $info['audio']['bitrate_mode'] = 'cbr';
31
32 $this->fseek($info['avdataoffset']);
33 $dsfheader = $this->fread(28 + 12);
34
35 $headeroffset = 0;
36 $info['dsf']['dsd']['magic'] = substr($dsfheader, $headeroffset, 4);
37 $headeroffset += 4;
38 $magic = 'DSD ';
39 if ($info['dsf']['dsd']['magic'] != $magic) {
40 $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dsf']['dsd']['magic']).'"');
41 unset($info['fileformat']);
42 unset($info['audio']);
43 unset($info['dsf']);
44 return false;
45 }
46 $info['dsf']['dsd']['dsd_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // should be 28
47 $headeroffset += 8;
48 $info['dsf']['dsd']['dsf_file_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
49 $headeroffset += 8;
50 $info['dsf']['dsd']['meta_chunk_offset'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
51 $headeroffset += 8;
52
53
54 $info['dsf']['fmt']['magic'] = substr($dsfheader, $headeroffset, 4);
55 $headeroffset += 4;
56 $magic = 'fmt ';
57 if ($info['dsf']['fmt']['magic'] != $magic) {
58 $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['fmt']['magic']).'"');
59 return false;
60 }
61 $info['dsf']['fmt']['fmt_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // usually 52 bytes
62 $headeroffset += 8;
63 $dsfheader .= $this->fread($info['dsf']['fmt']['fmt_chunk_size'] - 12 + 12); // we have already read the entire DSD chunk, plus 12 bytes of FMT. We now want to read the size of FMT, plus 12 bytes into the next chunk to get magic and size.
64 if (strlen($dsfheader) != ($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size'] + 12)) {
65 $this->error('Expecting '.($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size']).' bytes header, found '.strlen($dsfheader).' bytes');
66 return false;
67 }
68 $info['dsf']['fmt']['format_version'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "1"
69 $headeroffset += 4;
70 $info['dsf']['fmt']['format_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "0" = "DSD Raw"
71 $headeroffset += 4;
72 $info['dsf']['fmt']['channel_type_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
73 $headeroffset += 4;
74 $info['dsf']['fmt']['channels'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
75 $headeroffset += 4;
76 $info['dsf']['fmt']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
77 $headeroffset += 4;
78 $info['dsf']['fmt']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
79 $headeroffset += 4;
80 $info['dsf']['fmt']['sample_count'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
81 $headeroffset += 8;
82 $info['dsf']['fmt']['channel_block_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
83 $headeroffset += 4;
84 $info['dsf']['fmt']['reserved'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // zero-filled
85 $headeroffset += 4;
86
87
88 $info['dsf']['data']['magic'] = substr($dsfheader, $headeroffset, 4);
89 $headeroffset += 4;
90 $magic = 'data';
91 if ($info['dsf']['data']['magic'] != $magic) {
92 $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['data']['magic']).'"');
93 return false;
94 }
95 $info['dsf']['data']['data_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
96 $headeroffset += 8;
97 $info['avdataoffset'] = $headeroffset;
98 $info['avdataend'] = $info['avdataoffset'] + $info['dsf']['data']['data_chunk_size'];
99
100
101 if ($info['dsf']['dsd']['meta_chunk_offset'] > 0) {
102 $getid3_id3v2 = new getid3_id3v2($this->getid3);
103 $getid3_id3v2->StartingOffset = $info['dsf']['dsd']['meta_chunk_offset'];
104 $getid3_id3v2->Analyze();
105 unset($getid3_id3v2);
106 }
107
108
109 $info['dsf']['fmt']['channel_type'] = $this->DSFchannelTypeLookup($info['dsf']['fmt']['channel_type_id']);
110 $info['audio']['channelmode'] = $info['dsf']['fmt']['channel_type'];
111 $info['audio']['bits_per_sample'] = $info['dsf']['fmt']['bits_per_sample'];
112 $info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate'];
113 $info['audio']['channels'] = $info['dsf']['fmt']['channels'];
114 $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
115 $info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate'];
116
117 return true;
118 }
119
120 /**
121 * @param int $channel_type_id
122 *
123 * @return string
124 */
125 public static function DSFchannelTypeLookup($channel_type_id) {
126 static $DSFchannelTypeLookup = array(
127 // interleaving order:
128 1 => 'mono', // 1: Mono
129 2 => 'stereo', // 1: Front-Left; 2: Front-Right
130 3 => '3-channel', // 1: Front-Left; 2: Front-Right; 3: Center
131 4 => 'quad', // 1: Front-Left; 2: Front-Right; 3: Back-Left; 4: Back-Right
132 5 => '4-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency
133 6 => '5-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Back-Left 5: Back-Right
134 7 => '5.1', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency; 5: Back-Left; 6: Back-Right
135 );
136 return (isset($DSFchannelTypeLookup[$channel_type_id]) ? $DSFchannelTypeLookup[$channel_type_id] : '');
137 }
138
139 }