source: gs3-extensions/audioDB/trunk/src/interface/js/similarity-matrix-play.js@ 26291

Last change on this file since 26291 was 26291, checked in by davidb, 12 years ago

files that need to added into the 'web/ext/XX' area to support the new interface elements

File size: 14.9 KB
Line 
1
2// Audio objects
3var baseSong;
4var leftSong;
5var rightSong;
6
7var pannedPlayback = new Audio();
8
9var leftBuffers = [];
10var rightBuffers = [];
11
12var leftStartTimeSecs = 0.0;
13var rightStartTimeSecs = 0.0;
14var leftStartTimeOffset = 0;
15var rightStartTimeOffset = 0;
16
17var playTrackerMode = "stopped";
18
19var startPlayX;
20var startPlayY;
21
22var pannedPlayWidth;
23var pannedPlayHeight;
24
25var prevPlayedX = -1;
26var prevPlayedY = -1;
27
28//var prevPlayedOffset = -1;
29
30var preparingDualAudio = 0;
31
32function resetAudioBuffers()
33{
34 //console.log("Panned audio playback buffers initialized/reset");
35
36 pannedPlayback = new Audio();
37 pannedPlayback.mozSetup(2, baseSong.mozSampleRate);
38
39 leftBuffers = [];
40 rightBuffers = [];
41
42 leftStartTimeSecs = 0.0;
43 rightStartTimeSecs = 0.0;
44 leftStartTimeOffset = 0;
45 rightStartTimeOffset = 0;
46
47 prevPlayedX = -1;
48 prevPlayedY = -1;
49
50 // prevPlayedOffset = -1;
51}
52
53
54
55function dualPlay(evt)
56{
57 var mouse_x = evt.pageX;
58 var mouse_y = evt.pageY;
59
60 // display busy/loading cursor
61 var playTrackerBusy = document.getElementById("playtrackerBusy");
62 playTrackerBusy.setAttribute("style","visibility: visible;");
63 preparingDualAudio = 1;
64
65 var selfSimImg = document.getElementById("selfSimImgId");
66 var imgWidth = selfSimImg.getAttribute("width");
67 var imgHeight = selfSimImg.getAttribute("height") * yScaleSimImg;
68
69 //console.log("image w x h = " + imgWidth +"," + imgHeight);
70
71 var img_x = $("#selfSimImgId").offset().left;
72 var img_y = $("#selfSimImgId").offset().top;
73
74 var x_org = mouse_x - img_x;
75 var y_org = mouse_y - img_y;
76 var adjusted_y_org = imgHeight - y_org;
77
78 //console.log("img (x y) = (" + img_x + "," + img_y + ")");
79 //console.log("mouse (x y) = (" + mouse_x + "," + mouse_y + ")");
80 //console.log("(x y) = (" + x_org + "," + adjusted_y_org + ")");
81
82 startPlayX = x_org;
83 startPlayY = y_org;
84
85 pannedPlayWidth = imgWidth - x_org;
86 pannedPlayHeight = y_org;
87
88 resetAudioBuffers();
89
90 var baseSongSrc="sites/localsite/collect/" + collect +"/import/"+source;
91
92 leftStartTimeSecs = duration * (x_org / imgWidth);
93 rightStartTimeSecs = duration * (adjusted_y_org / imgHeight);
94
95 var sampleMult = baseSong.mozSampleRate * baseSong.mozChannels;
96 leftStartTimeOffset = leftStartTimeSecs * sampleMult;
97 rightStartTimeOffset = rightStartTimeSecs * sampleMult;
98
99 //leftSong.src = baseSongSrc + "#t=" + leftStartTimeSecs + ",";
100 //rightSong.src = baseSongSrc + "#t=" + rightStartTimeSecs + ",";
101
102 leftSong.currentTime = leftStartTimeSecs;
103 leftSong.play();
104
105 rightSong.currentTime = rightStartTimeSecs;
106 rightSong.play();
107
108 // console.log("play tracker mode = " + playTrackerMode);
109 if (togglePlayMode.match("pause")) {
110 // i.e. currently displaying the pause button
111 // stop
112 if (playTrackerMode.match("stopped")) {
113 // => playing through the main play bar
114 soundManager.stopAll();
115 togglePlayVisual(document.getElementById("mainPlayButton"));
116 }
117 }
118
119 if (!playTrackerMode.match("playing")) {
120 togglePlayVisual(document.getElementById("mainPlayButton"));
121 }
122}
123
124
125function playTrackerOn(evt)
126{
127 var playTracker = document.getElementById("playtracker");
128 playTrackerMove(evt);
129 playTracker.setAttribute("style","visibility: visible");
130}
131
132function playTrackerOff(evt)
133{
134 var playTracker = document.getElementById("playtracker");
135 playTracker.setAttribute("style","visibility: hidden");
136}
137
138function updateLeftAndRightTimes(cx,cy)
139{
140 var selfSimImg = document.getElementById("selfSimImgId");
141 var imgWidth = selfSimImg.getAttribute("width");
142 var imgHeight = selfSimImg.getAttribute("height") * yScaleSimImg;
143
144 var adjusted_cy = imgHeight - cy;
145
146 //var mysong = document.getElementById("mysong");
147 //var barWidth = mysong.getElementWidth();
148
149
150 // update L & R times on tracker
151 var currPlayedXInSecs = (cx/imgWidth) * duration;
152 var currPlayedYInSecs = (adjusted_cy/imgHeight) * duration;
153
154 // Deliberately crossed to fit visual playTracker circlea
155
156 var leftTime = document.getElementById("leftTime");
157 var leftText = "R: " + currPlayedXInSecs.toFixed(0) + " secs";
158 // (used to do 1 decimal place)
159
160 leftTextNode = leftTime.childNodes[0];
161 leftTextNode.nodeValue = leftText;
162
163 var rightTime = document.getElementById("rightTime");
164 var rightText = "L: " + currPlayedYInSecs.toFixed(0) + " secs";
165
166 rightTextNode = rightTime.childNodes[0];
167 rightTextNode.nodeValue = rightText;
168
169 // console.log("left text = " + leftText);
170 // console.log("right text = " + rightext);
171}
172
173
174function playTrackerMove(evt)
175{
176 if (!playTrackerMode.match("playing")) {
177 var mouse_x = evt.pageX;
178 var mouse_y = evt.pageY;
179
180 var img_x = $("#selfSimImgId").offset().left;
181 var img_y = $("#selfSimImgId").offset().top;
182
183 var x_org = mouse_x - img_x;
184 var y_org = mouse_y - img_y;
185
186 updateLeftAndRightTimes(x_org,y_org);
187
188 var playTracker = document.getElementById("playtracker");
189 var transform = "translate("+x_org+","+y_org+")";
190 playTracker.setAttribute("transform",transform);
191 }
192
193}
194
195function svgInitSimilarityPlay()
196{
197 var mysong = document.getElementById("mysong");
198 var barWidth = mysong.getElementWidth();
199
200 var baseSongSrc="sites/localsite/collect/" + collect +"/import/"+source;
201
202 baseSong = new Audio();
203 baseSong.src = baseSongSrc;
204 baseSong.control = "control";
205
206 baseSong.addEventListener('MozAudioAvailable', audioAvailable, false);
207 baseSong.addEventListener('loadedmetadata', loadedMetadata, false);
208
209 //leftSong = new Audio();
210 leftSong = document.getElementById("leftsong");
211 leftSong.addEventListener('MozAudioAvailable', audioAvailableLeft, false);
212 leftSong.addEventListener('loadedmetadata', loadedMetadataLeft, false);
213
214 //rightSong = new Audio();
215 rightSong = document.getElementById("rightsong")
216 rightSong.addEventListener('MozAudioAvailable', audioAvailableRight, false);
217 rightSong.addEventListener('loadedmetadata', loadedMetadataRight, false);
218
219
220 // Set up self similarity image
221
222 var selfSimImgSrc="sites/localsite/collect/" + collect +"/bordered/line-interlaced/"+self_sim_png;
223 //console.log("self sim img = " + selfSimImgSrc);
224
225 var simPlayLine = document.getElementById("simPlayLineGroup");
226
227 simPlayLine.setAttributeNS(SVG_NS,"transform","scale(1.0,"+yScaleSimImg+")");
228
229 var selfSimImg = document.createElementNS(SVG_NS,"image");
230 selfSimImg.setAttributeNS(XLINK_NS, "xlink:href", selfSimImgSrc);
231
232 var selfSimImgWidth = barWidth;
233 var selfSimImgHeight = barWidth * (815.0 / 776.0);
234
235 selfSimImg.setAttribute("x",0);
236 selfSimImg.setAttribute("y",0);
237 selfSimImg.setAttribute("id","selfSimImgId");
238 selfSimImg.setAttribute("width",barWidth);
239 selfSimImg.setAttribute("height",selfSimImgHeight);
240 selfSimImg.setAttribute("onclick","dualPlay(evt)");
241 selfSimImg.setAttribute("onmousemove","playTrackerMove(evt)");
242 selfSimImg.setAttribute("onmouseover","playTrackerOn(evt)");
243 //selfSimImg.setAttribute("onmouseout","playTrackerOff(evt)");
244
245 simPlayLine.appendChild(selfSimImg);
246
247 var svgSimilarityPlay = document.getElementById("svgSimilarityPlay");
248 svgSimilarityPlay.setAttribute("height",0 + selfSimImgHeight * yScaleSimImg); // used to be 30 +
249
250
251 // Firefox doesn't seem to like this being initialized statically
252 // in the HTML page generate, so add it dynamically here
253 var playTrackerBusy = document.getElementById("playtrackerBusy");
254 playTrackerBusy.setAttributeNS(XLINK_NS,"xlink:href",
255 "ext/audioDB/icons/wait30trans.gif");
256
257}
258
259
260
261
262function loadedMetadata() {
263 // Mute baseSong audio.
264 baseSong.volume = 0;
265
266 // Set up a pannedPlayback for baseSong to routed through
267 // console.log("num channels = " + baseSong.mozChannels);
268
269 pannedPlayback.mozSetup(2, baseSong.mozSampleRate);
270}
271
272
273function loadedMetadataLeft() {
274 // Mute baseSong audio.
275 leftSong.volume = 0;
276
277 //leftSong.currentTime = leftStartTimeSecs;
278 //leftSong.play();
279 //console.log("left start time = " + leftStartTimeSecs);
280}
281
282
283function loadedMetadataRight() {
284 // Mute baseSong audio.
285 rightSong.volume = 0;
286
287 //rightSong.currentTime = rightStartTimeSecs;
288 //rightSong.play();
289 //console.log("right start time = " + rightStartTimeSecs);
290
291}
292
293function audioAvailable(event) {
294 // Write the current framebuffer
295 alert("audioAvailable() should no longer be called");
296 var frameBuffer = event.frameBuffer; // frameBuffer is Float32Array
297 //writeAudio(frameBuffer);
298}
299
300function audioAvailableLeft(event)
301{
302 // Write the current framebuffer
303 var frameBuffer = event.frameBuffer;
304 writeAudio(frameBuffer,"left");
305
306}
307
308function audioAvailableRight(event)
309{
310 // Write the current framebuffer
311 var frameBuffer = event.frameBuffer;
312 writeAudio(frameBuffer,"right");
313}
314
315
316
317
318function activeAudioBuffer(audioBuffer,currentFullBufferSize,startTime)
319{
320 var buffer;
321 if (currentFullBufferSize < startTime) {
322 // active audio starts at offset within this segment of audioBuffer
323
324 var position = startTime - currentFullBufferSize;
325 buffer = audioBuffer.subarray(position);
326 }
327 else {
328 buffer = audioBuffer;
329 }
330 return buffer;
331}
332
333function panLeftEffect(buffer,s,panned_buffer,d)
334{
335 panned_buffer[d] = buffer[s];
336 if ((d+1) < panned_buffer.length) {
337 panned_buffer[d+1] = 0;
338 }
339}
340
341function panRightEffect(buffer,s,panned_buffer,d)
342{
343 panned_buffer[d] = 0;
344 if ((d+1) < panned_buffer.length) {
345 panned_buffer[d+1] = buffer[s];
346 }
347}
348
349function panAudioBuffersHead(buffer,position,panEffect)
350{
351 var remaining_len = buffer.length - position;
352 var panned_buffer;
353 if (baseSong.mozChannels == 1) {
354 panned_buffer = new Float32Array(remaining_len * 2);
355
356 var d=0;
357 for (var s=position; s < buffer.length; s++) {
358 panEffect(buffer,s,panned_buffer,d);
359 d += 2;
360 }
361 }
362 else {
363 // assume stereo
364 panned_buffer = new Float32Array(remaining_len);
365
366 var d=0;
367 for (var s=position; s < buffer.length; s+=2) {
368 panEffect(buffer,s,panned_buffer,d);
369 d += 2;
370 }
371 }
372
373 return panned_buffer;
374}
375
376function mergeLeftAndRightPan(leftPannedBuffer,rightPannedBuffer)
377{
378 // left and right buffers guaranteed to be stereo samples
379
380 // Deliberately crossed to fit visual playTracker circlea
381
382 var leftLen = leftPannedBuffer.length;
383 var rightLen = rightPannedBuffer.length;
384 var maxLen = Math.max(leftLen,rightLen);
385
386 var pannedBuffer = new Float32Array(maxLen);
387
388 for (i=0; i < maxLen; i+=2) {
389
390 if (i < leftLen-1) {
391 // i+1 actually right pos
392 pannedBuffer[i+1] = leftPannedBuffer[i];
393 }
394 else {
395 pannedBuffer[i+1] = 0;
396 }
397
398 if (i < rightLen-1) {
399 // actually left pos
400 pannedBuffer[i] = rightPannedBuffer[i+1];
401 }
402 else {
403 pannedBuffer[i] = 0;
404 }
405 }
406
407 return pannedBuffer;
408
409}
410
411function writeAudio(audioBuffer,channel)
412{
413
414 var mysong = document.getElementById("mysong");
415 var barWidth = mysong.getElementWidth();
416
417 // audioBuffer is Float32Array
418 var audioBufferLen = audioBuffer.length;
419
420 if (channel.match("left")) {
421 //var leftBuffer = activeAudioBuffer(audioBuffer,totalFullBufferSize,leftStartTimeOffset);
422 leftBuffers.push({buffer: audioBuffer, position: 0});
423 }
424
425 if (channel.match("right")) {
426 //var rightBuffer = activeAudioBuffer(audioBuffer,totalFullBufferSize,rightStartTimeOffset);
427 rightBuffers.push({buffer: audioBuffer, position: 0});
428 }
429
430
431 // If there's buffered data in both left and right buffers,
432 // then it's time to play something
433
434 var currPlayedX = null;
435 var currPlayedY = null;
436
437 while ((leftBuffers.length > 0) && (rightBuffers.length > 0)) {
438
439 if (preparingDualAudio) {
440 var playTrackerBusy= document.getElementById("playtrackerBusy");
441 playTrackerBusy.setAttribute("style","visibility: hidden;");
442 preparingDualAudio = 0;
443 }
444
445
446 var leftBuffer = leftBuffers[0].buffer;
447 var leftBufferPos = leftBuffers[0].position;
448 var leftPannedBuffer = panAudioBuffersHead(leftBuffer,leftBufferPos,panLeftEffect);
449
450 var rightBuffer = rightBuffers[0].buffer;
451 var rightBufferPos = rightBuffers[0].position;
452 var rightPannedBuffer = panAudioBuffersHead(rightBuffer,rightBufferPos,panRightEffect);
453
454 var pannedBuffer = mergeLeftAndRightPan(leftPannedBuffer,rightPannedBuffer);
455
456 // Send something to be played
457 var written = pannedPlayback.mozWriteAudio(pannedBuffer);
458
459 // get current play pos, and plot on selfSimImg
460 var currentPlayedOffset = pannedPlayback.mozCurrentSampleOffset();
461
462 var sampleRate = pannedPlayback.mozSampleRate;
463 var numChannels = pannedPlayback.mozChannels;
464
465 var pannedDurationLeft = duration - leftStartTimeSecs;
466 var pannedDurationRight = duration - rightStartTimeSecs;
467
468 var totalNumSamplesLeft = sampleRate * numChannels * pannedDurationLeft;
469 var totalNumSamplesRight = sampleRate * numChannels * pannedDurationRight;
470
471 var currentPlayedPercLeft = currentPlayedOffset/totalNumSamplesLeft;
472 var currentPlayedPercRight = currentPlayedOffset/totalNumSamplesRight;
473
474
475 var currPlayedXPrecise = startPlayX + (currentPlayedPercLeft*pannedPlayWidth);
476 var currPlayedYPrecise = startPlayY - (currentPlayedPercRight*pannedPlayHeight);
477 currPlayedX = Math.round(currPlayedXPrecise);
478 currPlayedY = Math.round(currPlayedYPrecise);
479
480
481 if ((currPlayedX != prevPlayedX) || (currPlayedY != prevPlayedY)) {
482
483 updateLeftAndRightTimes(currPlayedXPrecise,currPlayedYPrecise);
484
485 var playTracker = document.getElementById("playtracker");
486 var transform = "translate("+currPlayedX+","+currPlayedY+")";
487 playTracker.setAttribute("transform",transform);
488
489 if ((prevPlayedX == -1) && (prevPlayedY == -1)) {
490 // notice the first time this happens
491 playTracker.setAttribute("style","visibility: visible");
492 playTrackerMode = "playing";
493 }
494
495 prevPlayedX = currPlayedX;
496 prevPlayedY = currPlayedY;
497 }
498
499 // console.log("currently playing = " + currentPlayedSecs);
500
501
502 // If all data wasn't written, keep it in the buffers:
503 var doBreak = false;
504
505 if (leftBufferPos + written < leftBuffer.length) {
506 leftBuffers[0].position = leftBufferPos + written;
507 doBreak = true;
508 }
509 else {
510 leftBuffers.shift();
511 }
512
513 if (rightBufferPos + written < rightBuffer.length) {
514 rightBuffers[0].position = rightBufferPos + written;
515 doBreak = true;
516 }
517 else {
518 rightBuffers.shift();
519 }
520
521 if (doBreak) {
522 break;
523 }
524 }
525
526 var currentPlayedOffset = pannedPlayback.mozCurrentSampleOffset();
527
528 //if (currentPlayedOffset == prevPlayedOffset) {
529 // Nothing more is playing
530
531 var exceededX = ((currPlayedX != null) && (currPlayedX>barWidth));
532 var exceededY = ((currPlayedY != null) && (currPlayedY<0));
533
534 if ((exceededX || exceededY) && (!playTrackerMode.match("stopped"))) {
535
536 // console.log("detected stop condition");
537
538 // readed edge of play area
539 playTrackerMode = "stopped";
540 togglePlayVisual(document.getElementById("mainPlayButton"));
541 playTrackerOff(null);
542
543 //prevPlayedOffset = -1;
544 }
545 else {
546 //prevPlayedOffset = currentPlayedOffset;
547 }
548
549}
Note: See TracBrowser for help on using the repository browser.