source: gs3-extensions/web-audio/trunk/js-mad/script/main-jsmad.js@ 28548

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

Changes after developing the demo for the SMAM-2013 keynote talk

File size: 6.5 KB
Line 
1
2var JsMadProcessing = function(audio_id,active_workflow) {
3
4 this.audio_id = audio_id;
5 this.active_workflow = active_workflow || null;
6
7 var url = $('#'+audio_id).attr("href");
8 console.info("JsMadProcessing::JsMadProcessing() retrieving over AJAX: " + url);
9
10 var stream = new Mad.AjaxStream(url);
11
12 var that = this;
13
14 var channels = 2; // stereo
15 var rate = 44100; // 44.1 Khz
16 //var rate = 48000; // 44.1 Khz
17 //var bufsize = 65536 * 4096;
18 //var bufsize = 65536 * 1024;
19 //var bufsize = 2048;
20 var bufsize = 1024 * 8;
21
22 //this.dev = Sink(function(buffer) {that.refill(buffer)}, channels, bufsize, rate);
23 //console.log("*** got sample rate of: " + this.dev.sampleRate);
24
25
26 this.playBufferStore = new Array();
27
28/*
29 // default is to operate as fast as possible
30 if (BrowserDetect.browser == "Firefox") {
31 this.speedup_batch_limit = 100;
32 this.speedup_pause = 0;
33 }
34 else {
35 // e.g. Chrome
36 // => the following values played more nicely with letting DSP playback operate straightaway
37 // i.e. when jsmad is still working its way through the frames
38
39 this.speedup_batch_limit = 10;
40 this.speedup_pause = 2;
41
42 //speedup_batch_limit = 100;
43 //speedup_pause = 0;
44
45 //console.log("*** Running JsMadProcessing with: batch limit = " + speedup_batch_limit
46 // + ", pause = " + this.speedup_pause + " msecs");
47 }
48*/
49
50 // Assume slow, unless the user explicitly activates "speed up"
51 this.speedup_batch_limit = 10;
52 this.speedup_pause = 1000;
53
54 this.processing_finished = false;
55
56 stream.requestAbsolute(1 * 1024, function() { that.streamCallback(stream) });
57
58}
59
60JsMadProcessing.prototype.setSpeedupParams = function(new_batch_limit,new_pause) {
61 this.speedup_batch_limit = new_batch_limit;
62 this.speedup_pause = new_pause;
63}
64
65
66JsMadProcessing.prototype.processingFinished = function() {
67 return this.processing_finished;
68}
69
70JsMadProcessing.prototype.streamCallback = function(stream) {
71
72
73 var mp3 = new Mad.MP3File(stream);
74 var mpeg = mp3.getMpegStream();
75
76 //var howmuch = 10000;
77 var ss1 = Date.now();
78
79 var synth = new Mad.Synth();
80 var frame = new Mad.Frame();
81
82 frame = Mad.Frame.decode(frame, mpeg); // decode first frame to establish num channels and samplerate
83 var num_channels = frame.header.nchannels();
84 var sampleRate = frame.header.samplerate;
85
86 console.info("JsMadProcessing::streamCallback() decoding URL retrieved MP3 with " + num_channels + " channels, samplerate = " + sampleRate);
87
88
89 var that = this;
90
91 var numSamples = 0;
92
93 synth.frame(frame);
94 var prev_synth_frame_len = synth.pcm.samples[0].length;
95 console.info("JsMadProcesing.streamCallback(): synth frame length (initial frame) = " + prev_synth_frame_len);
96
97 var i=1; // already processed one frame
98
99 var overflowBuffer = null;
100
101 console.log("*** main-jsmad.js::stream_callback(): hardwiring workflow buffer size to 2048");
102
103 var $acc_proc_status = $('#accProcStatus') || null;
104
105
106 (function() {
107
108 var more_frames = 1;
109 try {
110
111 var speedup_i = 0;
112
113 while (speedup_i < that.speedup_batch_limit) { // Decode 100 frames at a time, before setTimeout break
114
115 frame = Mad.Frame.decode(frame, mpeg);
116 synth.frame(frame);
117
118 var synth_frame_len = synth.pcm.samples[0].length;
119
120 var playBuffer = null;
121 var pbp = 0; // pbp = play buffer pos
122
123 if (overflowBuffer != null) {
124 playBuffer = new Float32Array(overflowBuffer.length+(synth_frame_len*num_channels));
125 playBuffer.set(overflowBuffer);
126 pbp = overflowBuffer.length;
127 overflowBuffer = null;
128 }
129 else {
130 playBuffer = new Float32Array(synth_frame_len*num_channels);
131 pbp = 0;
132 }
133
134
135 for (var sfp=0; sfp<synth_frame_len; sfp++) {
136 for (var c=0; c<num_channels; c++) {
137 playBuffer[pbp] = synth.pcm.samples[c][sfp];
138 pbp++;
139 }
140 }
141
142 numSamples += synth_frame_len;
143
144 // uncomment the following line if you want to hear speeded-up playback as it works through the audio file
145 //var written = pannedPlayback.mozWriteAudio(playBuffer);
146
147
148 if (synth_frame_len != prev_synth_frame_len) {
149 console.log("*** new synth frame len (frame num = " + i + "): len = " + synth_frame_len);
150 prev_synth_frame_len = synth_frame_len;
151 }
152
153 if (that.active_workflow != null) {
154 // Send the data into the Javascript DSP workflow
155
156 // Note: workflow geared to 2048 samples at a time
157
158 var wi = 0;
159
160 var playBufferLen = playBuffer.length;
161 while (wi<playBuffer.length) {
162
163 if (wi+2048<=playBufferLen) {
164 var workflowBuffer = playBuffer.subarray(wi,wi+2048);
165 that.active_workflow.pumpDataHead("rawInput",workflowBuffer);
166 that.playBufferStore.push(workflowBuffer);
167 }
168 else {
169 // tail end => set up in overflow buffer
170 var workflowBufferTail = playBuffer.subarray(wi);
171
172 overflowBuffer = new Float32Array(playBufferLen-wi);
173 overflowBuffer.set(workflowBufferTail);
174
175 }
176 wi += 2048;
177 }
178
179
180 // Old approach: pump data in, in frames that are set by webAudioContext
181 //that.active_workflow.pumpDataHead("rawInput",playBuffer);
182 }
183
184 speedup_i++;
185 i++;
186
187
188 if ((i%10)==0) {
189 if ($acc_proc_status != null) {
190 $acc_proc_status.text(" (decoded " + i + " frames)");
191 }
192 }
193
194 }
195
196 }
197 catch(err) {
198 if (err == "Header decoding failed") {
199 console.info("JsMadProcessing::streamCallack() decoded " + i + " frames");
200 $acc_proc_status.text(" (done)");
201 that.processing_finished = true;
202 }
203 else {
204 console.error(err);
205 }
206 more_frames = 0;
207 }
208
209 if (more_frames) {
210 setTimeout(arguments.callee,that.speedup_pause); // even a delay of '0' gives the browser thread a break
211 }
212 else {
213 var ss2 = Date.now();
214
215 var song_duration = numSamples / sampleRate;
216 var speedup_duration = (ss2 - ss1)/1000;
217
218 var speedup_factor = song_duration / speedup_duration;
219 //console.log("Computed song duration: " + song_duration + " secs");
220 console.info("JsMad processing done in " + speedup_duration + " secs (a speed factor of " + speedup_factor + ")");
221
222 $acc_proc_status.text(" (done)");
223 that.processing_finished = true;
224
225 }
226
227 })();
228
229}
230
231
232JsMadProcessing.prototype.refill = function(buffer)
233{
234 console.log("refill called, asking for size = " + buffer.length);
235
236 var buffer_len = buffer.length;
237 var buffer_pos = 0;
238
239 while ((this.playBufferStore.length>0) && (buffer_pos<buffer_len)) {
240
241 var playBuffer = this.playBufferStore.shift();
242 buffer.set(playBuffer,buffer_pos);
243
244 buffer_pos += playBuffer.length;
245 }
246
247
248}
Note: See TracBrowser for help on using the repository browser.