source: gs3-extensions/web-audio/trunk/js-mad/script/id3v22stream.js@ 28388

Last change on this file since 28388 was 28388, checked in by davidb, 11 years ago

Set of JS, CSS, PNG etc web resources to support a mixture of audio player/document display capabilities

File size: 8.8 KB
Line 
1var trimString = function (string) {
2 return string.replace(/\0$/, "");
3};
4
5var stringToEncoding = function(string, encoding) {
6 switch (encoding) {
7 case 0:
8 return trimString(string);
9 case 1:
10 var ix = 2, offset1 = 1, offset2 = 0;
11
12 if (string.slice(0, 2) === "\xFE\xFF") {
13 offset1 = 0, offset2 = 1;
14 } else {
15 offset1 = 1, offset2 = 0;
16 }
17
18 var result = "";
19
20 for (var ix = 2; ix < string.length; ix += 2) {
21 var byte1 = string[ix + offset1].charCodeAt(0);
22 var byte2 = string[ix + offset2].charCodeAt(0);
23
24 var word1 = (byte1 << 8) | byte2;
25
26 if (byte1 < 0xD8 || byte1 >= 0xE0) {
27 result += String.fromCharCode(word1);
28 } else {
29 ix += 2;
30
31 var byte3 = string[ix + offset1].charCodeAt(0);
32 var byte4 = string[ix + offset2].charCodeAt(0);
33
34 var word2 = (byte3 << 8) | byte4;
35
36 result += String.fromCharCode(word1, word2);
37 }
38 }
39
40 return trimString(result);
41 default:
42 return string;
43 }
44}
45
46var decodeIdentifierFrame = function(header, stream) {
47 var data = stream.read(header['length']);
48
49 var array = data.split("\0", 2);
50
51 return {
52 'header': header,
53 'owner': array[0],
54 'identifier': array[1]
55 };
56}
57
58var decodeTextFrame = function(header, stream) {
59 var encoding = stream.readU8();
60 var data = stream.read(header['length'] - 1);
61
62 return {
63 'header': header,
64 'value': stringToEncoding(data, encoding)
65 };
66}
67
68var decodeCommentFrame = function(header, stream) {
69 var encoding = stream.readU8();
70 var language = stream.read(3);
71
72 var data = stream.read(header['length'] - 4);
73
74 var array = data.split("\0", 2);
75
76 return {
77 'header': header,
78 'language': stringToEncoding(language, 0),
79 'description': stringToEncoding(array[0], 0),
80 'value': stringToEncoding(array[1], encoding)
81 };
82}
83
84var extendWithValueFrame = function(tags, frame) {
85 tags[frame['name']] = frame['value'];
86
87 return tags;
88}
89
90
91var extendWithIdentifierFrame = function(tags, frame) {
92 tags[frame['name']] = {
93 'owner': frame['value'],
94 'identifier': frame['identifier']
95 };
96
97 return tags;
98}
99
100var extendWithCommentFrame = function(tags, frame) {
101 if (!tags[frame['name']]) {
102 tags[frame['name']] = []
103 }
104
105 tags[frame['name']][frame['description']] = {
106 'language': frame['language'],
107 'value': frame['value']
108 };
109
110 return tags;
111}
112
113Mad.ID3v22Stream = function(header, stream) {
114 this.offset = 0;
115
116 this.header = header;
117 this.stream = stream;
118
119 this.decoders = {
120 'UFI': decodeIdentifierFrame,
121 'TT1': decodeTextFrame,
122 'TT2': decodeTextFrame,
123 'TT3': decodeTextFrame,
124 'TP1': decodeTextFrame,
125 'TP2': decodeTextFrame,
126 'TP3': decodeTextFrame,
127 'TP4': decodeTextFrame,
128 'TCM': decodeTextFrame,
129 'TXT': decodeTextFrame,
130 'TLA': decodeTextFrame,
131 'TCO': decodeTextFrame,
132 'TAL': decodeTextFrame,
133 'TPA': decodeTextFrame,
134 'TRK': decodeTextFrame,
135 'TRC': decodeTextFrame,
136 'TYE': decodeTextFrame,
137 'TDA': decodeTextFrame,
138 'TIM': decodeTextFrame,
139 'TRD': decodeTextFrame,
140 'TMT': decodeTextFrame,
141 'TFT': decodeTextFrame,
142 'TBP': decodeTextFrame,
143 'TCR': decodeTextFrame,
144 'TPB': decodeTextFrame,
145 'TEN': decodeTextFrame,
146 'TSS': decodeTextFrame,
147 'TOF': decodeTextFrame,
148 'TLE': decodeTextFrame,
149 'TSI': decodeTextFrame,
150 'TDY': decodeTextFrame,
151 'TKE': decodeTextFrame,
152 'TOT': decodeTextFrame,
153 'TOA': decodeTextFrame,
154 'TOL': decodeTextFrame,
155 'TOR': decodeTextFrame,
156
157 'COM': decodeCommentFrame
158 };
159
160 this.names = {
161 /* Identification Frames */
162 'TT1': 'Content group description',
163 'TT2': 'Title/Songname/Content description',
164 'TT3': 'Subtitle/Description refinement',
165 'TAL': 'Album/Movie/Show title',
166 'TOT': 'Original album/movie/show title',
167 'TRK': 'Track number/Position in set',
168 'TPA': 'Part of a set',
169 'TRC': 'ISRC',
170
171 /* Involved Persons Frames */
172 'TP1': 'Lead artist/Lead performer/Soloist/Performing group',
173 'TP2': 'Band/Orchestra/Accompaniment',
174 'TP3': 'Conductor',
175 'TP4': 'Interpreted, remixed, or otherwise modified by',
176 'TOA': 'Original artist/performer',
177 'TXT': 'Lyricist/Text writer',
178 'TOL': 'Original lyricist/text writer',
179 'TCO': 'Composer',
180 'TEN': 'Encoded by',
181
182 /* Derived and Subjective Properties Frames */
183 'TBP': 'BPM',
184 'TLE': 'Length',
185 'TKE': 'Initial key',
186 'TLA': 'Language',
187 'TMT': 'Media type',
188
189 /* Rights and Licence Frames */
190 'TCR': 'Copyright message',
191 'TPB': 'Publisher',
192
193 /* Other Text Frames */
194 'TOF': 'Original filename',
195 'TDY': 'Playlist delay',
196 'TSS': 'Software/Hardware and settings used for encoding',
197 'TFT': 'File type',
198
199 /* Buffering */
200 'BUF': 'Recommended buffer size',
201
202 /* Attached Picture Frame */
203 'PIC': 'Attached picture',
204
205 /* Unique Identifier Frame */
206 'UFI': 'Unique identifier',
207
208 /* Music CD Identifier Frame */
209 'MCI': 'Music CD identifier',
210
211 /* Comment Frame */
212 'COM': 'Comment',
213
214 /* User Defined URL Link Frame */
215 'WXX': 'User defined URL link',
216
217 /* Deprecated ID3v2 frames */
218 'TDA': 'Date',
219 'TIM': 'Time',
220 'TOR': 'Original release year',
221 'TRD': 'Recording dates',
222 'TSI': 'Size',
223 'TYE': 'Year'
224 };
225
226 this.extenders = {
227 'UFI': extendWithIdentifierFrame,
228 'TT1': extendWithValueFrame,
229 'TT2': extendWithValueFrame,
230 'TT3': extendWithValueFrame,
231 'TP1': extendWithValueFrame,
232 'TP2': extendWithValueFrame,
233 'TP3': extendWithValueFrame,
234 'TP4': extendWithValueFrame,
235 'TCM': extendWithValueFrame,
236 'TXT': extendWithValueFrame,
237 'TLA': extendWithValueFrame,
238 'TCO': extendWithValueFrame,
239 'TAL': extendWithValueFrame,
240 'TPA': extendWithValueFrame,
241 'TRK': extendWithValueFrame,
242 'TRC': extendWithValueFrame,
243 'TYE': extendWithValueFrame,
244 'TDA': extendWithValueFrame,
245 'TIM': extendWithValueFrame,
246 'TRD': extendWithValueFrame,
247 'TMT': extendWithValueFrame,
248 'TFT': extendWithValueFrame,
249 'TBP': extendWithValueFrame,
250 'TCR': extendWithValueFrame,
251 'TPB': extendWithValueFrame,
252 'TEN': extendWithValueFrame,
253 'TSS': extendWithValueFrame,
254 'TOF': extendWithValueFrame,
255 'TLE': extendWithValueFrame,
256 'TSI': extendWithValueFrame,
257 'TDY': extendWithValueFrame,
258 'TKE': extendWithValueFrame,
259 'TOT': extendWithValueFrame,
260 'TOA': extendWithValueFrame,
261 'TOL': extendWithValueFrame,
262 'TOR': extendWithValueFrame,
263
264 'COM': extendWithCommentFrame
265 };
266}
267
268Mad.ID3v22Stream.prototype.readFrame = function() {
269 if (this.offset >= this.header.length) {
270 return null;
271 }
272
273 var identifier = this.stream.read(3);
274
275 if (identifier.charCodeAt(0) === 0) {
276 this.offset = this.header.length + 1;
277
278 return null;
279 }
280
281 var length = this.stream.readU24(true);
282
283 var header = {
284identifier: identifier,
285 length: length
286 };
287
288 if (this.decoders[identifier]) {
289 var result = this.decoders[identifier](header, this.stream);
290 } else {
291 var result = {
292identifier: identifier,
293 header: header
294 };
295
296 this.stream.read(length);
297 }
298
299 result.name = this.names[identifier] ? this.names[identifier] : 'UNKNOWN';
300
301 this.offset += 10 + length;
302
303 return result;
304}
305
306Mad.ID3v22Stream.prototype.read = function() {
307 if (!this.array) {
308 this.array = [];
309
310 var frame = null;
311
312 try {
313 while (frame = this.readFrame()) {
314 this.array.push(frame);
315 }
316 } catch (e) {
317 throw(e);
318 //console.log("ID3 Error: " + e);
319 }
320 }
321
322 return this.array;
323}
324
325Mad.ID3v22Stream.prototype.toHash = function() {
326 var frames = this.read();
327
328 var hash = {};
329
330 for (var i = 0; i < frames.length; i++) {
331 var frame = frames[i];
332
333 var extender = this.extenders[frame['header']['identifier']];
334
335 if (extender) {
336 hash = extender(hash, frames[i]);
337 }
338 }
339
340 return hash;
341}
Note: See TracBrowser for help on using the repository browser.