PageSourceSearch

https://ninbot.com/nb-mtrack.js

js ninbot.com collected 2026-10-04 01:36:52 UTC 57,654 bytes, 1,830 lines download raw bytes

1var app = angular.module('nb-mtrack', [])
2.directive('mtmeter', function() {
3	 return {
4	      restrict: 'AE',
5	      scope: {   src: '@',
6	      },
7	      template: '<div><canvas style="width:150px;height:48px; background-color:#ca3; border-radius:5px;" ></canvas></div>',
8	      link: function(scope, element, attrs) {
9console.log(" METER DIRECTIVE") ;
10		    scope.canvas = element.find('canvas')[0];
11		    scope.context = scope.canvas.getContext('2d');
12	     	    scope.canvas.width = scope.canvas.clientWidth;
13	     	    scope.canvas.height = scope.canvas.clientHeight;
14		    
15		    scope.$watch('src', function(newValue) {
16			let c = scope.canvas;
17		     	let f = newValue;	
18	
19 			var ctx = c.getContext("2d");
20                	let wid = c.width;
21                	let hei = c.height;
22                	ctx.width = wid;
23                	ctx.hei = hei;
24                	ctx.beginPath();
25                	ctx.rect(0, 0,  wid, hei);
26                	ctx.fillStyle = "#222";
27                	ctx.fill();
28
29                	ctx.beginPath();
30                	ctx.rect(0, 0, f * wid, hei);
31                	ctx.fillStyle = "#090";
32                	ctx.fill();
33/*
34			scope.context.fillStyle = '#000';
35			scope.context.fillRect(0, 0, scope.canvas.width, scope.canvas.height);
36			scope.context.fillStyle = "#0A0";
37			var y1 = 10;
38			var hei = 12;
39			var y3 = scope.canvas.height / 2;;
40			var y2 = scope.canvas.height - 10;
41			var x = newValue / 100 * (scope.canvas.width - 20);
42			scope.context.fillRect(5, y1, x, hei);
43			scope.context.fillRect(5, y1 + hei + 5, x, hei);
44			scope.context.lineStyle = "#000";
45			for( var ii = 0; ii < 20; ii++) {
46			   var x = 5 + (scope.canvas.width / 20 * ii);
47			   scope.context.beginPath();
48			   scope.context.moveTo(x, 0);
49			   scope.context.lineTo(x, scope.canvas.height);
50			   scope.context.stroke();
51			}	   
52*/
53
54			
55			//console.log("SRC CHANGED " + newValue);
56		    });
57
58
59
60
61		}
62	  };
63	})
64.directive('mt_meter', function() {
65    return {
66        restrict: 'E',
67	replace: 'true',
68	scope: {
69	    level:'@'
70	},
71        template:"<div>Text Text<canvas></canvas></div>",
72	controller: function( scope ) {
73	},
74	link: function(scope, element, attrs) {
75             scope.$watch('level', function(val) {
76	     });
77	}
78	
79    }
80})
81.directive('mt_timeline', function() {
82    return {
83	scope: {
84	    level:"@level"
85	},
86        template:"<canvas></canvas>",
87	controller: function( scope ) {
88	}
89    }
90})
91.directive('mtrack', function() {
92  return {
93    controller: "nb-mtrack",
94    templateUrl: "template-mtrack.html"
95  };
96})
97.controller('nb-mtrack', function( $scope, $http, $sce, $window, $location) {
98     $scope.mtrack_mixer = {};
99     $scope.mtrack_audio = {};
100     $scope.mtrack_group = function()
101     {
102	if (!$scope.user.groups) return(0);
103	return ($scope.user.groups.includes("mtrack"));
104
105     }
106     //////////////////////////// RADIO
107     $scope.mtrack_radio_queue = [];
108     $scope.mtrack_radio_ready_queue = [];
109     $scope.mtrack_radio_context = null;
110     $scope.mtrack_radio_model = {};
111  
112     // Called from Player Radio Entry 
113     $scope.mtrack_radio = function( s) 
114     {  	
115        $scope.user_menu_select_bytag("mtrack", "radio");
116	console.log("Radio playing is currently set to " + $scope.mtrack_radio_playing);
117
118	if ($scope.mtrack_radio_playing) {
119     	     $scope.mtrack_radio_stop();
120	}
121
122	$scope.mtrack_radio_server = s;
123        $scope.mtrack_radio_play();
124/*
125	$scope.socket.emit('radio', {
126	    server: s
127	});
128	$scope.mtrack_radio_playing = true;
129*/
130
131     }
132     $scope.mtrack_radio_play = function()  {
133        if ($scope.mtrack_radio_context == null) {
134    	       $scope.mtrack_radio_context = new AudioContext();
135	}
136	$scope.mtrack_radio_playing = 1;
137	$scope.mtrack_radio_playing_ready = 0;
138        $scope.mtrack_radio_model.play_time = 0;
139	$scope.mtrack_radio_timer_obj =  setInterval($scope.mtrack_radio_time, 100);
140	//$scope.mtrack_radio_time();
141	$scope.radio_play_time = $scope.mtrack_radio_context.currentTime;
142	$scope.socket.emit('radio', {
143	    server: $scope.mtrack_radio_server
144	});
145     }
146
147     //
148     //  Radio Idle Time
149     //
150     //
151     $scope.mtrack_radio_time = function()  {
152/*
153	var nothing_to_do = 0;
154
155	if ($scope.mtrack_radio_queue.length == 0) nothing_to_do = 1;
156        if ($scope.mtrack_radio_ready_queue.length) {
157 	}
158	if (nothing_to_do) {
159	    return;
160	}
161*/
162 	
163//console.log("RADIO _TIME " + $scope.mtrack_radio_queue.length + " " + $scope.mtrack_radio_ready_queue.length);
164//
165        let BUFFER_SECONDS = 60;
166	let anow = $scope.mtrack_radio_context.currentTime;
167        if ($scope.radio_play_time - anow < BUFFER_SECONDS) {
168	if ($scope.mtrack_radio_queue.length) {
169	   // Main Radio Pull Queue
170	    var idata = $scope.mtrack_radio_queue[0];
171	    $scope.mtrack_radio_queue.splice(0,1);
172	    $scope.mtrack_radio_load(idata);
173	}
174	}
175	if (!$scope.mtrack_radio_playing_ready)  {
176	    if ($scope.mtrack_radio_ready_queue.length > 2) {
177		$scope.mtrack_radio_playing_ready = 1;
178	    }
179
180	}
181	if ($scope.mtrack_radio_playing_ready) {
182
183	// Main Pull a ready interval
184	if ($scope.mtrack_radio_ready_queue.length) {
185	    
186	    var pdata = $scope.mtrack_radio_ready_queue[0];
187	    $scope.mtrack_radio_ready_queue.splice(0,1);
188	    $scope.mtrack_radio_model_and_play(pdata);
189	    
190        }
191        $scope.mtrack_radio_level_time();
192        }
193	$scope.$apply();
194	//console.log("READY TO PLAY");
195	//console.log(idata);
196
197     }
198
199
200    var myLevelCalc = function(meter) {
201        var freqData = new Uint8Array(meter.frequencyBinCount);
202        meter.getByteFrequencyData(freqData);
203
204  // Put the raw frequency into the newly created array
205        var max = 0;
206        var offset = 0;
207        for (var i = 0; i < freqData.length - offset; i+=8) {
208            if (i == 0) {
209                max = freqData[i + offset];
210            }
211            if (freqData[i + offset] > max) max = freqData[i + offset];
212        }
213        var f = max / 255.;
214        if (f > 1) f = 1.;
215        return(f);
216    }
217
218     $scope.mtrack_radio_level_change = function(track)  {
219 	var f = track.gainval;
220        track.gain.value = f;
221	
222     }
223     $scope.mtrack_radio_level_time = function()  {
224        var model = $scope.mtrack_radio_model;
225	if (!model.tracks) return;
226	for(var ii = 0; ii < model.tracks.length;ii++) {
227	    var val = myLevelCalc(model.tracks[ii].meter);
228	    model.tracks[ii].levels = val;
229	}
230	
231     }
232
233     //
234     //  Radio all stop
235     $scope.mtrack_radio_all_off = function() {
236	console.log("All Off");
237        var model = $scope.mtrack_radio_model;
238	if (!model  || !model.tracks) return;
239	for (t = 0; t < model.tracks.length; t++) {
240	    for (s = 0; s < model.tracks[t].sources.length; s++) {
241	console.log("Buffer source stop " + t + " " + s);
242	    model.tracks[t].sources[s].buffer.stop();
243	    model.tracks[t].sources[s].buffer.disconnect( model.tracks[t].gain);
244		}
245                //scope.mtrack_audio.audioSource[i][k].disconnect($scope.mtrack_audio.audioGain[i]);
246                //$scope.mtrack_audio.audioSource[i][k].stop(0);
247                //scope.mtrack_audio.audioSource[i][k].disconnect($scope.mtrack_audio.audioGain[i]);
248            	//m.pan.disconnect($scope.mtrack_radio_context.destination);
249	}
250	
251     }
252
253     //
254     //  Radio Render to Webaudio
255     //
256     //
257     $scope.mtrack_radio_model_track = function(item, play_time)  {
258        var model = $scope.mtrack_radio_model;
259	var m = null;
260
261	console.log(model);
262	console.log(model.tracks);
263	console.log(model.tracks.length);
264
265	for (t = 0; t < model.tracks.length; t++) {
266	    if(model.tracks[t].username == item.username && model.tracks[t].chan == item.chan) {
267	  	console.log("FOUND TRACK " + item.username + " " + item.chan);
268		m = model.tracks[t];
269	    }
270	}
271	if (m == null) {
272	  	console.log("CREATING TRACK " + item.username + " " + item.chan);
273	    m = {};
274            if ($scope.mtrack_radio_context == null) {
275    	         $scope.mtrack_radio_context = new AudioContext();
276	    }
277	    m.chan = item.chan;
278	    m.username = item.username;
279       
280	    m.gain  = $scope.mtrack_radio_context.createGain();
281                m.pan   = $scope.mtrack_radio_context.createPanner();
282            var x = 0;
283            var y = 0;
284            var z = 3.;
285            m.pan.panningModel = 'equalpower';
286            m.pan.setPosition(0, 0, 0);
287 
288            m.meter = $scope.mtrack_radio_context.createAnalyser();
289            m.meter.smoothingTimeConstant = 0.3;
290            m.meter.fftSize = 128;
291            m.gain.connect(m.pan);
292            m.pan.connect($scope.mtrack_radio_context.destination);
293            m.gain.connect(m.meter);
294	    model.tracks.push(m);
295	}
296        var buff = $scope.mtrack_radio_context.createBufferSource();
297	buff.connect(m.gain);
298        buff.buffer = item.buffer;
299        buff.start(play_time);
300	m.buffer_source = buff;
301	if (!m.sources) {
302	    m.sources = [];
303	}
304	let dur = 60 /item.bpm * item.bpi;
305	m.sources.push( { buffer:buff, start:play_time, dur:dur });
306/*
307            m.source = [];
308            m.source[0] = $scope.mtrack_context.createBufferSource();
309	    m.source[0].connect(m.gain);
310            m.source[1] = $scope.mtrack_context.createBufferSource();
311	    m.audio.source[1].connect(m.gain);
312*/
313	
314     };
315     // Radio Model and Play - Final
316     $scope.radio_play_time = 0;
317     $scope.mtrack_radio_model_and_play = function(idata)  {
318        //$scope.mtrack_radio_model = null;
319        var m = $scope.mtrack_radio_model;
320	if (m == null) {
321		console.log("*************************** MODEL IS NULL");
322	     m = {};
323             $scope.mtrack_radio_model = m;
324 	}
325	//console.log("PLAYING TIME WAS " + m.play_time);
326        if (!m.play_time) {
327  	     m.play_time = 0;
328	} 
329	//var id = idata.
330	m.interval = idata.interval;
331	m.bpi = idata.bpi;
332	m.bpm = idata.bpm;
333	m.server = idata.server;
334	console.log("PLAY 1");
335	console.log(idata);
336	var dur = 60.0 / idata.bpm  * idata.bpi;
337        
338	if (m.tracks == null) {
339	    m.tracks = [];
340	} 
341	//console.log("PLAYING TIME " + m.play_time + " Dur is " + dur);
342	//console.log("PLAYING TIME " + $scope.radio_play_time + " Dur is " + dur + " Track=" + idata.list.length);
343 	for(var ii = 0 ;ii < idata.list.length;ii++) {
344	    var t;
345            //$scope.mtrack_radio_model_track(idata.list[ii], m.play_time);
346            $scope.mtrack_radio_model_track(idata.list[ii], $scope.radio_play_time);
347	}
348	m.play_time += dur;
349	$scope.radio_play_time += dur;
350	$scope.$apply();
351     }
352     $scope.mtrack_radio_load = function(idata)  {
353	idata.waiting  = idata.list.length;
354	for(var ii =0; ii < idata.list.length;ii++) {
355	    $scope.mtrack_radio_load_track(idata, idata.list[ii], function( track )
356	    {
357		idata.waiting --;
358		if (idata.waiting == 0) {
359		    console.log("OMG WE HAVE ALL THE BUFFERS");
360		    $scope.mtrack_radio_ready_queue.push(idata);
361		    
362		}
363	    });
364	}
365     }
366     $scope.mtrack_read = function(buff, callback) {
367	var s = $scope.mtrack_song;
368        var url = "/mtrack?s=" + s + "&afile=" + buff.fname;
369console.log(url);
370  	var request = new XMLHttpRequest();
371  	   request.open('GET', url, true);
372  	   request.responseType = 'arraybuffer';
373  	request.onload = function() {
374
375    	     $scope.mtrack_context.decodeAudioData(request.response, function(buffer) {
376		 console.log("YES");
377	   	    buff.buffer = buffer;
378	   	    buff.status = "loaded";
379		    if (callback) {
380		        callback(null, buff);
381		    }
382	     }, function(err) {
383		console.log("BAD error " + err);
384		    if (callback) {
385		        callback(err, buff);
386		    }
387	     });
388	}
389  	request.send();
390   }
391   $scope.mtrack_radio_load_track = function(idata, track, cb)  {
392	console.log("LOAD TRACK");
393	console.log(idata);
394	console.log(track);
395	if ($scope.mtrack_radio_context == null) $scope.mtrack_radio_context = new AudioContext();
396	var url = "/mradio?session=" + idata.session +"&server=" +idata.server + "&fname=" + track.fname;
397	if (track.arg4.indexOf("Video") > -1) {
398	     console.log("ITS VIDEO");
399	     url = "/mradio?session=" + idata.session +"&video=1&server=" +idata.server + "&fname=" + track.fname;
400	     track.isvideo = 1;
401	} ;
402	
403
404
405        var request = new XMLHttpRequest();
406        request.open('GET', url, true);
407  	request.responseType = 'arraybuffer';
408  	request.onload = function() {
409    	$scope.mtrack_radio_context.decodeAudioData(request.response, function(buffer) {
410	   track.buffer = buffer;
411	   if (cb) cb(track);
412	});
413        }
414  	request.send();
415/*
416console.log(url);
417	     $http( 
418		{  url: url, 
419		   method:"GET"
420		}).then(function(res) {
421                        console.log("Success len = " + res.data.length);
422                        var data = res.data;
423                             $scope.mtrack_radio_context.decodeAudioData(data, function(buffer) {
424                                 console.log("Decoded Audio");
425                                 //buff.buffer = buffer;
426			   	track.buffer = buffer;
427				if (cb) cb(track);
428			
429                             })
430
431                }, function(err) {
432                        track.error = err;
433			if (cb) cb(track);
434                });
435*/
436
437/*
438
439                    if (res.data.error ) {
440                        track.error = res.data.error;
441			if (cb) cb(track);
442                    } else {
443		   	track.buffer = res.data;
444			if (cb) cb(track);
445                    }
446                }, function(err) {
447                        track.error = err;
448			if (cb) cb(track);
449                });
450*/
451
452
453
454	
455	
456     }
457     $scope.mtrack_radio_stop = function()  {
458	$scope.socket.emit('radio', {
459	    server: $scope.mtrack_radio_server,
460	    cmd: "unsub"
461	});
462	//$scope.mtrack_radio_stop();
463
464	$scope.mtrack_radio_playing = 0;
465        $scope.mtrack_radio_all_off();
466
467	clearInterval($scope.mtrack_radio_timer_obj);
468     }
469     var lastInterval = 0;
470     $scope.socket.on('interval', function(msg){
471/*
472	if ($scope.mtrack_radio_playing == 0 ) {
473	    return;
474	}
475*/
476	console.log("Interval Event Received " + msg.interval + " channels " + msg.list.length);
477	console.log(msg);
478/*
479	if (msg.interval == lastInterval) {
480	    console.log("Dup Event Received");
481	} else  {
482	    $scope.mtrack_radio_queue.push(msg);
483	}
484*/
485
486	$scope.mtrack_radio_queue.push(msg);
487
488	// Keep the queue Small
489	/*
490	if ($scope.mtrack_radio_queue.length > 2) {
491		console.log("I spliced the quue length now " + $scope.mtrack_radio_queue.length);
492	   $scope.mtrack_radio_queue.splice(0,1);
493	}
494*/
495	lastInterval = msg.interval;
496/*
497	if ($scope.mtrack_radio_queue.length > 3) {
498	   console.log("Dropping interval " + $scope.mtrack_radio_queue[0].interval);
499	   $scope.mtrack_radio_queue.splice(0,1);
500	}
501*/
502	$scope.$apply();
503     });
504
505     $scope.mtrack_edit_radio = function( s) 
506     {
507          //$scope.mtrack_radio(s);
508          $scope.mtrack_edit_song(s);
509
510     }
511     //////////////////////////// END RADIO
512     //
513     //	
514     //
515     // Entry point for mtrack edit
516     //
517     // 
518     // Main Timeline Reader Recalc Rebuild Reader Loader Master Facilitator
519     //
520     //
521     //
522     $scope.mtrack_edit_song = function( s) 
523     {    
524        $scope.user_menu_select_bytag("mtrack", "edit");
525	if ($scope.mtrack_song == s) {
526	   return;
527	}
528	   if (s && s.indexOf(":") != -1) {
529		$scope.isradio = 1;
530	   } else {
531		$scope.isradio = 0;
532	
533 	   }
534
535	if ($scope.mtrack_playing) {
536             $scope.mtrack_play_pause();
537	}
538	$scope.mtrack_song = s;
539	$http( {method:"GET",
540              url:"/mtrack?s=" + s
541                }).then(function(res) {
542
543                    if (res.data.error ) {
544			console.log(res.data.error);
545                        $scope.mtrack = null;
546			$scope.mtrack_timeline_rebuild();
547                    } else {
548			console.log("MTRACK RETURNED ");
549			console.log(res.data);
550                        $scope.mtrack = res.data;
551			$scope.mtrack_timeline_rebuild();
552                    }
553                }, function(err) {
554                        $scope.mtrack = null;
555			$scope.mtrack_timeline_rebuild();
556                });
557
558     }
559     let last_radio_update = 0;
560     $scope.mtrack_radio_update = function( ) 
561     {    
562	var ss = new Date().getTime();
563	if (ss - last_radio_update < 30000) {
564	     return(0);
565	}
566      	last_radio_update = ss;
567	console.log("radio update called");
568	console.log($scope.mtrack[$scope.mtrack.length -1]);
569	var last_session = $scope.mtrack[$scope.mtrack.length -1].session;
570	var last_interval = $scope.mtrack[$scope.mtrack.length -1].interval;
571
572        //$scope.user_menu_select_bytag("mtrack", "edit");
573	var s = $scope.mtrack_song;
574	$http( {method:"GET",
575              url:"/mtrack?s=" + s
576                }).then(function(res) {
577
578                    if (res.data.error ) {
579			console.log(res.data.error);
580 //                       $scope.mtrack = null;
581//			$scope.mtrack_timeline_rebuild();
582                    } else {
583			console.log("MTRACK RETURNED ");
584			console.log(res.data);
585			let cnt = 0;
586                        var mtrack_new = res.data;
587			for (var ii = 0 ; ii < mtrack_new.length; ii++) {
588			    if (mtrack_new[ii].session != last_session || mtrack_new[ii].interval > last_interval) {
589			     	$scope.mtrack.push(mtrack_new[ii]);
590				cnt++;
591			    }
592			}
593			console.log("Added " + cnt + " intervals");
594     			$scope.mtrack_timeline_radio_rebuild($scope.mtrack.length -cnt) ;
595			//console.log("New is " + new_session + " " + new_interval);
596	
597			
598			//$scope.mtrack_timeline_rebuild();
599                    }
600                }, function(err) {
601                        //$scope.mtrack = null;
602			//$scope.mtrack_timeline_rebuild();
603                });
604	
605
606     }
607     // 
608     // Son of Main Timeline Recalc Rebuild Reader Loader Master Facilitator
609     // Takes mtrack and build tracklist
610     //
611     $scope.mtrack_timeline_radio_rebuild = function(start) 
612     {
613console.log("MTRACK REBUILD " + start + " " + $scope.mtrack.length);
614   	//var tracklist = $scope.tracklist;
615	var dur = $scope.mtrack_duration;
616	for (var ii = start; ii < $scope.mtrack.length; ii++) {
617	    interval = $scope.mtrack[ii];
618console.log(interval);
619	    dur += (60 / interval.bpm * interval.bpi);
620	    for(var utrack of interval.channels) {
621	         var id = utrack.user + "-" +  utrack.type + "-" + utrack.chan;
622	  	 var fnd = 0;	
623console.log("LOOKING FOR ID " + id);
624	         for(var tt = 0; tt <  $scope.tracklist.length; tt++) {
625	         //for(var track of $scope.tracklist) {
626		    if ($scope.tracklist[tt].id == id) {
627/*
628		        for (var nn = $scope.tracklist[tt].last_interval ; nn < interval.interval;nn++ ) {
629			    $scope.tracklist[tt].intervals.push({});
630			}
631*/
632console.log("PUSHING NEW INTERVAL");
633console.log(utrack);
634			$scope.tracklist[tt].intervals.push(utrack);
635			fnd = 1; break;
636			break;
637		    } 
638		 }
639	 	if (!fnd) {
640		   var track = {};
641		   track.id = id;
642		   track.type = utrack.type;
643		   track.chan = utrack.chan;
644		   track.user = utrack.user;
645		   track.level = 0;
646		   track.gain = 100;
647		   track.pan = 0;
648		   var ss = track.user.lastIndexOf("@");
649		   if (ss == -1) {
650		       track.name = track.user;
651		       track.ip = "";
652		   } else {
653		       track.ip = track.user.substr(ss+1, track.user.length);
654		       track.name = track.user.substr(0, ss);
655		   }
656		   //console.log(track);
657		   track.intervals = [];
658		   for (var nn =1 ; nn < interval.interval;nn++ ) {
659		       track.intervals.push({});
660		   }
661		   track.intervals.push(utrack);
662		   track.last_interval = interval.interval;
663		   track.uid = track_uid_cnt++;
664     		   $scope.mtrack_create_audio(track);
665		   if (track.type == "audio") {
666		       $scope.tracklist.push(track);
667		   } else {
668		       $scope.videolist.push(track);
669		   }
670		}	
671	   
672	   }
673
674	}
675 	console.log($scope.mtrack);	
676 	console.log($scope.tracklist);	
677	$scope.mtrack_duration = dur;
678
679
680     }
681     var track_uid_cnt = 0;
682     $scope.mtrack_timeline_rebuild = function() 
683     {
684console.log("TIMELINE REBUILD");
685	let dur = 0;
686     	//$scope.mtrack_audio_init();
687	//console.log($scope.mtrack);
688	var tracklist = [];
689	var videolist = [];
690	track_uid_cnt = 0;
691	for(var interval of $scope.mtrack) {
692	   dur += (60 / interval.bpm * interval.bpi);
693	   for(var utrack of interval.channels) {
694		var id = utrack.user + "-" +  utrack.type + "-" + utrack.chan;
695	  	var fnd = 0;	
696	        for(var track of tracklist) {
697		    if (track.id == id) {
698		        for (var nn =track.lst_interval ; nn < interval.interval;nn++ ) {
699			    track.intervals.push({});
700			}
701			track.intervals.push(utrack);
702			fnd = 1; break;
703			break;
704		    } 
705		}
706	 	if (!fnd) {
707		   var track = {};
708		   track.id = id;
709		   track.type = utrack.type;
710		   track.chan = utrack.chan;
711		   track.user = utrack.user;
712		   track.level = 0;
713		   track.gain = 100;
714		   track.pan = 0;
715		   var ss = track.user.lastIndexOf("@");
716		   if (ss == -1) {
717		       track.name = track.user;
718		       track.ip = "";
719		   } else {
720		       track.ip = track.user.substr(ss+1, track.user.length);
721		       track.name = track.user.substr(0, ss);
722		   }
723		   //console.log(track);
724		   track.intervals = [];
725		   for (var nn =1 ; nn < interval.interval;nn++ ) {
726		       track.intervals.push({});
727		   }
728		   track.intervals.push(utrack);
729		   track.last_interval = interval.interval;
730		   track.uid = track_uid_cnt++;
731		   if (track.type == "audio") {
732		       tracklist.push(track);
733		   } else {
734		       videolist.push(track);
735		   }
736		}	
737	   
738	   }
739	   $scope.mtrack_in = 0.0;
740	   $scope.meta_in_trans = "none";
741	   $scope.meta_out_trans = "none";
742	   $scope.meta_share = "private";
743	   $scope.mtrack_out = dur;
744	   $scope.metadata_lookup = $scope;
745	   //console.log("Dur is " + dur);
746	}
747	$scope.mtrack_duration = dur;
748        $scope.mtrack_draw_timeline();
749	$scope.tracklist = tracklist;
750	$scope.videolist = videolist;
751//	$scope.tracklist.sort();
752
753	$scope.tracklist.sort(function(a,b) {
754	    if (a.id < b.id) return(-1);
755	    if (a.id > b.id) return(1);
756	    return(0);
757	});
758	console.log($scope.tracklist);
759
760    	$scope.mtrack_context = new AudioContext();
761	// Wire up audio
762	for( var track of $scope.tracklist ) {
763	    track.audio = {};
764	    track.audio.gain  = $scope.mtrack_context.createGain();
765            track.audio.pan   = $scope.mtrack_context.createPanner();
766            var x = 0;
767            var y = 0;
768            var z = 3.;
769            track.audio.pan.panningModel = 'equalpower';
770            track.audio.pan.setPosition(0, 0, 0);
771    
772            track.audio.meter = $scope.mtrack_context.createAnalyser();
773            track.audio.meter.smoothingTimeConstant = 0.3;
774            track.audio.meter.fftSize = 128;
775/*    
776            $scope.mtrack_audio.audioSource[i] = new Array(numSource);
777            $scope.mtrack_audio.audioLoaded[i] = new Array(numSource);
778            $scope.mtrack_audio.audioBuffer[i] = new Array(numSource);
779
780*/
781            track.audio.gain.connect(track.audio.pan);
782            track.audio.pan.connect($scope.mtrack_context.destination);
783            track.audio.gain.connect(track.audio.meter);
784
785            track.audio.source = [];
786            track.audio.source[0] = $scope.mtrack_context.createBufferSource();
787	    track.audio.source[0].connect(track.audio.gain);
788            track.audio.source[1] = $scope.mtrack_context.createBufferSource();
789	    track.audio.source[1].connect(track.audio.gain);
790            track.audio.source[2] = $scope.mtrack_context.createBufferSource();
791	    track.audio.source[2].connect(track.audio.gain);
792            track.audio.source[3] = $scope.mtrack_context.createBufferSource();
793	    track.audio.source[3].connect(track.audio.gain);
794/*
795        for (var i = 0; i < appMixer.data.length; i++) {
796          if (appMixer.audioLoaded[i][appMixer.mixer.readBuffer] == 9) {
797                // console.log("Playing track " + i + " at time " + appMixer.playTime);
798            appMixer.audioSource[i][appMixer.mixer.readBuffer] = appMixer.audioContext.createBufferSource();
799            appMixer.audioSource[i][appMixer.mixer.readBuffer].buffer =  appMixer.audioBuffer[i][appMixer.mixer.readBuffer];
800            intervalSize = appMixer.audioBuffer[i][appMixer.mixer.readBuffer].duration;
801            appMixer.audioSource[i][appMixer.mixer.readBuffer].loop = appMixer.loopMode;
802            appMixer.audioSource[i][appMixer.mixer.readBuffer].connect(appMixer.audioGain[i]);
803            //appMixer.audioSource[i][appMixer.mixer.readBuffer].noteOn(appMixer.playTime);
804            appMixer.audioSource[i][appMixer.mixer.readBuffer].start(appMixer.playTime);
805          } else {
806                // console.log("Skipping track " + i);
807          }
808       }
809*/
810       
811         }
812	
813	setTimeout( function() {
814        $scope.mtrack_draw_timeline();
815	}, 1000);
816	$scope.mtrack_ready();
817     }
818     $scope.mtrack_create_audio = function(track)
819     {
820	    track.audio = {};
821	    track.audio.gain  = $scope.mtrack_context.createGain();
822            track.audio.pan   = $scope.mtrack_context.createPanner();
823            var x = 0;
824            var y = 0;
825            var z = 3.;
826            track.audio.pan.panningModel = 'equalpower';
827            track.audio.pan.setPosition(0, 0, 0);
828    
829            track.audio.meter = $scope.mtrack_context.createAnalyser();
830            track.audio.meter.smoothingTimeConstant = 0.3;
831            track.audio.meter.fftSize = 128;
832/*    
833            $scope.mtrack_audio.audioSource[i] = new Array(numSource);
834            $scope.mtrack_audio.audioLoaded[i] = new Array(numSource);
835            $scope.mtrack_audio.audioBuffer[i] = new Array(numSource);
836
837*/
838            track.audio.gain.connect(track.audio.pan);
839            track.audio.pan.connect($scope.mtrack_context.destination);
840            track.audio.gain.connect(track.audio.meter);
841
842            track.audio.source = [];
843            track.audio.source[0] = $scope.mtrack_context.createBufferSource();
844	    track.audio.source[0].connect(track.audio.gain);
845            track.audio.source[1] = $scope.mtrack_context.createBufferSource();
846	    track.audio.source[1].connect(track.audio.gain);
847            track.audio.source[2] = $scope.mtrack_context.createBufferSource();
848	    track.audio.source[2].connect(track.audio.gain);
849            track.audio.source[3] = $scope.mtrack_context.createBufferSource();
850	    track.audio.source[3].connect(track.audio.gain);
851
852
853     }
854
855
856
857     //
858     //  Main Mtrack Param render
859     //
860     //
861     $scope.mtrack_audio_remix = function() {
862	let is_solo = 0;
863	console.log("Audio Remix");
864	for(var tt = 0; tt < $scope.tracklist.length; tt++) {
865	    if ($scope.tracklist[tt].solo) { 
866		is_solo = 1;
867		break;
868	    }
869        }   
870   	if (is_solo) {
871	    for(var tt = 0; tt < $scope.tracklist.length; tt++) {
872		g = 0;
873	        if ($scope.tracklist[tt].solo) {
874		    g = 1;
875		}
876	        if ($scope.tracklist[tt].mute) {
877		    g = 0;
878		}
879	        g *= ($scope.tracklist[tt].gain / 100);
880		console.log("TTSOLO " + tt + " " + g);
881		$scope.tracklist[tt].audio.gain.gain.value = g;
882	    }
883	}  else {
884	    for(var tt = 0; tt < $scope.tracklist.length; tt++) {
885		g = 1;
886	        if ($scope.tracklist[tt].mute) {
887		    g = 0;
888		}
889	        g *= ($scope.tracklist[tt].gain / 100);
890		console.log("TT " + tt + " " + g);
891		$scope.tracklist[tt].audio.gain.gain.value = g;
892	    }
893	} 
894
895     }
896    var can = document.getElementById("mtrack_seek");
897
898    //
899    //   mounse down in seek canvas
900    //
901    can.onmousedown = function(e) {
902        var rect = can.getBoundingClientRect();
903        //var wid= can.width;
904        var wid= can.offsetWidth;
905
906        var p = (e.x - rect.left) / wid;
907        //console.log("wid is + " + can.width + " wid = " + wid + "  got e.x  = " + e.x + " rect.left is " +rect.left + " = " +  (e.x - rect.left) + "  Pp = " + p);
908//can.width;
909//200;
910        var ct = $scope.mtrack_duration * p;
911        $scope.mtrack_seek(ct);
912        //$location.search("time", $scope.audio.currentTime );
913
914
915    };
916     $scope.mtrack_seek = function( time ) {
917	let was_playing = 0;
918	if ($scope.mtrack_playing) {
919	    was_playing = 1;
920     	    $scope.mtrack_play_pause();
921	}
922        $scope.mtrack_play_time_currentTime = time;
923        $scope.mtrack_play_current_time = time;
924	if (was_playing) {
925     	    $scope.mtrack_play_pause();
926	}
927/*
928     	    $scope.mtrack_play_pause();
929	}
930*/
931        $scope.mtrack_seek_update();
932        $scope.mtrack_draw_timeline();
933	$scope.$apply();
934	console.log("MTRACK SEEK " + time);
935     }
936     $scope.mtrack_seek_update = function( ) {
937	var c = document.getElementById("mtrack_seek");
938        var ctx = c.getContext("2d");
939        var wid= c.width;
940        ctx.fillStyle = "#333";
941        ctx.fillRect(0, 0, wid, 150);
942        ctx.fillStyle = "#36b";
943	   //$scope.mtrack_play_current_time = sofar;
944        ctx.fillRect(0, 0,  wid * ($scope.mtrack_play_current_time / $scope.mtrack_duration), 150);
945
946     }
947
948     var drawit = function(c, start, stop) {
949	//console.log("Drawit " + start +" " + stop);
950  
951        var wid = c.width;
952        var ctx = c.getContext("2d");
953	var x1 = wid * (start /  $scope.mtrack_duration);
954	var x2 = wid * (stop /  $scope.mtrack_duration);
955        ctx.fillStyle = "#222";
956        ctx.fillRect(0, 0, wid, 150);
957        ctx.fillStyle = "#522";
958        ctx.fillRect(x1, 0, x2-x1, 150);
959        //ctx.fillStyle = "#36b";
960	   //$scope.mtrack_play_current_time = sofar;
961        //ctx.fillRect(0, 0,  wid * ($scope.mtrack_play_current_time / $scope.mtrack_duration), 150);
962     }
963
964
965     mtrack_timeline_canvas_mouse = function(can, e)  {
966        var rect = can.getBoundingClientRect();
967        //var wid= can.width;
968        var wid= can.offsetWidth;
969
970        var p = (e.x - rect.left) / wid;
971        //console.log("wid is + " + can.width + " wid = " + wid + "  got e.x  = " + e.x + " rect.left is " +rect.left + " = " +  (e.x - rect.left) + "  Pp = " + p);
972//can.width;
973//200;
974        var ct = $scope.mtrack_duration * p;
975        $scope.mtrack_seek(ct);
976        //$location.search("time", $scope.audio.currentTime );
977
978
979    };
980     $scope.mtrack_draw_timeline = function( ) {
981	if (!$scope.tracklist) return;
982	for (var tt= 0;tt <$scope.tracklist.length;tt++) {
983	     var cname = "mtrack_timeline_" + $scope.tracklist[tt].uid;
984		//console.log("cname = " + cname);
985	     var c = document.getElementById(cname);
986		//console.log("Element " + c.width + " " + c.clientWidth);
987	     c.width = c.clientWidth;
988	     //c.height = c.style.height;
989	     //var lw = c.style.width / c.width *5;
990	     var lw = 2;
991	     c.onmousedown = function(e) {
992		 mtrack_timeline_canvas_mouse(c, e);
993	     }
994             var ctx = c.getContext("2d");
995             var wid = c.width;
996	     //console.log($scope.tracklist[tt].intervals);	
997	     let start = -1;
998	     let stop = -1;
999	     let t = 0;
1000//console.log($scope.mtrack);
1001	     for (var ii= 0;ii <$scope.tracklist[tt].intervals.length;ii++) {
1002		if ($scope.tracklist[tt].intervals[ii].fname) {
1003		    if (start == -1) {
1004			start = t;
1005		    }
1006		    stop = t;
1007		} else {
1008		    if (start != -1) {
1009		        stop = t;
1010			drawit(c, start, stop);
1011		    }
1012		}
1013if ( !$scope.mtrack[ii] ) {
1014     //console.log("II = " + ii + " No MTRACK") ;
1015} else {
1016		t += (60/ $scope.mtrack[ii].bpm *  $scope.mtrack[ii].bpi);
1017}
1018		//console.log("T now " + t);
1019		
1020	     }
1021  	     if (start != -1) {
1022		  stop = t;
1023		 drawit(c, start, stop);
1024	     }
1025	     ctx.beginPath();
1026	     //var xx = $scope.mtrack_play_current_time;
1027	     var xx = wid * ($scope.mtrack_play_current_time /  $scope.mtrack_duration);
1028	     xx = Math.ceil(xx) + 1;
1029	     ctx.moveTo(xx, 0);
1030	     ctx.lineTo(xx, 150);
1031	     ctx.lineWidth = lw;
1032             ctx.strokeStyle = '#009900';
1033	     ctx.stroke();
1034	     xx = wid * ($scope.mtrack_in /  $scope.mtrack_duration);
1035	     xx = Math.ceil(xx) + 1;
1036	     ctx.moveTo(xx, 0);
1037	     ctx.lineTo(xx, 150);
1038             ctx.strokeStyle = '#90a0a0';
1039	     ctx.stroke();
1040	     xx = wid * ($scope.mtrack_out /  $scope.mtrack_duration);
1041	     xx = Math.ceil(xx) + 1;
1042	     ctx.moveTo(xx, 0);
1043	     ctx.lineTo(xx, 150);
1044             ctx.strokeStyle = '#00a090';
1045	     ctx.stroke();
1046	}
1047     }
1048
1049     // 
1050     // Main Play Idle Time
1051     //
1052     let BUFFER_SECONDS = 12;
1053     $scope.mtrack_play_current_time = 0;
1054     $scope.mtrack_play_update_time = function() {
1055	   let anow = $scope.mtrack_context.currentTime;
1056	   let sofar = (anow - $scope.mtrack_play_time_startCurrentTime);
1057	   sofar += $scope.mtrack_play_time_startTime;
1058	   $scope.mtrack_play_current_time = sofar;
1059           $scope.mtrack_seek_update();
1060// + $scope.mtrack_play_time_startTime;
1061//Need to know start time relative to context.currentTime
1062	   //console.log("SOFAR " + sofar);
1063	    $scope.$apply();
1064
1065	   let now = new Date().getTime();
1066	   now = now - $scope.mtrack_play_time;
1067	   now /= 1000;
1068	   //console.log("Its Play Update Time Sec=" + now);
1069	   //console.log("Anow   " + anow);
1070	   //console.log("Buffer time is " + $scope.mtrack_play_buffer_time);
1071	   if ( ($scope.mtrack_play_buffer_time - anow) <= BUFFER_SECONDS ) 
1072	   {
1073		let interval = $scope.mtrack_play_time_interval;
1074	   console.log("Its time for a buffer " + interval);
1075	   console.log("Its Play Update Time Sec=" + now);
1076	   console.log("Buffer time is " + $scope.mtrack_play_buffer_time);
1077		//console.log( $scope.tracklist[0].intervals[interval]);
1078		let bbpi = $scope.mtrack[interval].bpi;
1079		let bbpm = $scope.mtrack[interval].bpm;
1080		//let bbpm = $scope.tracklist[0].intervals[interval].bpm;
1081		let bsec = 60/ bbpm * bbpi;
1082		$scope.mtrack_play_time_interval++;
1083      		$scope.mtrack_play_buffer_time += bsec;
1084      		let mytime = $scope.mtrack_play_buffer_time;
1085      		let myinterval = interval;
1086	        $scope.mtrack_queue_one( $scope.mtrack_play_time_interval, mytime, function(interval, sec) {
1087		console.log("PLAYING INTERVAL  " + myinterval + " At " + sec + " Sec");
1088		    $scope.mtrack_play_interval(interval, sec);
1089	        });
1090/*
1091	       $scope.mtrack_queue_one( $scope.mtrack_play_time_interval, function(interval) {
1092		// Ready for playback;
1093		    console.log("Ready For playback " + interval);
1094		    $scope.mtrack_play_interval(interval, 0);
1095
1096		
1097	       });
1098*/
1099 	   }
1100
1101     	   //$scope.mtrack_play_time = 0;
1102     //$scope.mtrack_play_time_interval = 0;
1103     //$scope.mtrack_play_time_next_time = 0;
1104	   for(var tt = 0; tt < $scope.tracklist.length; tt++) {
1105    		let f = myLevelCalc($scope.tracklist[tt].audio.meter);
1106
1107		//console.log("mtrack_meter_" + $scope.tracklist[tt].uid);
1108		let elem = document.getElementById("mtrack_meter_" + $scope.tracklist[tt].uid);
1109		var ctx = elem.getContext("2d");
1110
1111		let wid = elem.width;
1112		let hei = elem.height;
1113		ctx.width = wid;
1114		ctx.hei = hei;
1115		ctx.beginPath();
1116		ctx.rect(0, 0,  wid, hei);
1117		ctx.fillStyle = "#222";
1118		ctx.fill();
1119
1120		ctx.beginPath();
1121		ctx.rect(0, 0, f * wid, hei);
1122		ctx.fillStyle = "#090";
1123		ctx.fill();
1124
1125
1126    		//let f = $scope.mtrack_levelCalc(tt);
1127    		if (f != 0) {
1128		    //console.log("LEVEL " + tt + " = " + f);
1129		}
1130	   }
1131     	   $scope.mtrack_draw_timeline();
1132           $scope.mtrack_radio_update();
1133     }
1134
1135     $scope.mtrack_play_time = 0;
1136     $scope.mtrack_play_time_interval = 0;
1137     $scope.mtrack_play_time_next_time = 0;
1138     $scope.mtrack_play_buffer_time = 0;
1139     $scope.mtrack_play_time_startTime = 0;
1140     $scope.mtrack_play_time_currentTime = 0;
1141
1142     //
1143     //   Main Play and Stop
1144     //
1145     //
1146     $scope.mtrack_play_pause = function() {
1147
1148	if ($scope.mtrack_playing) {
1149	    $scope.mtrack_playing = 0;
1150            $scope.mtrack_play_time_currentTime = $scope.mtrack_context.currentTime +  $scope.mtrack_play_time_startTime;
1151            $scope.mtrack_play_time_currentTime = $scope.mtrack_play_time_startTime + ($scope.mtrack_context.currentTime - $scope.mtrack_play_time_startCurrentTime);
1152	    clearInterval( $scope.mtrack_play_interval_timer);
1153	    console.log("Stopping sources");
1154	    for(var tt=0; tt< $scope.tracklist.length;tt++) {	
1155	        for(var bb=0; bb< $scope.tracklist[tt].audio.source.length;bb++) {	
1156		    try {
1157		        $scope.tracklist[tt].audio.source[bb].stop();	
1158		    } catch(err) {
1159		    }
1160		}
1161 	    }
1162	} else {
1163	    //$scope.mtrack_context.resume();
1164     	    $scope.mtrack_play_time = new Date().getTime();
1165	    $scope.mtrack_play_interval_timer = setInterval(function() {
1166		//console.log("MrStickies Interval Timer Called");
1167		$scope.mtrack_play_update_time();
1168 	    }, 100);
1169
1170	    $scope.mtrack_playing = 1;
1171      	    $scope.mtrack_play_buffer_time =0;
1172	    //$scope.mtrack_animate();
1173/*
1174     	    $scope.mtrack_audio.playFrom(0);
1175*/
1176//	    $scope.mtrack_play_start(0);
1177//
1178//Need to know start time relative to context.currentTime
1179
1180            // startTime is clip time
1181	    $scope.mtrack_play_time_startTime =  $scope.mtrack_play_time_currentTime + 1;
1182            // startCurrnetTime is context time
1183     	    $scope.mtrack_play_time_startCurrentTime = $scope.mtrack_context.currentTime + 1;
1184            // buffer_time = context time
1185     	    $scope.mtrack_play_buffer_time = $scope.mtrack_play_time_startCurrentTime ;
1186	    let start_time = $scope.mtrack_play_time_startTime;
1187	    let ttime = 0;
1188 	    $scope.mtrack_play_time_interval = 0;
1189	    for (var nn = 0; nn < $scope.mtrack.length;nn++ ) {
1190		let bbpi = $scope.mtrack[nn].bpi;
1191		let bbpm = $scope.mtrack[nn].bpm;
1192		let bsec = 60/ bbpm * bbpi;
1193	  	let res = ttime + bsec;	
1194		if (res > start_time) {
1195		    $scope.mtrack_play_time_interval = nn;
1196		    break;
1197		}
1198		ttime += bsec;
1199	    }
1200	    $scope.mtrack_queue_one( $scope.mtrack_play_time_interval, $scope.mtrack_play_buffer_time,  function(interval, sec) {
1201		// Ready for playback;
1202		console.log("Ready For playback " + interval);
1203		$scope.mtrack_play_interval(interval, sec);
1204
1205		
1206	    });
1207	}
1208	//$scope.mtrack_playing = !$scope.mtrack_playing;
1209     }
1210/*
1211     $scope.mtrack_play_start = function(interval) {
1212     }
1213
1214     $scope.mtrack_play_time = function() {
1215	
1216	while(playing) {
1217	    $scope.mtrack_queue_one( interval, function(interval) {
1218		// Ready for playback;
1219		console.log("Ready For playback " + interval);
1220		$scope.mtrack_play_interval(interval, 0);
1221	    }
1222
1223	
1224     }
1225
1226*/
1227     function unlockAudioContext(audioCtx) {
1228        if (audioCtx.state !== 'suspended') return;
1229  	const b = document.body;
1230  	const events = ['touchstart','touchend', 'mousedown','keydown'];
1231  	events.forEach(e => b.addEventListener(e, unlock, false));
1232  	function unlock() { audioCtx.resume().then(clean); }
1233  	function clean() { events.forEach(e => b.removeEventListener(e, unlock)); }
1234     }
1235     //
1236     //  Main Interval Play Routine
1237     //
1238     //
1239     //
1240     $scope.mtrack_play_interval = function(interval, sec)
1241     {
1242	    //var context = new AudioContext();
1243            var context = new (window.AudioContext || window.webkitAudioContext)();
1244	    unlockAudioContext(context);
1245
1246
1247	    //console.log("Playing interval " + window.performance.memory);
1248	    console.log("======================== Playing interval at time " + sec);
1249
1250
1251
1252	    for(var tt = 0; tt < $scope.tracklist.length; tt++) {
1253		if ($scope.tracklist[tt].intervals.length > interval) {
1254		if ($scope.tracklist[tt].intervals[interval].fname) {
1255		    var buff = $scope.tracklist[tt].intervals[interval].buff.buffer;
1256	//console.log("Playing " +  $scope.tracklist[tt].intervals[interval].buff.id);
1257		    if (buff) {
1258			//var which = interval % 2;
1259			var which = interval % $scope.tracklist[tt].audio.source.length;
1260
1261//                        $scope.tracklist[tt].audio.source[which].stop(0);
1262                        $scope.tracklist[tt].audio.source[which].disconnect($scope.tracklist[tt].audio.gain);
1263                        $scope.tracklist[tt].audio.source[which] = null;
1264
1265                        $scope.tracklist[tt].audio.source[which] = $scope.mtrack_context.createBufferSource();
1266                        $scope.tracklist[tt].audio.source[which].connect($scope.tracklist[tt].audio.gain);
1267/*
1268			let bbpi = $scope.tracklist[tt].intervals[interval].bpi;
1269			let bbpm = $scope.tracklist[tt].intervals[interval].bpm;
1270			let bsec = bbpm / 60 * bbpi;
1271      			$scope.mtrack_play_buffer_time = sec + bsec;
1272*/
1273
1274			var source = $scope.tracklist[tt].audio.source[which];
1275  		        source.buffer = buff; 
1276
1277console.log("=============== SOURCE START " + sec);
1278	     	        source.start(sec);                           // play the source now
1279		       /*
1280  		       source.buffer = buff; 
1281			source.connect(context.destination);
1282	     	       source.start(0);                           // play the source now
1283	*/
1284		    }
1285		
1286		}}
1287 	     }
1288
1289	
1290
1291     }
1292$scope.mtrack_audio.updateAudio = function ()
1293{
1294  var solo = 0;
1295
1296  for(var i = 0; i < $scope.mtrack_audio.data.length; i++) {
1297     // If we have one solo turn them all off
1298     if ($scope.mtrack_audio.chanParamValues[i]['solo']) {
1299        if ($scope.mtrack_audio.chanParamValues[i]['solo'].val == 1) {
1300            solo ++;
1301        }
1302     }
1303  }
1304
1305//console.log("Solo is " + solo);
1306
1307  for(var i = 0; i < $scope.mtrack_audio.data.length; i++) {
1308        var panp = $scope.mtrack_audio.chanParamValues[i]['pan'];
1309        var gainp = $scope.mtrack_audio.chanParamValues[i]['gain'];
1310        var gain = 1.;
1311        if (gainp) {
1312            gain = gainp.val;
1313            gain = $scope.mtrack_audio.easeInQuad(gain, 0, 100., 100.) ;
1314            gain = gain / 100.;
1315        }
1316        if ($scope.mtrack_audio.chanParamValues[i]['mute']) {
1317           if ($scope.mtrack_audio.chanParamValues[i]['mute'].val) {
1318                gain = 0;
1319           }
1320        }
1321
1322  if (solo) {
1323           if (!$scope.mtrack_audio.chanParamValues[i]['solo']) {
1324              gain = 0;
1325           } else {
1326               if ($scope.mtrack_audio.chanParamValues[i]['solo'].val == 0) {
1327                  gain = 0;
1328                }
1329           }
1330        }
1331        $scope.mtrack_audio.audioGain[i].gain.value = gain;
1332
1333        $scope.mtrack_audio.audioPan[i].setPosition( panp.val /100. , 0, 1 - Math.abs(panp.val / 100.));
1334
1335         //$scope.mtrack_audio.audioPan[track].setPosition( ui.value , 0,  1 - Math.abs( ui.value));;
1336        //$scope.mtrack_audio.audioPan[i].panningModel = 'equalpower';
1337        //$scope.mtrack_audio.audioPan[i].setPosition(0,0,0);
1338  }
1339  if ($scope.mtrack_audio.masterParams) {
1340        var gainp = $scope.mtrack_audio.masterParams['gain'];
1341        var gain = 1.;
1342        if (gainp)  {
1343            gain = gainp.val;
1344            gain = $scope.mtrack_audio.easeInQuad(gain, 0, 100., 100.) ;
1345            gain /= 100.;
1346        }
1347        $scope.mtrack_audio.masterGain.gain.value = gain;
1348
1349   }
1350
1351}
1352
1353
1354
1355
1356     $scope.mtrack_current_pos = 1;
1357     $scope.mtrack_queue_interval = 1;
1358     $scope.mtrack_queue_chan = 0;
1359     $scope.mtrack_read = function(buff, callback) {
1360	var s = $scope.mtrack_song;
1361        var url = "/mtrack?s=" + s + "&afile=" + buff.fname;
1362	// url += "&mp3file=1";
1363console.log(url);
1364  	var request = new XMLHttpRequest();
1365  	   request.open('GET', url, true);
1366  	   request.responseType = 'arraybuffer';
1367  	request.onload = function() {
1368
1369    	     $scope.mtrack_context.decodeAudioData(request.response, function(buffer) {
1370		 //console.log("YES");
1371	   	    buff.buffer = buffer;
1372	   	    buff.status = "loaded";
1373		    if (callback) {
1374		        callback(null, buff);
1375		    }
1376	     }, function(err) {
1377		console.log("BAD error " + err);
1378		    if (callback) {
1379		        callback(err, buff);
1380		    }
1381	     });
1382	}
1383  	request.send();
1384   }
1385     $scope.mtrack_read_no = function(buff, callback) {
1386	var s = $scope.mtrack_song;
1387	//console.log("Mtrack read " + JSON.stringify(buff));
1388	
1389	//console.log("MTRACK " + s);
1390	$http( {method:"GET",
1391              url:"/mtrack?s=" + s + "@afile=" + buff.fname
1392                }).then(function(res) {
1393                    if (res.data.error ) {
1394			console.log(res.data.error);
1395			if (callback) {
1396			    callback(res.data.error, buff);
1397			}
1398                    } else {
1399			console.log("Success");
1400			console.log("Success len = " + res.data.length);
1401			buff.data = res.data;
1402			res.arrayBuffer().then(function(buffer) {
1403				buff.data = buffer;
1404				
1405			     $scope.mtrack_context.decodeAudioData(buff.data, function(buffer) {
1406			         console.log("Decoded Audio");	
1407			         buff.buffer = buffer;
1408			     if (callback) {
1409			        callback(res.data.error, buff);
1410			     }
1411			   }, function(err) {
1412				console.log(err);
1413			     if (callback) {
1414			        callback(err, null);
1415			     }
1416			   }) ;
1417			});
1418                        //$scope.mtrack = JSON.parse(res.data);
1419                    }
1420                }, function(err) {
1421			if (callback) {
1422			    callback(err, buff);
1423			}
1424			console.log(err);
1425                });
1426
1427     }
1428     $scope.mtrack_queue_one = function(interval,sec,  cb) {
1429	    var interval_waiting = 0;
1430	    for(var tt = 0; tt < $scope.tracklist.length; tt++) {
1431		if ($scope.tracklist[tt].intervals.length > interval) {
1432		if ($scope.tracklist[tt].intervals[interval].fname && $scope.tracklist[tt].type == "audio") {
1433		   console.log($scope.tracklist[tt].intervals[interval].fname);
1434		   var buff;
1435		   if ($scope.tracklist[tt].intervals[interval].buff ) {
1436		       buff = $scope.tracklist[tt].intervals[interval].buff ;
1437		   } else {
1438		       $scope.tracklist[tt].intervals[interval].buff = {};
1439		       buff = $scope.tracklist[tt].intervals[interval].buff ;
1440 		   }
1441		   buff.fname = $scope.tracklist[tt].intervals[interval].fname;
1442		   buff.id = $scope.tracklist[tt].id;
1443		   buff.interval = interval;
1444		   buff.user = $scope.tracklist[tt].user;
1445		   buff.status = "start";
1446		   $scope.tracklist[tt].intervals[interval].buff = buff;
1447		   interval_waiting++;
1448     		   $scope.mtrack_read(buff, function(err, buff){
1449			if (err) {
1450			   buff.error = err;
1451		   	   interval_waiting--;
1452			   buff.status = "error";
1453			} else {
1454			   //console.log("Buffer read " + buff.id);
1455			   buff.status = "ready"
1456		   	   interval_waiting--;
1457			   buff.error = null;
1458			}
1459			if (interval_waiting == 0) {
1460			   //console.log("Interval complete " + buff.interval);
1461			   if (cb) {
1462				cb(buff.interval, sec);	
1463			   }
1464			}
1465		   });
1466		   //console.log(buff);
1467		}
1468		}
1469	    }
1470
1471     }
1472     $scope.mtrack_queue = function(cb) {
1473	for(var ii = $scope.mtrack_current_pos; ii <= $scope.mtrack.length; ii++) {
1474	    for(var tt = 0; tt < $scope.tracklist.length; tt++) {
1475		if ($scope.tracklist[tt].intervals.length > ii) {
1476		if ($scope.tracklist[tt].intervals[ii -1].fname) {
1477		   console.log($scope.tracklist[tt].intervals[ii -1].fname);
1478		   var buff = {};
1479		   buff.fname = $scope.tracklist[tt].intervals[ii -1].fname;
1480		   buff.id = $scope.tracklist[tt].id;
1481		   buff.interval = ii;
1482		   buff.user = $scope.tracklist[tt].user;
1483		   buff.status = "start";
1484     		   $scope.mtrack_read(buff);
1485	
1486		}
1487		}
1488	    }
1489	    
1490	}	
1491/*
1492	while(1) {
1493	    var buffer = mtrack_pool_get_buffer();
1494	     
1495	    if (!buffer) break;
1496
1497        }
1498*/
1499/*
1500	while(var buffer = $scope.mtrack_buffer_get()) {
1501	    console.log("Got buffer");
1502	}
1503	
1504*/
1505
1506     }
1507     $scope.mtrack_queue_next = function(cb) {
1508     }
1509  
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521     $scope.mtrack_audio_init = function() {
1522/*
1523	console.log("Initing Audio");
1524	if ($scope.mtrack_context) return;
1525    	$scope.mtrack_context = new AudioContext();
1526        $scope.mtrack_source1 = $scope.mtrack_context.createBufferSource();
1527        $scope.mtrack_source1Gain = $scope.mtrack_context.createGain();
1528*/
1529
1530     }
1531    $scope.mtrack_audio.stop = function()
1532    {
1533        if (!$scope.mtrack_audio.isPlaying) return(0);
1534
1535        $scope.mtrack_audio.isPlaying = 0;
1536        $scope.mtrack_mixer.playPos = $scope.mtrack_mixer.playPosCurrent;
1537        for (var i = 0; i < $scope.mtrack_audio.data.length; i++)
1538        {
1539            for (var k = 0; k < $scope.mtrack_mixer.numIntervals; k++) {
1540            if ( $scope.mtrack_audio.audioSource[i] &&  $scope.mtrack_audio.audioSource[i][k]) {
1541    
1542    // console.log("Stopping " + i + " interval " + k);
1543                //appMixer.audioSource[i][k].noteOff(0);
1544                $scope.mtrack_audio.audioSource[i][k].stop(0);
1545                $scope.mtrack_audio.audioSource[i][k].disconnect($scope.mtrack_audio.audioGain[i]);
1546                $scope.mtrack_audio.audioSource[i][k] = 0;
1547            } else {
1548            }
1549            }
1550        }
1551
1552    }
1553     $scope.mtrack_audio.playInitControls = function()
1554     {
1555
1556
1557// console.log("Creating context and everything");
1558//      $scope.mtrack_audio.audioContext = new webkitAudioContext();
1559        $scope.mtrack_audio.audioContext = new AudioContext();
1560
1561// console.log("SAMPLE RATE is " +  $scope.mtrack_audio.audioContext.sampleRate);
1562        $scope.mtrack_audio.masterGain = $scope.mtrack_audio.audioContext.createGain();
1563        $scope.mtrack_audio.masterGain.connect($scope.mtrack_audio.audioContext.destination);
1564        $scope.mtrack_audio.masterLevel = $scope.mtrack_audio.audioContext.createAnalyser();
1565        $scope.mtrack_audio.masterLevel.smoothingTimeConstant = 0.3;
1566        $scope.mtrack_audio.masterLevel.fftSize = 128;
1567        $scope.mtrack_audio.masterGain.connect($scope.mtrack_audio.masterLevel);
1568
1569        for (var i = 0; i < $scope.mtrack_audio.data.length; i++)
1570    	{
1571            var gain  = $scope.mtrack_audio.audioContext.createGain();
1572            $scope.mtrack_audio.audioGain[i] = gain;
1573
1574            var pan   = $scope.mtrack_audio.audioContext.createPanner();
1575            var x = (i / $scope.mtrack_audio.data.length) * 20 - (100);
1576            var x = 0;
1577            var y = 0;
1578            var z = 3.;
1579            pan.panningModel = 'equalpower';
1580            pan.setPosition(0, 0, 0);
1581            $scope.mtrack_audio.audioPan[i] = pan;
1582            // pan.maxDistance = 100;
1583    
1584            var meter = $scope.mtrack_audio.audioContext.createAnalyser();
1585            $scope.mtrack_audio.audioMeter[i] = meter;
1586            meter.smoothingTimeConstant = 0.3;
1587            meter.fftSize = 128;
1588    
1589            var numSource = 2;
1590            numSource = $scope.mtrack_mixer.numIntervals;
1591            $scope.mtrack_audio.audioSource[i] = new Array(numSource);
1592            $scope.mtrack_audio.audioLoaded[i] = new Array(numSource);
1593            $scope.mtrack_audio.audioBuffer[i] = new Array(numSource);
1594            for (var k = 0; k < numSource ; k++) {
1595                $scope.mtrack_audio.audioLoaded[i][k] = 0;
1596            }
1597            gain.connect(pan);
1598            if ($scope.mtrack_audio.masterGain) {
1599                pan.connect($scope.mtrack_audio.masterGain);
1600            } else {
1601                pan.connect($scope.mtrack_audio.audioContext.destination);
1602            }
1603            gain.connect(meter);
1604           }
1605/*
1606        $scope.mtrack_audio.stop();
1607        $scope.mtrack_audio.updateAudio();
1608        $scope.mtrack_audio.playStartPos = $scope.mtrack_audio.playPos;
1609        $scope.mtrack_audio.isPlaying = 1;
1610        $scope.mtrack_audio.isCue = 1;
1611
1612        $scope.mtrack_audio.loadInterval($scope.mtrack_mixer.readBuffer);
1613        $scope.mtrack_audio.playLoop();
1614*/
1615
1616
1617     }
1618
1619     $scope.mtrack_audio.playFrom = function(start)
1620     {
1621         $scope.mtrack_mixer.readBuffer =  Math.floor($scope.mtrack_mixer.playPos);
1622         $scope.mtrack_mixer.playBuffer =  Math.floor($scope.mtrack_mixer.playPos);
1623 // console.log("PlayFrom " + start + " Pos = " + $scope.mtrack_mixer.readBuffer);
1624    if ($scope.mtrack_audio.audioContext == 0) {
1625
1626
1627// console.log("Creating context and everything");
1628//      $scope.mtrack_audio.audioContext = new webkitAudioContext();
1629        $scope.mtrack_audio.audioContext = new AudioContext();
1630
1631// console.log("SAMPLE RATE is " +  $scope.mtrack_audio.audioContext.sampleRate);
1632        $scope.mtrack_audio.masterGain = $scope.mtrack_audio.audioContext.createGain();
1633        $scope.mtrack_audio.masterGain.connect($scope.mtrack_audio.audioContext.destination);
1634        $scope.mtrack_audio.masterLevel = $scope.mtrack_audio.audioContext.createAnalyser();
1635        $scope.mtrack_audio.masterLevel.smoothingTimeConstant = 0.3;
1636        $scope.mtrack_audio.masterLevel.fftSize = 128;
1637        $scope.mtrack_audio.masterGain.connect($scope.mtrack_audio.masterLevel);
1638
1639        for (var i = 0; i < $scope.mtrack_audio.data.length; i++)
1640    	{
1641            var gain  = $scope.mtrack_audio.audioContext.createGain();
1642            $scope.mtrack_audio.audioGain[i] = gain;
1643
1644            var pan   = $scope.mtrack_audio.audioContext.createPanner();
1645            var x = (i / $scope.mtrack_audio.data.length) * 20 - (100);
1646            var x = 0;
1647            var y = 0;
1648            var z = 3.;
1649            pan.panningModel = 'equalpower';
1650            pan.setPosition(0, 0, 0);
1651            $scope.mtrack_audio.audioPan[i] = pan;
1652            // pan.maxDistance = 100;
1653    
1654            var meter = $scope.mtrack_audio.audioContext.createAnalyser();
1655            $scope.mtrack_audio.audioMeter[i] = meter;
1656            meter.smoothingTimeConstant = 0.3;
1657            meter.fftSize = 128;
1658    
1659            var numSource = 2;
1660            numSource = $scope.mtrack_mixer.numIntervals;
1661            $scope.mtrack_audio.audioSource[i] = new Array(numSource);
1662            $scope.mtrack_audio.audioLoaded[i] = new Array(numSource);
1663            $scope.mtrack_audio.audioBuffer[i] = new Array(numSource);
1664            for (var k = 0; k < numSource ; k++) {
1665                $scope.mtrack_audio.audioLoaded[i][k] = 0;
1666            }
1667            gain.connect(pan);
1668            if ($scope.mtrack_audio.masterGain) {
1669                pan.connect($scope.mtrack_audio.masterGain);
1670            } else {
1671                pan.connect($scope.mtrack_audio.audioContext.destination);
1672            }
1673            gain.connect(meter);
1674           }
1675        }
1676        $scope.mtrack_audio.stop();
1677        $scope.mtrack_audio.updateAudio();
1678        $scope.mtrack_audio.playStartPos = $scope.mtrack_audio.playPos;
1679        $scope.mtrack_audio.isPlaying = 1;
1680        $scope.mtrack_audio.isCue = 1;
1681
1682        $scope.mtrack_audio.loadInterval($scope.mtrack_mixer.readBuffer);
1683        $scope.mtrack_audio.playLoop();
1684
1685    }
1686/*
1687    $scope.mtrack_animate = function() {
1688console.log("Mtrack_animate");
1689	$scope.mtrack_update();
1690        if ($scope.mtrack_playing) {
1691	      requestAnimFrame($scope.mtrack_animate);
1692	}
1693    }
1694*/
1695
1696    $scope.mtrack_update = function() {
1697	console.log("Mtrack Update called");
1698         //var mlevel = $scope.mtrack_levelCalc('master');
1699         //var mlevel = $scope.mtrack_levelCalc(0);
1700	//console.log("Master Level " + mlevel);
1701    }
1702    $scope.mtrack_levelCalc = function(which) {
1703	var freqdata;
1704	which = "master";
1705        if (which == 'master') {
1706            freqData = new Uint8Array($scope.mtrack.masterLevel.frequencyBinCount);
1707            $scope.mtrack.masterLevel.getByteFrequencyData(freqData);
1708        } else {
1709	var meter = $scope.tracklist[which].audio.meter;
1710/*
1711	var meter = $scope.mtrack_audio.audioMeter[which];
1712*/
1713            freqData = new Uint8Array(meter.frequencyBinCount);
1714            meter.getByteFrequencyData(freqData);
1715        }
1716  // Put the raw frequency into the newly created array
1717        var max = 0;
1718        var offset = 0;
1719        for (var i = 0; i < freqData.length - offset; i+=8) {
1720            if (i == 0) {
1721                max = freqData[i + offset];
1722            }
1723            if (freqData[i + offset] > max) max = freqData[i + offset];
1724        }
1725        var f = max / 255.;
1726        if (f > 1) f = 1.;
1727        return(f);
1728    }
1729
1730
1731    $scope.mtrack_audio.play = function()
1732    {
1733        if ($scope.mtrack_audio.isPlaying) {
1734           $scope.mtrack_audio.stop();
1735        }
1736	if (!$scope.mtrack_mixer.playPos) {
1737	    $scope.mtrack_mixer.playPos = 0;
1738	}
1739        $scope.mtrack_audio.playFrom($scope.mtrack_mixer.playPos);
1740        $scope.mtrack_audio.animate();
1741    }
1742    $scope.metadata = [
1743	{ name:"meta_title", desc:"Title" },
1744	{ name:"meta_desc", desc:"Description", type:"textarea" },
1745	{ name:"mtrack_in", desc:"In Point" },
1746	{ name:"mtrack_out", desc:"Out Point" },
1747	{ name:"meta_in_trans", desc:"In/Transition", type:"menu", menu:[{name:"none", desc:"None"}, {name:"linear-1", desc:"1 Second Linear"} ] },
1748	{ name:"meta_out_trans", desc:"Out/Transition", type:"menu", menu:[{name:"none", desc:"None"}, {name:"linear-1", desc:"1 Second Linear"} ] },
1749	{ name:"meta_share", desc:"Sharing", type:"menu", menu:[{name:"private", desc:"Private"}, {name:"unlisted", desc:"Unlisted"}, {name:"public", desc:"Public"} ] },
1750/*
1751	{ name:"meta_in_trans", desc:"out/Transition", menu:[{name:"none", desc:"None"}, {name:"linear-1", "1 Second Linear"} ] },
1752
1753	{ name:"meta_public", desc:"Public/Private", menu:[{name:"public", desc:"Public"}, {name:"private", "Private"} ] }
1754
1755*/
1756
1757    ];
1758
1759    $scope.mtrack_ready = function() {
1760 	
1761/* 
1762	setTimeout(function() {
1763	
1764	var query = $location.search();
1765	if (query.time) {
1766     	       $scope.mtrack_seek(query.time);
1767	} 
1768	}, 1000);
1769*/
1770
1771    } 
1772    $scope.mtrack_render = function() {
1773	var query = $location.search();
1774	$scope.render = {};
1775	let ss = query.track.lastIndexOf(".");
1776	$scope.render.song = query.track.substr(0, ss);
1777	let list = [];
1778	for (var ii =0; ii < $scope.tracklist.length;ii++) {
1779	    let obj = {}
1780	    obj.id = $scope.tracklist[ii].id;
1781	    obj.chan = $scope.tracklist[ii].chan;
1782	    obj.type = $scope.tracklist[ii].type;
1783	    obj.user = $scope.tracklist[ii].user;
1784	    obj.gain = $scope.tracklist[ii].gain;
1785	    list.push(obj);
1786	}
1787	$scope.render.tracklist = list;
1788	//$scope.render.metadata = $scope.metadata;
1789	let mdata = {};
1790	for(var ii = 0;ii < $scope.metadata.length; ii++) {
1791	    mdata[$scope.metadata[ii].name] = $scope[$scope.metadata[ii].name];
1792	}
1793	$scope.render.metadata = mdata;
1794 	$http({
1795            url: '/mtrack',
1796            method: "POST",
1797            data: $scope.render
1798        })
1799        .then(function(response) {
1800            // success
1801        }, 
1802        function(response) { // optional
1803            // failed
1804        });
1805
1806    }
1807    setTimeout( function() {
1808	var query = $location.search();
1809
1810	if (query.page ==  "mtrack") {
1811	   var s = query.track;
1812/*
1813	   if (s && s.indexOf(":")) {
1814	    	return;
1815	   }
1816*/
1817           $scope.player_stop();
1818//	   console.log("EDIT SONG " +s);
1819/*
1820	   if (query.time) {
1821     	       $scope.mtrack_seek(query.time);
1822	   } 
1823*/
1824           $scope.mtrack_edit_song(s);
1825	}
1826    }, 1000);
1827
1828
1829		
1830 });

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.