source: gs3-extensions/web-audio/trunk/js-mad/script/frame.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: 12.7 KB
Line 
1
2var bitrate_table /* [5][15] */ = [
3/* MPEG-1 */
4[ 0, 32000, 64000, 96000, 128000, 160000, 192000, 224000, /* Layer I */
5 256000, 288000, 320000, 352000, 384000, 416000, 448000 ],
6 [ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer II */
7 128000, 160000, 192000, 224000, 256000, 320000, 384000 ],
8 [ 0, 32000, 40000, 48000, 56000, 64000, 80000, 96000, /* Layer III */
9 112000, 128000, 160000, 192000, 224000, 256000, 320000 ],
10
11 /* MPEG-2 LSF */
12 [ 0, 32000, 48000, 56000, 64000, 80000, 96000, 112000, /* Layer I */
13 128000, 144000, 160000, 176000, 192000, 224000, 256000 ],
14 [ 0, 8000, 16000, 24000, 32000, 40000, 48000, 56000, /* Layers */
15 64000, 80000, 96000, 112000, 128000, 144000, 160000 ] /* II & III */
16 ];
17
18 var samplerate_table /* [3] */ = [ 44100, 48000, 32000 ];
19
20 var decoder_table = [
21 function() { console.log("Layer I decoding is not implemented!"); },
22 function() { console.log("Layer II decoding is not implemented!"); },
23 Mad.layer_III
24 ];
25
26 Mad.Layer = {
27I: 1,
28 II: 2,
29 III: 3
30 };
31
32Mad.Mode = {
33SINGLE_CHANNEL : 0,
34 DUAL_CHANNEL : 1, /* dual channel */
35 JOINT_STEREO : 2, /* joint (MS/intensity) stereo */
36 STEREO : 3 /* normal LR stereo */
37};
38
39Mad.Emphasis = {
40NONE : 0, /* no emphasis */
41 _50_15_US : 1, /* 50/15 microseconds emphasis */
42 CCITT_J_17 : 3, /* CCITT J.17 emphasis */
43 RESERVED : 2 /* unknown emphasis */
44};
45
46Mad.Header = function () {
47 this.layer = 0; /* audio layer (1, 2, or 3) */
48 this.mode = 0; /* channel mode (see above) */
49 this.mode_extension = 0; /* additional mode info */
50 this.emphasis = 0; /* de-emphasis to use (see above) */
51
52 this.bitrate = 0; /* stream bitrate (bps) */
53 this.samplerate = 0; /* sampling frequency (Hz) */
54
55 this.crc_check = 0; /* frame CRC accumulator */
56 this.crc_target = 0; /* final target CRC checksum */
57
58 this.flags = 0; /* flags (see below) */
59 this.private_bits = 0; /* private bits (see below) */
60
61 //this.duration = mad_timer_zero; /* audio playing time of frame */
62};
63
64Mad.Header.prototype.nchannels = function () {
65 return this.mode === 0 ? 1 : 2;
66}
67
68Mad.Header.prototype.nbsamples = function() {
69 return (this.layer === Mad.Layer.I ? 12 :
70 ((this.layer === Mad.Layer.III && (this.flags & Mad.Flag.LSF_EXT)) ? 18 : 36));
71}
72
73/* libmad's decode_header */
74Mad.Header.actually_decode = function(stream) {
75 var header = new Mad.Header();
76
77 header.flags = 0;
78 header.private_bits = 0;
79
80 /* header() */
81
82 /* syncword */
83 stream.ptr.skip(11);
84
85 /* MPEG 2.5 indicator (really part of syncword) */
86 if (stream.ptr.read(1) === 0) {
87 header.flags |= Mad.Flag.MPEG_2_5_EXT;
88 }
89
90 /* ID */
91 if (stream.ptr.read(1) === 0) {
92 header.flags |= Mad.Flag.LSF_EXT;
93 } else if (header.flags & Mad.Flag.MPEG_2_5_EXT) {
94 stream.error = Mad.Error.LOSTSYNC;
95 return null;
96 }
97
98 /* layer */
99 header.layer = 4 - stream.ptr.read(2);
100
101 if (header.layer === 4) {
102 stream.error = Mad.Error.BADLAYER;
103 return header;
104 }
105
106 /* protection_bit */
107 if (stream.ptr.read(1) === 0) {
108 header.flags |= Mad.Flag.PROTECTION;
109 // TODO: crc
110 //header.crc_check = mad_bit_crc(stream.ptr, 16, 0xffff);
111 stream.ptr.skip(16);
112 }
113
114 /* bitrate_index */
115 var index = stream.ptr.read(4);
116 if (index === 15) {
117 stream.error = Mad.Error.BADBITRATE;
118 return header;
119 }
120
121 if (header.flags & Mad.Flag.LSF_EXT) {
122 header.bitrate = bitrate_table[3 + (header.layer >> 1)][index];
123 } else {
124 header.bitrate = bitrate_table[header.layer - 1][index];
125 }
126
127 /* sampling_frequency */
128 index = stream.ptr.read(2);
129
130 if (index === 3) {
131 stream.error = Mad.Error.BADSAMPLERATE;
132 return header;
133 }
134
135 header.samplerate = samplerate_table[index];
136
137 if (header.flags & Mad.Flag.LSF_EXT) {
138 header.samplerate /= 2;
139
140 if (header.flags & Mad.Flag.MPEG_2_5_EXT)
141 header.samplerate /= 2;
142 }
143
144 /* padding_bit */
145 if (stream.ptr.read(1))
146 header.flags |= Mad.Flag.PADDING;
147
148 /* private_bit */
149 if (stream.ptr.read(1))
150 header.private_bits |= Mad.Private.HEADER;
151
152 /* mode */
153 header.mode = 3 - stream.ptr.read(2);
154
155 /* mode_extension */
156 header.mode_extension = stream.ptr.read(2);
157
158 /* copyright */
159 if (stream.ptr.read(1))
160 header.flags |= Mad.Flag.COPYRIGHT;
161
162 /* original/copy */
163 if (stream.ptr.read(1))
164 header.flags |= Mad.Flag.ORIGINAL;
165
166 /* emphasis */
167 header.emphasis = stream.ptr.read(2);
168
169 /* error_check() */
170
171 /* crc_check */
172 if (header.flags & Mad.Flag.PROTECTION)
173 header.crc_target = stream.ptr.read(16);
174
175 return header;
176}
177
178/* libmad's mad_header_decode */
179Mad.Header.decode = function(stream) {
180 var header = null;
181
182 // those are actually pointers. javascript powa.
183 var ptr = stream.next_frame;
184 var end = stream.bufend;
185 var pad_slot = 0;
186 var N = 0;
187
188 /* stream skip */
189 if (stream.skiplen) {
190 if (!stream.sync)
191 ptr = stream.this_frame;
192
193 if (end - ptr < stream.skiplen) {
194 stream.skiplen -= end - ptr;
195 stream.next_frame = end;
196
197 stream.error = Mad.Error.BUFLEN;
198 return null;
199 }
200
201 ptr += stream.skiplen;
202 stream.skiplen = 0;
203
204 stream.sync = 1;
205 }
206
207 // emulating goto in JS, yay! this was a 'sync:' label
208 var syncing = true;
209
210 while(syncing) {
211 syncing = false;
212
213 /* synchronize */
214 try {
215 if (stream.sync) {
216 if (end - ptr < Mad.BUFFER_GUARD) {
217 stream.next_frame = ptr;
218
219 stream.error = Mad.Error.BUFLEN;
220 return null;
221 } else if (!(stream.getU8(ptr) === 0xff && (stream.getU8(ptr + 1) & 0xe0) === 0xe0)) {
222 /* mark point where frame sync word was expected */
223 stream.this_frame = ptr;
224 stream.next_frame = ptr + 1;
225
226 stream.error = Mad.Error.LOSTSYNC;
227 return null;
228 }
229 } else {
230 stream.ptr = new Mad.Bit(stream.stream, ptr);
231
232 if (stream.doSync() === -1) {
233 if (end - stream.next_frame >= Mad.BUFFER_GUARD)
234 stream.next_frame = end - Mad.BUFFER_GUARD;
235 stream.error = Mad.Error.BUFLEN;
236 return null;
237 }
238
239 ptr = stream.ptr.nextbyte();
240 }
241 } catch (e) {
242 console.log("Synchronization error: " + e);
243
244 stream.error = Mad.Error.BUFLEN;
245
246 return null;
247 }
248
249 /* begin processing */
250 stream.this_frame = ptr;
251 stream.next_frame = ptr + 1; /* possibly bogus sync word */
252
253 stream.ptr = new Mad.Bit(stream.stream, stream.this_frame);
254
255 header = Mad.Header.actually_decode(stream);
256 if(header === null) return null; // well Duh^2
257
258 //console.log("=============== Decoding layer " + header.layer + " audio mode " +
259 // header.mode + " with " + header.bitrate +
260 // " bps and a samplerate of " + header.samplerate);
261
262 /* calculate frame duration */
263 //mad_timer_set(&header.duration, 0, 32 * MAD_NSBSAMPLES(header), header.samplerate);
264
265 /* calculate free bit rate */
266 if (header.bitrate === 0) {
267 console.log("Uh oh, a free bitrate stream. We're fucked.");
268 stream.error = Mad.Error.BADDATAPTR; // best guess
269 return null;
270
271 // if ((stream.freerate === 0 || !stream.sync ||
272 // (header.layer === Mad.Layer.III && stream.freerate > 640000)) &&
273 // free_bitrate(stream, header) === -1)
274 // return null;
275 //
276 // header.bitrate = stream.freerate;
277 // header.flags |= Mad.Flag.FREEFORMAT;
278 }
279
280 /* calculate beginning of next frame */
281 pad_slot = (header.flags & Mad.Flag.PADDING) ? 1 : 0;
282
283 if (header.layer === Mad.Layer.I) {
284 N = (((12 * header.bitrate / header.samplerate) << 0) + pad_slot) * 4;
285 } else {
286 var slots_per_frame = (header.layer === Mad.Layer.III &&
287 (header.flags & Mad.Flag.LSF_EXT)) ? 72 : 144;
288 //console.log("slots_per_frame = " + slots_per_frame + ", bitrate = " + header.bitrate + ", samplerate = " + header.samplerate);
289
290 N = ((slots_per_frame * header.bitrate / header.samplerate) << 0) + pad_slot;
291 }
292
293
294 /* verify there is enough data left in buffer to decode this frame */
295 if (N + Mad.BUFFER_GUARD > end - stream.this_frame) {
296 stream.next_frame = stream.this_frame;
297
298 stream.error = Mad.Error.BUFLEN;
299 return null;
300 }
301
302 stream.next_frame = stream.this_frame + N;
303
304 // console.log("N = " + N + ", pad_slot = " + pad_slot + ", next_frame = " + stream.next_frame);
305
306 if (!stream.sync) {
307 /* check that a valid frame header follows this frame */
308 ptr = stream.next_frame;
309 if (!(stream.getU8(ptr) === 0xff && (stream.getU8(ptr + 1) & 0xe0) === 0xe0)) {
310 ptr = stream.next_frame = stream.this_frame + 1;
311
312 // emulating 'goto sync'
313 syncing = true;
314 continue;
315 }
316 stream.sync = 1;
317 }
318 } // end of goto emulation (label 'sync')
319
320 header.flags |= Mad.Flag.INCOMPLETE;
321 return header;
322}
323
324Mad.Frame = function () {
325 this.header = new Mad.Header(); /* MPEG audio header */
326
327 this.options = 0; /* decoding options (from stream) */
328
329 // sbsample[2][36][32]
330 this.sbsample = []; /* synthesis subband filter samples */
331 for(var ch = 0; ch < 2; ch++) {
332 this.sbsample[ch] = [];
333 for(var grp = 0; grp < 36; grp++) {
334 // this.sbsample[ch][grp] = new Float64Array(new ArrayBuffer(8 * 32));
335 this.sbsample[ch][grp] = [];
336 for(var i = 0; i < 32; i++) {
337 this.sbsample[ch][grp][i] = 0;
338 }
339 }
340 }
341
342 // overlap[2][32][18]
343 this.overlap = []; /* Layer III block overlap data */
344 for(var ch = 0; ch < 2; ch++) {
345 this.overlap[ch] = [];
346 for(var sb = 0; sb < 32; sb++) {
347 // this.overlap[ch][sb] = new Float64Array(new ArrayBuffer(8 * 18));
348 this.overlap[ch][sb] = [];
349 for(var i = 0; i < 18; i++) {
350 this.overlap[ch][sb][i] = 0;
351 }
352 }
353 }
354};
355
356Mad.Frame.decode = function(frame, stream) {
357 frame.options = stream.options;
358
359 /* header() */
360 /* error_check() */
361
362 if (!(frame.header.flags & Mad.Flag.INCOMPLETE)) {
363 frame.header = Mad.Header.decode(stream);
364 if(frame.header === null) {
365 // something went wrong
366 throw 'Header decoding failed';
367 }
368 }
369
370 frame.header.flags &= ~Mad.Flag.INCOMPLETE;
371
372 if (decoder_table[frame.header.layer - 1](stream, frame) === -1) {
373 if (!Mad.recoverable(stream.error)) {
374 stream.next_frame = stream.this_frame;
375 }
376 throw 'Decoder table error';
377 }
378
379 return frame;
380};
381
382Mad.sbsampleIndex = function (i, j, k) {
383 return i * 36 * 32 + j * 32 + k;
384};
385
386Mad.overlapIndex = function (i, j, k) {
387 return i * 32 * 18 + j * 18 + k;
388};
389
390Mad.Flag = {
391NPRIVATE_III : 0x0007, /* number of Layer III private bits */
392 INCOMPLETE : 0x0008, /* header but not data is decoded */
393
394 PROTECTION : 0x0010, /* frame has CRC protection */
395 COPYRIGHT : 0x0020, /* frame is copyright */
396 ORIGINAL : 0x0040, /* frame is original (else copy) */
397 PADDING : 0x0080, /* frame has additional slot */
398
399 I_STEREO : 0x0100, /* uses intensity joint stereo */
400 MS_STEREO : 0x0200, /* uses middle/side joint stereo */
401 FREEFORMAT : 0x0400, /* uses free format bitrate */
402
403 LSF_EXT : 0x1000, /* lower sampling freq. extension */
404 MC_EXT : 0x2000, /* multichannel audio extension */
405 MPEG_2_5_EXT : 0x4000 /* MPEG 2.5 (unofficial) extension */
406};
407
408Mad.Private = {
409HEADER : 0x0100, /* header private bit */
410 III : 0x001f /* Layer III private bits (up to 5) */
411};
Note: See TracBrowser for help on using the repository browser.