50be37c321bbf7d76bc8f06442c2af0219ce63ae
[lhc/web/www.git] / www / plugins-dist / medias / lib / getid3 / module.audio.dsf.php
1 <?php
2 /////////////////////////////////////////////////////////////////
3 /// getID3() by James Heinrich <info@getid3.org> //
4 // available at http://getid3.sourceforge.net //
5 // or http://www.getid3.org //
6 // also https://github.com/JamesHeinrich/getID3 //
7 /////////////////////////////////////////////////////////////////
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 public function Analyze() {
23 $info = &$this->getid3->info;
24
25 $info['fileformat'] = 'dsf';
26 $info['audio']['dataformat'] = 'dsf';
27 $info['audio']['lossless'] = true;
28 $info['audio']['bitrate_mode'] = 'cbr';
29
30 $this->fseek($info['avdataoffset']);
31 $dsfheader = $this->fread(28 + 12);
32
33 $headeroffset = 0;
34 $info['dsf']['dsd']['magic'] = substr($dsfheader, $headeroffset, 4);
35 $headeroffset += 4;
36 $magic = 'DSD ';
37 if ($info['dsf']['dsd']['magic'] != $magic) {
38 $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dsf']['dsd']['magic']).'"');
39 unset($info['fileformat']);
40 unset($info['audio']);
41 unset($info['dsf']);
42 return false;
43 }
44 $info['dsf']['dsd']['dsd_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // should be 28
45 $headeroffset += 8;
46 $info['dsf']['dsd']['dsf_file_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
47 $headeroffset += 8;
48 $info['dsf']['dsd']['meta_chunk_offset'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
49 $headeroffset += 8;
50
51
52 $info['dsf']['fmt']['magic'] = substr($dsfheader, $headeroffset, 4);
53 $headeroffset += 4;
54 $magic = 'fmt ';
55 if ($info['dsf']['fmt']['magic'] != $magic) {
56 $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['fmt']['magic']).'"');
57 return false;
58 }
59 $info['dsf']['fmt']['fmt_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // usually 52 bytes
60 $headeroffset += 8;
61 $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.
62 if (strlen($dsfheader) != ($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size'] + 12)) {
63 $this->error('Expecting '.($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size']).' bytes header, found '.strlen($dsfheader).' bytes');
64 return false;
65 }
66 $info['dsf']['fmt']['format_version'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "1"
67 $headeroffset += 4;
68 $info['dsf']['fmt']['format_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "0" = "DSD Raw"
69 $headeroffset += 4;
70 $info['dsf']['fmt']['channel_type_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
71 $headeroffset += 4;
72 $info['dsf']['fmt']['channels'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
73 $headeroffset += 4;
74 $info['dsf']['fmt']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
75 $headeroffset += 4;
76 $info['dsf']['fmt']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
77 $headeroffset += 4;
78 $info['dsf']['fmt']['sample_count'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
79 $headeroffset += 8;
80 $info['dsf']['fmt']['channel_block_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4));
81 $headeroffset += 4;
82 $info['dsf']['fmt']['reserved'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // zero-filled
83 $headeroffset += 4;
84
85
86 $info['dsf']['data']['magic'] = substr($dsfheader, $headeroffset, 4);
87 $headeroffset += 4;
88 $magic = 'data';
89 if ($info['dsf']['data']['magic'] != $magic) {
90 $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['data']['magic']).'"');
91 return false;
92 }
93 $info['dsf']['data']['data_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8));
94 $headeroffset += 8;
95 $info['avdataoffset'] = $headeroffset;
96 $info['avdataend'] = $info['avdataoffset'] + $info['dsf']['data']['data_chunk_size'];
97
98
99 if ($info['dsf']['dsd']['meta_chunk_offset'] > 0) {
100 $getid3_id3v2 = new getid3_id3v2($this->getid3);
101 $getid3_id3v2->StartingOffset = $info['dsf']['dsd']['meta_chunk_offset'];
102 $getid3_id3v2->Analyze();
103 unset($getid3_id3v2);
104 }
105
106
107 $info['dsf']['fmt']['channel_type'] = $this->DSFchannelTypeLookup($info['dsf']['fmt']['channel_type_id']);
108 $info['audio']['channelmode'] = $info['dsf']['fmt']['channel_type'];
109 $info['audio']['bits_per_sample'] = $info['dsf']['fmt']['bits_per_sample'];
110 $info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate'];
111 $info['audio']['channels'] = $info['dsf']['fmt']['channels'];
112 $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels'];
113 $info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate'];
114
115 return true;
116 }
117
118
119 public static function DSFchannelTypeLookup($channel_type_id) {
120 static $DSFchannelTypeLookup = array(
121 // interleaving order:
122 1 => 'mono', // 1: Mono
123 2 => 'stereo', // 1: Front-Left; 2: Front-Right
124 3 => '3-channel', // 1: Front-Left; 2: Front-Right; 3: Center
125 4 => 'quad', // 1: Front-Left; 2: Front-Right; 3: Back-Left; 4: Back-Right
126 5 => '4-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency
127 6 => '5-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Back-Left 5: Back-Right
128 7 => '5.1', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency; 5: Back-Left; 6: Back-Right
129 );
130 return (isset($DSFchannelTypeLookup[$channel_type_id]) ? $DSFchannelTypeLookup[$channel_type_id] : '');
131 }
132
133 }