Files
homeclaw/web-ui/audiomass/ui.js
T
kimandClaude Opus 5 e85ebe6608 v4.3.20: 미커밋 자산 일괄 정리 + 유저 워크스페이스/세션토큰 gitignore
그동안 쌓여 있던 미커밋 파일들을 정리. 소스·자산만 올리고, 개인 데이터와
런타임 상태는 gitignore로 차단.

추가된 자산:
- web-ui/audiomass, web-ui/wavacity — 자체 호스팅 오디오 에디터
- web-ui/drums — 드럼 샘플
- wol-gate — WOL 프록시 컨테이너(Dockerfile + server.js)
- glm-1m-fix — GLM 1M 컨텍스트 설치 스크립트(linux/windows)
- RENODE_FIXES_SUMMARY*.md, CCTV정보_서울특별시.csv, .claude/plans

수정:
- edge_tts_synth.py: rate 인자 추가(말하기 속도 조절)
- .smallclaw/config.json: google(gemini) provider 등록 — 키는 vault 참조
- assets/SmallClaw*.png 삭제분 반영

gitignore (중요):
- .smallclaw/users/*/workspace/ 전체 차단. 기존 패턴이 memory/uploads와 일부
  확장자만 막아서 detective/(고소장·통화녹취·의사소견서·가족관계증명서),
  generated-media/, music/, pptx/ 등 앱 생성 개인 데이터 403MB가 노출돼 있었음
- .smallclaw/active-sessions.json 차단 — 살아있는 bearer 토큰과 admin 역할이
  평문으로 들어있어 커밋 시 게이트웨이 관리자 자격증명이 그대로 공개됨
- google-usage.json, config.json.bak-*, workspace/memory·weather-maps·
  task_result_*, voice/ 등 런타임 상태도 함께 차단

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 14:55:37 +09:00

3704 lines
108 KiB
JavaScript
Executable File

(function ( w, d, PKAE ) {
'use strict';
//
// MAIN UI CLASS
function activeMultitrackFor ( app ) {
var mt = (app && app.multitrack) || (PKAE && PKAE.multitrack);
var root = (app && app.el) || (PKAE && PKAE.el);
return mt &&
mt.IsOn &&
(mt.IsOn () || (root && root.classList.contains ('pk_mt_on'))) ?
mt :
null;
}
function activeCursorTimeFor ( app ) {
var mt = activeMultitrackFor ( app );
var ws = app.engine && app.engine.wavesurfer;
return mt ? mt.GetCursor () : (ws ? ws.getCurrentTime () : 0);
}
function activeDurationFor ( app ) {
var mt = activeMultitrackFor ( app );
var ws = app.engine && app.engine.wavesurfer;
return mt ? mt.GetDuration () : (ws ? ws.getDuration () : 0);
}
function activeRegionFor ( app ) {
var mt = activeMultitrackFor ( app );
var ws = app.engine && app.engine.wavesurfer;
return mt && mt.GetRegion ? mt.GetRegion () :
(ws && ws.regions ? ws.regions.list[0] : null);
}
function activeZoomFor ( app ) {
var mt = activeMultitrackFor ( app );
var ws = app.engine && app.engine.wavesurfer;
return mt ?
(mt.GetSeekZoomFactor ? mt.GetSeekZoomFactor () : mt.GetZoomFactor ()) :
(ws ? ws.ZoomFactor : 1);
}
function activeSeekRampFor ( app ) {
return 0.15;
}
function activeSeekWarmupFor ( app ) {
return 2;
}
function activeReadyFor ( app ) {
return !!activeMultitrackFor ( app ) ||
!!(app.engine && app.engine.is_ready);
}
function seekMarkerEdgeFor ( app, dir ) {
return !!(app.mrk && app.mrk.edge && app.mrk.edge (dir));
}
function seekRegionMarkerEdgeFor ( app, dir ) {
var mt = activeMultitrackFor ( app );
var r = activeRegionFor ( app );
var total = activeDurationFor ( app );
var pos, start, end;
if (r && total > 0) {
pos = mt ? (mt.GetMarker ? mt.GetMarker () : mt.GetCursor ()) :
app.engine.wavesurfer.ActiveMarker;
start = mt ? r.start : r.start / total;
end = mt ? r.end : r.end / total;
if (dir < 0) {
if (pos > end + 0.004) {
app.fireEvent ('RequestSeekTo', (r.end / total) - 0.0001);
return true;
}
if (pos > start + 0.004) {
app.fireEvent ('RequestSeekTo', r.start / total);
return true;
}
}
else {
if (pos < start - 0.004) {
app.fireEvent ('RequestSeekTo', r.start / total);
return true;
}
if (pos < end - 0.004) {
app.fireEvent ('RequestSeekTo', r.end / total);
return true;
}
}
}
if (seekMarkerEdgeFor (app, dir)) return true;
app.fireEvent ('RequestSeekTo', dir < 0 ? 0 : 1);
return true;
}
var PKUI = function( app ) {
var q = this;
this.el = app.el;
// if mobile add proper class
this.el.className += ' pk_app' + (app.isMobile ? ' pk_mob' : '');
// hold refferences to the event functions
this.fireEvent = app.fireEvent;
this.listenFor = app.listenFor;
// keep track of the active UI element
this.InteractionHandler = {
on : false,
by : null,
arr : [],
check: function ( _name ) {
if (this.on && this.by !== _name) {
return (false);
}
return (true);
},
checkAndSet: function ( _name ) {
if (!this.check (_name))
return (false);
this.on = true;
this.by = _name;
return (true);
},
forceSet: function ( _name ) {
if (this.on)
{
this.arr.push ({
on: this.on,
by: this.by
});
}
this.on = true;
this.by = _name;
},
forceUnset: function ( _name ) {
if (this.check (_name))
{
var prev = this.arr.pop ();
if (prev)
{
this.on = prev.on;
this.by = prev.by;
}
else
{
this.on = false;
this.by = null;
}
}
// ---
}
};
if (app.isMobile)
{
d.body.className = 'pk_stndln';
var fxd = d.createElement ('div');
fxd.className = 'pk_fxd';
fxd.appendChild (this.el);
d.body.appendChild (fxd);
_makeMobileScroll (this);
}
this.KeyHandler = new app._deps.keyhandler ( this ); // initializing keyhandler
this.TopHeader = new _makeUITopHeader ( _topbarConfig ( app ), this ); // topmost menu
this.Toolbar = new _makeUIToolbar ( this ); // main toolbar and controls
this.footer = new _makeUIMainView ( this, app );
this.BarBtm = new _makeUIBarBottom (this, app);
this.MainHeight = function () {
var root = this.el;
var h = root.clientHeight || (app.isMobile && w.visualViewport ? w.visualViewport.height : w.innerHeight);
var used = 0;
var hdr = root.getElementsByClassName ('pk_hdr')[0];
var tbc = root.getElementsByClassName ('pk_tbc')[0];
var ftr = root.getElementsByClassName ('pk_ftr')[0];
if (hdr) used += hdr.offsetHeight;
if (tbc) used += tbc.offsetHeight;
if (ftr) used += ftr.offsetHeight;
if (this.BarBtm && this.BarBtm.on) used += this.BarBtm.height;
return Math.max (112, h - used);
};
if (app.isMobile && w.visualViewport) {
var resize_raf = 0;
w.visualViewport.addEventListener ('resize', function () {
if (resize_raf) return ;
resize_raf = w.requestAnimationFrame (function () {
resize_raf = 0;
app.fireEvent ('RequestResize');
});
});
}
this.Dock = function ( id, arg1, arg2 ) {
app.fireEvent (id, arg1, arg2);
};
this.GetActiveCursor = function () {
return activeCursorTimeFor ( app );
};
app.listenFor ('ShowError', function( message ) {
new PKSimpleModal ({
title : 'Oops! Something is not right',
clss:'pk_modal_anim',
ondestroy : function( q ) {
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('modalTempErr');
},
buttons:[],
body:'<p>' + message + '</p>',
setup:function( q ) {
app.fireEvent ('RequestPause');
app.fireEvent( 'RequestRegionClear');
app.ui.InteractionHandler.checkAndSet ('modal');
app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) {
q.Destroy ();
}, [27]);
}
}).Show ();
});
app.listenFor ('RequestKeyDown', function ( key ) {
q.KeyHandler.keyDown ( key, null );
q.KeyHandler.keyUp ( key );
});
};
//top bar config list
function _topbarConfig ( app, ui ) {
return [
{
name:'File',
children : [
{
name: 'Export / Download',
action: function () {
new PKSimpleModal({
title:'Export / Download',
ondestroy: function( q ) {
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('modalTemp');
},
buttons:[
{
title:'Export',
clss:'pk_modal_a_accpt',
callback: function( q ) {
var input = q.el_body.getElementsByTagName('input')[0];
var value = input.value.trim();
var format = 'mp3';
var kbps = 128;
var export_sel = false;
var stereo = false;
var bit_depth = 16;
var radios = q.el_body.getElementsByClassName ('pk_check');
var l = radios.length;
while (l-- > 0) {
if (radios[l].checked)
{
if (radios[l].name == 'frmtex')
{
format = radios[l].value;
}
else if (radios[l].name == 'xport')
{
if (radios[l].value === 'sel')
{
var region = activeRegionFor ( app );
if (!region) export_sel = false;
else export_sel = [region.start, region.end];
}
}
else if (radios[l].name == 'chnl')
{
if (radios[l].value === 'stereo')
{
stereo = true;
}
}
else if (radios[l].name == 'wavbits')
{
bit_depth = radios[l].value / 1;
}
else
{
kbps = radios[l].value / 1;
}
}
}
var dither_chk = document.getElementById ('wav-dither');
var dither = !!(dither_chk && dither_chk.checked);
if (format === 'amss')
{
var mt = activeMultitrackFor ( app );
if (mt) mt.ExportSession ( value );
q.Destroy ();
return ;
}
if (format == 'flac')
{
kbps = document.getElementById('flac-comp').value / 1;
}
app.engine.DownloadFile ( value, format, kbps, export_sel, stereo, bit_depth, dither );
q.Destroy ();
// -
}
}
],
body:'<div class="pk_row"><label for="k0">File Name</label>' +
'<input style="min-width:250px" placeholder="mp3 filename" value="audiomass-output.mp3" ' +
'class="pk_txt" type="text" id="k0" /></div>'+
'<div class="pk_row" id="frmtex" style="padding-bottom:4px"><label style="display:inline">Format</label>'+
'<input type="radio" class="pk_check" id="k01" name="frmtex" checked value="mp3">'+
'<label for="k01">mp3</label>' +
'<input type="radio" class="pk_check" id="k02" name="frmtex" value="wav">'+
'<label for="k02">wav <i>(44100hz)</i></label>' +
'<input type="radio" class="pk_check" id="k03" name="frmtex" value="flac">'+
'<label for="k03">flac</i></label>' +
'<br class="pk_amss"><input type="radio" class="pk_check pk_amss" id="k04" name="frmtex" value="amss">'+
'<label class="pk_amss" for="k04">session file (.amss)</label>' +
'</div>' +
'<div class="pk_row" id="frmtex-mp3"><input type="radio" class="pk_check" id="k1" name="rdslnc" checked value="128">'+
'<label for="k1">128kbps</label>' +
'<input type="radio" class="pk_check" id="k2" name="rdslnc" value="192">'+
'<label for="k2">192kbps</label>'+
'<input type="radio" class="pk_check" id="k3" name="rdslnc" value="256">'+
'<label for="k3">256kbps</label></div>'+
'<div class="pk_row" style="display:none" id="frmtex-flac">'+
'<label>Flac: Compression Level</label>'+
'<input type="range" class="pk_horiz" min="0" max="8" step="1" value="5" id="flac-comp">'+
'<span class="pk_val" style="float:left;margin-left:15px">5</span></div>' +
'<div class="pk_row" style="display:none" id="frmtex-wav">'+
'<input type="radio" class="pk_check" id="kwb1" name="wavbits" checked value="16">'+
'<label for="kwb1">16-bit</label>'+
'<input type="radio" class="pk_check" id="kwb2" name="wavbits" value="24">'+
'<label for="kwb2">24-bit</label>'+
'<input type="radio" class="pk_check" id="kwb3" name="wavbits" value="32">'+
'<label for="kwb3">32-bit float</label>'+
'<div id="wav-dither-wrap" style="margin-top:6px">'+
'<input type="checkbox" class="pk_check" id="wav-dither">'+
'<label for="wav-dither">TPDF dither</label>'+
'</div></div>' +
'<div class="pk_row" style="padding-bottom:5px">' +
'<input type="radio" class="pk_check" id="k6" name="chnl" checked value="mono">'+
'<label for="k6">Mono</label>'+
'<input type="radio" class="pk_check pk_stereo" id="k7" name="chnl" value="stereo">'+
'<label for="k7">Stereo</label>'+
'</div>'+
'<div class="pk_row">' +
'<input type="radio" class="pk_check" id="k4" name="xport" checked value="whole">'+
'<label for="k4">Export whole file</label>'+
'<input type="radio" class="pk_check" id="k5" name="xport" value="sel">'+
'<label class="pk_lblmp3" for="k5">Export Selection Only</label></div>',
setup:function( q ) {
var wv = PKAudioEditor.engine.wavesurfer;
var mt_on = activeMultitrackFor ( app );
// if no region
var region = activeRegionFor ( app );
if (!region) {
var lbl = q.el_body.getElementsByClassName('pk_lblmp3')[0];
lbl.className = 'pk_dis';
}
var chan_num = mt_on ? 2 :
(wv.backend.buffer ? wv.backend.buffer.numberOfChannels : 1);
if (chan_num === 2) {
q.el_body.getElementsByClassName('pk_stereo')[0].checked = true;
}
app.fireEvent ('RequestPause');
app.ui.InteractionHandler.checkAndSet ('modal');
app.ui.KeyHandler.addCallback ('modalTemp', function ( e ) {
q.Destroy ();
}, [27]);
setTimeout(function() {
if (!q.el) return ;
var inputtxt = q.el.getElementsByTagName('input')[0];
inputtxt && inputtxt.select ();
var format = document.getElementById('frmtex');
var mp3conf = document.getElementById('frmtex-mp3');
var flacconf = document.getElementById('frmtex-flac');
var wavconf = document.getElementById('frmtex-wav');
var ditherWrap = document.getElementById('wav-dither-wrap');
var amss = q.el_body.getElementsByClassName ('pk_amss');
function setDitherFor ( bits ) {
var on = bits === 16;
document.getElementById('wav-dither').disabled = !on;
ditherWrap.classList.toggle ('pk_inact', !on);
}
function showConf ( m, f, w ) {
mp3conf.style.display = m ? 'block' : 'none';
flacconf.style.display = f ? 'block' : 'none';
wavconf.style.display = w ? 'block' : 'none';
}
var k6 = document.getElementById ('k6');
var k7 = document.getElementById ('k7');
if (!mt_on) {
for (var x = 0; x < amss.length; ++x)
amss[x].style.display = 'none';
}
function setExt ( ext ) {
inputtxt.value = inputtxt.value.replace (/\.(mp3|wav|flac|amss)$/i, '') + ext;
}
function chanOff ( off ) {
k6.disabled = k7.disabled = !!off;
}
if (mt_on) {
document.getElementById ('k01').checked = true;
showConf (1, 0, 0);
chanOff ( false );
setExt ('.mp3');
}
document.getElementById('flac-comp').oninput = function() {
this.parentNode.getElementsByTagName('span')[0].innerText = this.value;
};
setDitherFor (16);
wavconf.addEventListener ('change', function () {
var ws = wavconf.getElementsByTagName ('input');
for (var i = 0; i < ws.length; ++i)
if (ws[i].name === 'wavbits' && ws[i].checked) {
setDitherFor (ws[i].value / 1);
break;
}
}, false);
format && format.addEventListener('change', function(e){
var inputs = this.getElementsByTagName('input');
for (var i = 0; i < inputs.length; ++i)
{
if (inputs[i].checked)
{
var v = inputs[i].value;
chanOff (v === 'amss');
showConf (v === 'mp3', v === 'flac', v === 'wav');
setExt ('.' + v);
}
}
}, false);
},20);
}
}).Show();
},
clss: 'pk_inact',
setup: function ( obj ) {
obj.setAttribute('data-id', 'dl');
function setExportReady () {
var mt = activeMultitrackFor ( app );
if (mt || (app.engine && app.engine.is_ready))
obj.classList.remove ('pk_inact');
else
obj.classList.add ('pk_inact');
}
app.listenFor ('DidUnloadFile', setExportReady);
app.listenFor ('DidLoadFile', setExportReady);
app.listenFor ('DidUpdateMultitrack', setExportReady);
setExportReady ();
}
},
{
name: 'Load from Computer',
type: 'file',
action: function ( e ) {
app.fireEvent ('RequestLoadLocalFile');
}
},
{
name: 'Load Sample File',
action: function ( e ) {
if (app.fireEvent ('RequestLoadSampleFile') !== true)
app.engine.LoadSample ('test.mp3');
}
},
{
name: 'Load From URL',
action: function ( e ) {
new PKSimpleModal({
title:'Load audio from remote url',
ondestroy: function( q ) {
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('modalTemp');
app.ui.KeyHandler.removeCallback ('modalTempEnter');
},
buttons:[
{
title:'Load Asset',
clss:'pk_modal_a_accpt',
callback: function( q ) {
var input = q.el_body.getElementsByTagName('input')[0];
var value = input.value.trim();
function isURL ( str ) {
var pattern = new RegExp('^((https?:)?\\/\\/)?'+ // protocol
'(?:\\S+(?::\\S*)?@)?' + // authentication
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
'((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
'(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
'(\\#[-a-z\\d_]*)?$','i'); // fragment locater
if (!pattern.test(str)) {
return false;
} else {
return true;
}
};
if (isURL (value))
{
// LOAD FROM URL....
if (app.fireEvent ('RequestLoadURL', value) !== true)
app.engine.LoadURL ( value );
q.Destroy ();
}
else
{
OneUp ('Invalid URL entered', 1100);
}
// -
}
}
],
body:'<label for="k00">Insert url</label>' +
'<input style="min-width:250px" placeholder="Please insert url" class="pk_txt" type="text" id="k00" />',
setup:function( q ) {
app.fireEvent ('RequestPause');
app.ui.InteractionHandler.checkAndSet ('modal');
app.ui.KeyHandler.addCallback ('modalTemp', function ( e ) {
q.Destroy ();
}, [27]);
app.ui.KeyHandler.addCallback ('modalTempEnter', function ( e ) {
q.els.bottom[0].click ();
}, [13]);
setTimeout(function() {
q.el && q.el.getElementsByTagName('input')[0].focus ();
},20);
}
}).Show();
}
// ---
},
{
name: 'New Recording',
action: function ( e ) {
app.fireEvent('RequestActionNewRec');
}
},
{
name: 'Save Draft Locally',
clss: 'pk_inact',
action: function ( e ) {
if (!app.engine.is_ready) return ;
var saving = function ( type, name ) {
var buff = app.engine.wavesurfer.backend.buffer;
if (type === 'copy') buff = app.engine.GetCopyBuff ();
else if (type === 'sel') buff = app.engine.GetSel ();
var func = function ( fls ) {
var rr = Math.random().toString(36).substring(7);
fls.SaveSession (buff, rr, name);
app.stopListeningFor ('DidOpenDB', func);
};
app.listenFor ('DidOpenDB', func);
if (!app.fls.on) app.fls.Init (function(err){if(err){alert("db error")}});
else app.fireEvent ('DidOpenDB', app.fls);
};
// modal that asks for - full file, selection, copy buffer
new PKSimpleModal ({
title : 'Save Local Draft of...',
ondestroy : function( q ) {
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('modalTempErr');
},
buttons:[
{
title:'Save',
clss:'pk_modal_a_accpt',
callback: function( q ) {
var type = 'whole';
var input = q.el_body.getElementsByTagName ('input');
var name = input[ input.length - 1 ].value;
if (name) {
name = name.trim ();
if (name.length >= 100) name = name.substr(0,99).trim();
if (name.length === 0) name = null;
}
else {
name = null;
}
for (var i = 0; i < input.length; ++i) {
if (input[i].checked)
{
type = input[i].value;
break;
}
}
saving (type, name);
q.Destroy ();
}
}
],
body:'<p>Please choose source...</p>' +
'<div class="pk_row"><input type="radio" class="pk_check" id="sl1" name="rdslnc" checked value="whole">'+
'<label style="vertical-align:top" for="sl1">Whole Track</label>' +
'<input type="radio" class="pk_check" id="sl2" name="rdslnc" value="sel">'+
'<label style="vertical-align:top" class="pk_lblsel" for="sl2">Selection'+
'<i style="display:block;font-size:11px;margin-top:-5px"></i></label>'+
'<input type="radio" class="pk_check" id="sl3" name="rdslnc" value="copy">'+
'<label style="vertical-align:top" class="pk_lblsel2" for="sl3">"Copy" clipboard/buffer</label></div>'+
'<div class="pk_row"><label for="slk0">Draft Name</label>' +
'<input style="min-width:250px" placeholder="(optional) filename" maxlength="100" ' +
'class="pk_txt" type="text" id="slk0" /></div>',
setup:function( q ) {
// check if selection
var wv = app.engine.wavesurfer;
// if no region
var region = wv.regions.list[0];
var lblr = q.el_body.getElementsByClassName('pk_lblsel')[0];
if (!region) {
lblr.className = 'pk_dis';
} else {
q.el_body.getElementsByClassName('pk_check')[1].checked = true;
lblr.childNodes[1].textContent = app.ui.formatTime(region.start) + ' to ' + app.ui.formatTime(region.end);
}
// if no copy buffer
var copy = app.engine.GetCopyBuff ();
if (!copy) {
var lbl = q.el_body.getElementsByClassName('pk_lblsel2')[0];
lbl.className = 'pk_dis';
}
if (!app.isMobile)
{
setTimeout(function() {
q.el && q.el.getElementsByClassName('pk_txt')[0].focus ();
},20);
}
app.fireEvent ('RequestPause');
app.ui.InteractionHandler.checkAndSet ('modal');
app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) {
q.Destroy ();
}, [27]);
}
}).Show ();
return ;
},
setup: function ( obj ) {
app.listenFor ('DidUnloadFile', function () {
obj.classList.add ('pk_inact');
});
app.listenFor ('DidLoadFile', function () {
obj.classList.remove ('pk_inact');
});
app.listenFor ('DidStoreDB', function ( obj, e ) {
var name = obj.id;
var txt = '<div style="padding:2px 0">id: ' + name + '</div>'+
'<div style="padding:2px 0"><span>durr: ' + obj.durr + 's</span>'+
'&nbsp;&nbsp;&nbsp;'+
'<span>chan: ' + (obj.chans === 1 ? 'mono' : 'stereo') + '</span></div>'+
'<div style="padding:2px 0"><img src="' + obj.thumb + '" /></div>';
new PKSimpleModal ({
title : 'Succesfully Stored',
ondestroy : function( q ) {
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('modalTempErr');
},
buttons:[
{
title:'OPEN IN NEW WINDOW',
callback: function( q ) {
window.open ( window.location.pathname + '?local=' + name);
q.Destroy ();
}
}
],
body:'<p>Open in new window?</p>' + txt,
setup:function( q ) {
app.fireEvent ('RequestPause');
app.fireEvent( 'RequestRegionClear');
app.ui.InteractionHandler.checkAndSet ('modal');
app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) {
q.Destroy ();
}, [27]);
}
}).Show ();
});
}
},
{
name: 'Open Local Drafts',
action: function ( e ) {
var datenow = new Date ();
var time_ago = function ( arg ) {
var a = (datenow - arg) / 1E3 >> 0;
if (59 >= a) return datenow = 1 < a ? 's' : '', a + ' second' + datenow + ' ago';
if (60 <= a && 3599 >= a) return a = Math.floor(a / 60), a + ' minute' + (1 < a ? 's' : '') + ' ago';
if (3600 <= a && 86399 >= a) return a = Math.floor(a / 3600), a + ' hour' + (1 < a ? 's' : '') + ' ago';
if (86400 <= a && 2592030 >= a) return a = Math.floor(a / 86400), a + ' day' + (1 < a ? 's' : '') + ' ago';
if (2592031 <= a) return a = Math.floor(a / 2592E3), a + ' month' + (1 < a ? 's' : '') + ' ago';
};
var func = function ( fls ) {
fls.ListSessions(function( ret ) {
var msg = '';
if (ret.length === 0) {
msg += 'No drafts found...';
}
else
{
for (var i = 0; i < ret.length; ++i)
{
var curr = ret[i];
var date = new Date(curr.created);
var datestr = (date.getMonth()+1) + '/' +
date.getDate() + '/' +
date.getFullYear() + " " +
date.getHours() + ":" +
date.getMinutes() + ":" +
date.getSeconds();
var agostr = time_ago (date);
var filename = curr.name || '-';
var duration = curr.durr;
var thumb = curr.thumb;
var chns = (curr.chans === 1 ? 'mono' : 'stereo');
msg += '<div id="pk_' + curr.id + '" class="pk_lcldrf">'+
'<div style="padding-bottom:2px"><span><i class="pk_i">name:</i>' + filename + '</span></div>' +
'<div><span class="pk_lcls"><i class="pk_i">id:</i><strong>' + curr.id + '</strong><br/><i class="pk_i">chn:</i>'+ chns +'</span>' +
'<span class="pk_lcls" style="width:50%;text-align:center"><i class="pk_i">date:</i><span>' + datestr + '<br/>'+ agostr +'</span></span>' +
'<span style="text-align:right;float:right" class="pk_lcls"><i class="pk_i">durr:</i>' + duration + 's</span></div><div>' +
'<img class="pk_lcli" src="' + thumb + '" />' +
'<a class="pk_lcla2" onclick="PKAudioEditor.fireEvent(\'LoadDraft\',\'' + curr.id + '\', 3);">PLAY</a>' +
'<a class="pk_lcla" onclick="PKAudioEditor.fireEvent(\'LoadDraft\',\'' + curr.id + '\');">Open</a>';
if (app.engine.is_ready) {
msg += '<a onclick="PKAudioEditor.fireEvent(\'LoadDraft\',\'' + curr.id +
'\',1);" class="pk_lcla">Append to Current Track</a>';
}
msg += '<a class="pk_lcla" style="color:#ad2b2b" onclick="PKAudioEditor.fireEvent(\'LoadDraft\',\'' + curr.id + '\',2);">Del</a>';
msg += '</div></div>';
}
}
var modal;
var closeModal = function ( val, val2 ) {
if (val2 === 2 || val2 === 3) return ;
modal.Destroy ();
modal = null;
};
var set_act_btn = function ( name, state ) {
var act;
if (!state) {
act = modal.el_body.getElementsByClassName('pk_act')[0];
if (act) {
act.classList.remove ('pk_act');
}
}
else {
var el = document.getElementById ('pk_' + name);
if (el) {
act = el.getElementsByClassName ('pk_lcla2')[0];
act && act.classList.add ('pk_act');
}
}
// --
};
app.listenFor ('_lclStart', set_act_btn);
modal = new PKSimpleModal ({
title : 'Local Drafts',
clss : 'pk_bigger',
ondestroy : function( q ) {
app.fireEvent ('_lclStop');
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('modalTempErr');
app.stopListeningFor ('LoadDraft', closeModal);
app.stopListeningFor ('_lclStart', set_act_btn);
},
buttons:[],
body:'<div>' + msg + '</div>',
setup:function( q ) {
app.fireEvent ('RequestPause');
app.fireEvent( 'RequestRegionClear');
app.listenFor ('LoadDraft', closeModal);
app.ui.InteractionHandler.checkAndSet ('modal');
app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) {
q.Destroy ();
}, [27]);
}
});
modal.Show ();
});
app.stopListeningFor ('DidOpenDB', func);
};
app.listenFor ('DidOpenDB', func);
if (!app.fls.on) app.fls.Init (function(err){if(err){alert("db error")}});
else app.fireEvent ('DidOpenDB', app.fls);
},
setup: function () {
var source = {};
app.listenFor ('_lclStop', function ( name, append ) {
if (source.src) {
source.src.stop ();
source.src.disconnect ();
source.src.onended = null;
source.aud.close && source.aud.close ();
source = {};
}
});
app.listenFor ('LoadDraft', function ( name, append ) {
app.fls.Init (function (err) {
if (err) return ;
if (append === 2)
{
if (source.id === name)
{
app.fireEvent ('_lclStart', source.id, 0);
source.src.stop ();
source.src.disconnect ();
source.src.onended = null;
source.aud.close && source.aud.close ();
source = {};
}
app.fls.DelSession (name, function (name) {
var id = 'pk_' + name;
var el = document.getElementById (id);
if (el)
{
if ( el.parentNode.children.length === 1 ) {
el.parentNode.innerHTML = 'No drafts found...';
}
else el.parentNode.removeChild(el);
el = null;
}
});
return ;
}
if (append === 3)
{
if (source.id) {
var xt = false;
if (source.id === name) xt = true;
app.fireEvent ('_lclStart', source.id, 0);
source.src.stop ();
source.src.disconnect ();
source.src.onended = null;
source.aud.close && source.aud.close ();
source = {};
if (xt) return ;
}
// generate audio context here...
var aud_cont = new (w.AudioContext || w.webkitAudioContext)();
if (aud_cont && aud_cont.state == 'suspended') {
aud_cont.resume && aud_cont.resume ();
}
app.fls.GetSession (name, function ( e ) {
if(e && e.id === name )
{
source.id = e.id;
source.aud = aud_cont;
source.src = app.engine.PlayBuff (e.data, e.chans, e.samplerate, aud_cont);
if (!source.src) {
source.aud && source.aud.close && source.aud.close ();
source = {};
return ;
}
source.src.onended = function ( e ) {
app.fireEvent ('_lclStart', source.id, 0);
source.src.stop ();
source.src.disconnect ();
source.src.onended = null;
source.aud.close && source.aud.close ();
source = {};
};
app.fireEvent ('_lclStart', e.id, 1);
}
});
return ;
}
var overwrite = (function ( app, name, append ) {
return function () {
app.fls.GetSession (name, function ( e ) {
if(e && e.id === name )
{
app.fireEvent ('RequestOriginalEditor');
app.engine.wavesurfer.backend._add = append ? 1 : 0;
app.engine.LoadDB ( e );
}
});
};
})( app, name, append );
// --- ask if we want to click the first one
if (app.engine.is_ready && !append)
{
var mm = new PKSimpleModal ({
title : 'Open in Existing?',
body : '<div>Open in new window, or in the current one?</div>',
buttons:[
{
title:'OPEN',
clss:'pk_modal_a_accpt',
callback: function( q ) {
overwrite ();
q.Destroy ();
}
},
{
title:'OPEN IN NEW',
clss:'pk_modal_a_accpt',
callback: function( q ) {
window.open (window.location.pathname + '?local=' + name);
q.Destroy ();
}
}
],
setup: function ( q ) {
app.ui.InteractionHandler.checkAndSet ('mm');
app.ui.KeyHandler.addCallback ('mmErr', function ( e ) {
q.Destroy ();
}, [27]);
},
ondestroy: function ( q ) {
overwrite = null;
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('mmErr');
}
});
setTimeout(function() { mm.Show (); },0);
return ;
}
overwrite ();
// --
});
});
// ---
}
}
]
},
{
name:'Edit',
children:[
{
name: 'Undo <span class="pk_shrtct">Shft+Z</span>',
clss: 'pk_inact',
action: function () {
app.fireEvent ('StateRequestUndo');
},
setup: function ( obj ) {
app.listenFor ('DidStateChange', function ( undo_states, redo_states ) {
if (undo_states.length === 0)
{
obj.innerHTML = 'Undo <span class="pk_shrtct">Shft+Z</span>';
obj.classList.add ('pk_inact');
}
else
{
obj.innerHTML = 'Undo&nbsp;<i style="pointer-events:none">' + undo_states[undo_states.length - 1].desc + '</i><span class="pk_shrtct">Shft+Z</span>';
obj.classList.remove ('pk_inact');
}
});
}
},
{
name: 'Redo <span class="pk_shrtct">Shft+Y</span>',
clss: 'pk_inact',
action: function () {
app.fireEvent ('StateRequestRedo');
},
setup: function ( obj ) {
app.listenFor('DidStateChange', function ( undo_states, redo_states ) {
if (redo_states.length === 0)
{
obj.innerHTML = 'Redo <span class="pk_shrtct">Shft+Y</span>';
obj.classList.add ('pk_inact');
}
else
{
obj.innerHTML = 'Redo&nbsp;<i style="pointer-events:none">' + redo_states[0].desc + '</i><span class="pk_shrtct">Shft+Y</span>';
obj.classList.remove ('pk_inact');
}
});
}
},
{
name: 'Play <span class="pk_shrtct">Space</span>',
action: function () {
app.fireEvent ('RequestPlay');
}
},
{
name: 'Stop',
action: function () {
app.fireEvent ('RequestStop');
}
},
{
name: 'Select All <span class="pk_shrtct">Shft+A</span>',
action: function () {
app.fireEvent ('RequestSelect');
}
},
{
name: 'Deselect All <span class="pk_shrtct">~</span>',
action: function () {
app.fireEvent ('RequestDeselect');
}
},
{
name : 'Channel Info/Flip',
action : function () {
app.fireEvent ('RequestActionFXUI_Flip');
},
clss: 'pk_inact',
setup: function ( obj ) {
app.listenFor ('DidUnloadFile', function () {
obj.classList.add ('pk_inact');
});
app.listenFor ('DidLoadFile', function () {
obj.classList.remove ('pk_inact');
});
}
},
{
name:'Seamless Loop',
action:function () {
app.fireEvent ('RequestActionFXUI_SeamlessLoop');
}
},
{
name: 'Zero Cross Selection',
action: function () {
app.fireEvent ('RequestSnapSelDrag');
},
setup: function ( obj ) {
var txt = 'Zero Cross Selection';
function set ( val ) { obj.innerHTML = txt + (val ? ' &#10004;' : ''); }
set (!w.localStorage || w.localStorage.pk_snapzc !== '0');
app.listenFor ('DidSnapSelDrag', set);
}
}
]
},
{
name:'Effects',
children:[
{
name:'Gain',
action:function () {
app.fireEvent ('RequestFXUI_Gain');
}
},
{
name:'Fade In',
action:function () {
app.fireEvent ('RequestActionFX_FadeIn');
}
},
{
name:'Fade Out',
action:function () {
app.fireEvent ('RequestActionFX_FadeOut');
}
},
{
name: "Noise Reduction (Voice)",
action: function () {
app.fireEvent("RequestActionFX_NoiseRNN");
},
},
{
name : 'Paragraphic EQ',
action:function () {
app.fireEvent ('RequestActionFXUI_ParaGraphicEQ');
}
},
{
name:'Compressor',
action:function () {
app.fireEvent ('RequestActionFXUI_Compressor');
}
},
{
name : 'Normalize',
action:function () {
app.fireEvent ('RequestActionFXUI_Normalize');
}
},
{
name : 'Graphic EQ',
action:function () {
app.fireEvent ('RequestActionFXUI_GraphicEQ', 10);
}
},
{
name : 'Graphic EQ (20 bands)',
action:function () {
app.fireEvent ('RequestActionFXUI_GraphicEQ', 20);
}
},
{
name : 'Hard Limiter',
action:function () {
app.fireEvent ('RequestActionFXUI_HardLimiter');
}
},
{
name : 'Delay',
action:function () {
app.fireEvent ('RequestActionFXUI_Delay');
}
},
{
name:'Distortion',
action:function () {
app.fireEvent ('RequestActionFXUI_Distortion');
}
},
{
name:'Reverb',
action:function () {
app.fireEvent ('RequestActionFXUI_Reverb');
}
},
{
name:'Audio Repair',
action:function () {
app.fireEvent ('RequestActionFXUI_Repair');
}
},
{
name : 'Speed Up / Slow Down (pitch)',
action:function () {
app.fireEvent ('RequestActionFXUI_Speed');
}
},
{
name : 'Speed / Playback Rate',
action:function () {
app.fireEvent ('RequestActionFXUI_Rate');
}
},
{
name : 'Reverse',
action : function () {
app.fireEvent ('RequestActionFX_Reverse');
}
},
{
name : 'Invert',
action : function () {
app.fireEvent ('RequestActionFX_Invert');
}
},
{
name : 'Remove Silence',
action : function () {
app.fireEvent ('RequestActionFX_RemSil');
}
}
]
},
{
name:'View',
children:[
{
name:'Follow Cursor &#10004;',
action: function ( obj ) {
app.fireEvent ('RequestViewFollowCursorToggle');
},
setup: function ( obj ) {
// perhaps read from stored settings?
app.listenFor ('DidViewFollowCursorToggle', function ( val ) {
var txt = 'Follow Cursor';
if (val) {
obj.innerHTML = txt + ' &#10004;';
} else {
obj.textContent = txt;
}
});
}
},
{
name:'Peak Separators &#10004;',
action: function ( obj ) {
app.fireEvent ('RequestViewPeakSeparatorToggle');
},
setup: function ( obj ) {
app.listenFor ('DidViewPeakSeparatorToggle', function ( val ) {
var txt = 'Peak Separators';
if (val) {
obj.innerHTML = txt + ' &#10004;';
} else {
obj.textContent = txt;
}
});
}
},
{
name:'Timeline &#10004;',
action: function ( obj ) {
app.fireEvent ('RequestViewTimelineToggle');
},
setup: function ( obj ) {
app.listenFor ('DidViewTimelineToggle', function ( val ) {
var txt = 'Timeline';
if (val) {
obj.innerHTML = txt + ' &#10004;';
} else {
obj.textContent = txt;
}
});
}
},
{
name:'---'
},
{
name:'Frequency Analyser',
action: function ( obj ) {
app.fireEvent ('RequestShowFreqAn', 'eq', [1]);
},
setup: function ( obj ) {
app.listenFor ('DidToggleFreqAn', function ( url, val ) {
if (url !== 'eq') return ;
var txt = 'Frequency Analyser';
if (val) {
obj.innerHTML = txt + ' &#10004;';
} else {
obj.textContent = txt;
}
});
}
},
{
name:'Spectrum Analyser',
action: function ( obj ) {
app.fireEvent ('RequestShowFreqAn', 'sp', [1]);
},
setup: function ( obj ) {
app.listenFor ('DidToggleFreqAn', function ( url, val ) {
if (url !== 'sp') return ;
var txt = 'Spectrum Analyser';
if (val) {
obj.innerHTML = txt + ' &#10004;';
} else {
obj.textContent = txt;
}
});
}
},
{
name:'Multitrack Mixer',
action: function ( obj ) {
var mt = app.multitrack;
if (mt && mt.IsOn && !mt.IsOn ()) mt.Toggle ( true );
app.fireEvent ('RequestMixerToggle');
},
setup: function ( obj ) {
app.listenFor ('DidToggleFreqAn', function ( url, val ) {
if (url !== 'mix') return ;
var txt = 'Multitrack Mixer';
if (val) {
obj.innerHTML = txt + ' &#10004;';
} else {
obj.textContent = txt;
}
});
}
},
{
name:'Tempo Tools',
action: function ( obj ) {
app.fireEvent ('RequestActionTempo');
}
},
{
name:'ID3 Tags',
action: function ( obj ) {
app.fireEvent ('RequestActionID3');
}
},
{
name:'---'
},
{
name:'Center to Cursor <span class="pk_shrtct">[Tab]</span>',
action: function ( obj ) {
app.fireEvent ('RequestViewCenterToCursor');
}
},
{
name:'Reset Zoom <span class="pk_shrtct">[0]</span>',
action: function ( obj ) {
app.fireEvent ('RequestZoomUI', 0);
}
}
]
},
{
name:'Help',
children:[
{
name : 'Store Offline Version',
action : function () {
if (window.location.href.indexOf('-cache') > 0) {
function onUpdateReady ( e ) {
if (confirm ('Would you like to refresh the page to load the newer version?'))
window.location.reload();
}
function downLoading ( e ) {
OneUp ('Downloading newer version', 1500);
}
window.applicationCache.onupdateready = onUpdateReady;
window.applicationCache.ondownloading = downLoading;
if(window.applicationCache.status === window.applicationCache.UPDATEREADY) {
onUpdateReady ();
}
window.applicationCache.update ();
return ;
}
var message = 'This will open a new window that will try to store a local version in your browser'; // nicer text
new PKSimpleModal ({
title : 'Open Offline Version?',
ondestroy : function( q ) {
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback ('modalTempErr');
},
buttons:[
{
title:'OPEN',
callback: function( q ) {
window.open ('/index-cache.html');
q.Destroy ();
}
}
],
body:'<p>' + message + '</p>',
setup:function( q ) {
app.fireEvent ('RequestPause');
app.fireEvent( 'RequestRegionClear');
app.ui.InteractionHandler.checkAndSet ('modal');
app.ui.KeyHandler.addCallback ('modalTempErr', function ( e ) {
q.Destroy ();
}, [27]);
}
}).Show ();
// -
},
setup: function ( obj ) {
if (window.location.href.indexOf('-cache') > 0)
{
obj.innerHTML = 'Update Offline Version';
}
}
},
{
name:'---'
},
{
name : 'About',
action : function () {
window.open ('/about.html');
}
},
{
name : 'See Welcome Message',
action : function () {
PKAudioEditor._deps.Wlc ();
}
},
// {
// name : 'About AudioMass',
// action : function () {
// window.open ('/about.html');
// }
// },
// {
// name:'---'
// },
{
name : 'SourceCode on Github',
action : function () {
window.open ('https://github.com/pkalogiros/audiomass');
}
}
]
}
];
};
//
// TOP-BAR CLASS
//
function _makeUITopHeader ( menu_tree, UI ) {
var header = d.createElement ( 'div' );
header.className = 'pk_hdr pk_noselect';
var _name = 'TopHeader',
_default_class = 'pk_btn pk_noselect';
var target_index = -1;
var target_el = null;
var target_el_old = null;
var target_option = null;
var top_els = [];
var q = this;
// recursively build the interface
function build_menus ( parent_el, tree_obj, level ) {
for (var i = 0; i < tree_obj.length; ++i)
{
var btn_container = d.createElement ( 'div' );
var curr_obj = tree_obj[i];
if (level === 0)
{
btn_container.className = _default_class;
var btn = d.createElement ( 'button' );
btn.innerHTML = curr_obj.name;
btn_container.appendChild ( btn );
}
else
{
btn_container.className = 'pk_menu_el';
var btn = d.createElement ( 'button' );
btn.className = 'pk_opt ' + (curr_obj.clss ? curr_obj.clss : '');
btn.setAttribute ( 'tab-index', '-1' );
btn.setAttribute ( 'data-index', i );
btn.innerHTML = curr_obj.name;
btn_container.appendChild ( btn );
if (curr_obj.action)
{
(function ( btn, action ) {
btn.onclick = function ( obj ) {
if (this.classList.contains('pk_inact')) return ;
q.closeMenu ();
action ( obj );
};
})( btn, curr_obj.action );
}
if (curr_obj.setup)
{
curr_obj.setup ( btn );
}
}
parent_el.appendChild ( btn_container );
if (level === 0)
top_els[i] = btn_container.childNodes[0];
if (curr_obj.children)
{
var ch = curr_obj.children;
var list = d.createElement('div');
list.className = 'pk_menu';
build_menus ( list, curr_obj.children, level + 1 );
btn_container.appendChild ( list );
}
// ---
}
};
build_menus ( header, menu_tree, 0 );
this.getOpenElement = function () {
return target_el;
};
this.closeMenu = function() {
if (!target_el) return ;
target_el.parentNode.className = _default_class;
target_el = target_el_old = null;
if (target_option)
{
target_option.classList.remove ('pk_act');
target_option = null;
}
UI.InteractionHandler.on = false;
d.removeEventListener ( 'mouseup', mouseup );
// de-register keys
UI.KeyHandler.removeCallback (_name + 1);
UI.KeyHandler.removeCallback (_name + 2);
UI.KeyHandler.removeCallback (_name + 3);
UI.KeyHandler.removeCallback (_name + 4);
UI.KeyHandler.removeCallback (_name + 5);
UI.KeyHandler.removeCallback (_name + 6);
};
this.openMenu = function ( index, is_mouse ) {
if (target_el) {
target_el.parentNode.className = _default_class;
}
if (index === -1) {
index = target_index === -1 ? 0 : target_index;
}
var curr_target = top_els[ index ];
target_el = curr_target;
var parent = curr_target.parentNode;
var left = parent.getBoundingClientRect ().left;
var max = window.innerWidth;
var offset = 0;
if ( max - left < 200 )
{
offset = (264 - (max - left)) >> 0;
if (offset > 1)
parent.getElementsByClassName ('pk_menu')[0].style.left = (-offset / 2) + 'px';
}
parent.className += ' pk_vis';
setTimeout(function() {
if (target_el === curr_target)
parent.className += ' pk_act';
},0);
target_index = index;
UI.InteractionHandler.checkAndSet (_name);
if (!is_mouse)
d.addEventListener ( 'mouseup', mouseup, false );
// register keystrokes
UI.KeyHandler.addCallback (_name + 1, function ( key ) {
if (target_index === 0)
target_index = top_els.length;
q.closeMenu ();
q.openMenu ( target_index - 1 );
}, [37]);
UI.KeyHandler.addCallback (_name + 2, function ( key ) {
if (target_index === top_els.length - 1)
target_index = -1;
q.closeMenu ();
q.openMenu ( target_index + 1 );
}, [39]);
UI.KeyHandler.addCallback (_name + 3, function ( key ) {
q.closeMenu ();
}, [27]);
UI.KeyHandler.addCallback (_name + 4, function ( key, m, e ) {
if (!target_option)
{
var els = target_el.parentNode.getElementsByClassName ('pk_opt');
if (els[0]) {
target_option = els[0];
target_option.classList.add ('pk_act');
}
}
else
{
var ind = target_option.getAttribute ('data-index')/1;
target_option.classList.remove ('pk_act');
target_option = target_el.parentNode.getElementsByClassName ('pk_opt');
if (ind - 1 < 0)
{
target_option = target_option[target_option.length - 1];
}
else
{
target_option = target_option[ind - 1];
}
target_option.classList.add ('pk_act');
}
}, [38]);
UI.KeyHandler.addCallback (_name + 5, function ( key, m, e ) {
if (!target_option)
{
var els = target_el.parentNode.getElementsByClassName ('pk_opt');
if (els[0]) {
target_option = els[0];
target_option.classList.add ('pk_act');
}
}
else
{
var ind = target_option.getAttribute ('data-index')/1;
target_option.classList.remove ('pk_act');
target_option = target_el.parentNode.getElementsByClassName ('pk_opt');
if (target_option.length <= ind + 1)
{
target_option = target_option[0];
}
else
{
target_option = target_option[ind + 1];
}
target_option.classList.add ('pk_act');
}
}, [40]);
UI.KeyHandler.addCallback (_name + 6, function ( key ) {
if (target_option)
target_option.click();
else
q.closeMenu ();
}, [13]);
return (true);
};
UI.listenFor ('DidReadyFire', function () {
q.closeMenu ();
});
// register hot keys for opening the menu
function _checkForAct( x ) {
if (target_el == x || !x) return (false);
var par = x.parentNode;
while (par && target_el) {
if (target_el.parentNode == par) {
return (false);
}
par = par.parentNode;
}
var l = top_els.length;
while(l-- > 0) {
if (top_els[l] === x) {
return q.openMenu (l, true);
}
}
return (false);
}
// now make the buttons interactive
var mousemove = function ( e ) {
if (!UI.InteractionHandler.check (_name)) {
return (false);
}
if (target_el || (UI.InteractionHandler.on && UI.InteractionHandler.by === _name) )
{
var x = e.target || e.srcElement;
if (x.className.indexOf('pk_opt') >= 0)
{
if (target_option)
target_option.classList.remove ('pk_act');
target_option = x;
target_option.classList.add ('pk_act');
}
else
{
if (target_option)
target_option.classList.remove ('pk_act');
target_option = null;
}
return _checkForAct ( x );
}
return (false);
};
var mouseup = function( e ) {
var x = e.target || e.srcElement;
if (target_el)
{
// todo check for inner menu?
var par = x;
var found = false;
while (par && target_el) {
if (target_el.parentNode == par) {
found = true;
break;
}
par = par.parentNode;
}
if (!found || target_el_old === x) {
q.closeMenu();
}
}
else
{
UI.InteractionHandler.on = false;
d.removeEventListener ( 'mouseup', mouseup );
}
target_el_old = null;
};
header.addEventListener ( 'mousemove', mousemove, false );
header.addEventListener ( 'mousedown', function( e ) {
if (!UI.InteractionHandler.checkAndSet (_name)) {
return (false);
}
d.removeEventListener ( 'mouseup', mouseup );
if (target_el)
{
if (!_checkForAct ( e.target || e.srcElement ))
target_el_old = target_el;
else
target_el_old = null;
d.addEventListener ( 'mouseup', mouseup, false );
}
else
{
target_el_old = null;
d.addEventListener ( 'mouseup', mouseup, false );
_checkForAct ( e.target || e.srcElement );
}
// -
}, false);
UI.el.appendChild ( header );
// -
};
// ####
function _makeUIBarBottom ( UI, app ) {
var q = this;
var bar_bottom_el = d.createElement ('div');
bar_bottom_el.className = 'pk_dck';
UI.el.appendChild( bar_bottom_el );
q.el = bar_bottom_el;
q.on = false;
q.height = 130;
q.SetHeight = function ( height ) {
q.height = height;
if (q.on) bar_bottom_el.style.height = height + 'px';
};
q.Show = function () {
q.on = true;
bar_bottom_el.style.display = 'block';
bar_bottom_el.style.height = q.height + 'px';
app.fireEvent ('RequestResize');
};
q.Hide = function () {
q.on = false;
bar_bottom_el.style.display = 'none';
bar_bottom_el.style.height = '0';
app.fireEvent ('RequestResize');
};
};
function _makeUIMainView ( UI, app ) {
var q = this;
var audio_container = d.createElement ('div');
audio_container.className = 'pk_av_cont';
UI.el.appendChild( audio_container );
var main_audio_view = d.createElement ( 'div' );
main_audio_view.className = 'pk_av pk_noselect';
main_audio_view.id = 'pk_av_' + app.id;
audio_container.appendChild( main_audio_view );
var footer = d.createElement ( 'div' );
footer.className = 'pk_ftr pk_noselect';
UI.el.appendChild( footer );
// make panner buttons
var btn_panner_cnt = d.createElement ('div');
btn_panner_cnt.className = 'pk_panner pk_noselect';
var panner_col_left = d.createElement ('div');
panner_col_left.className = 'pk_pan_left';
var panner_col_right = d.createElement ('div');
panner_col_right.className = 'pk_pan_right';
var btn_panner_left = d.createElement ('button');
var btn_panner_right = d.createElement ('button');
btn_panner_left.setAttribute ('tabIndex', -1);
btn_panner_right.setAttribute ('tabIndex', -1);
btn_panner_left.className = 'pk_pan_btn';
btn_panner_right.className = 'pk_pan_btn';
btn_panner_left.innerHTML = '<strong>L</strong> ON';
btn_panner_right.innerHTML = '<strong>R</strong> ON';
panner_col_left.appendChild ( btn_panner_left );
panner_col_right.appendChild ( btn_panner_right );
btn_panner_cnt.appendChild ( panner_col_left );
btn_panner_cnt.appendChild ( panner_col_right );
audio_container.appendChild ( btn_panner_cnt );
btn_panner_left.onclick = function () {
app.fireEvent ('RequestChanToggle', 0);
this.blur();
};
btn_panner_right.onclick = function () {
app.fireEvent ('RequestChanToggle', 1);
this.blur();
};
app.listenFor ('DidChanToggle', function ( chan, val ) {
if ( chan === 0) {
if (val)
{
btn_panner_left.classList.remove ('pk_inact');
btn_panner_left.innerHTML = '<strong>L</strong> ON';
}
else
{
btn_panner_left.classList.add ('pk_inact');
btn_panner_left.innerHTML = '<strong>L</strong> OFF';
}
} else {
if (val)
{
btn_panner_right.classList.remove ('pk_inact');
btn_panner_right.innerHTML = '<strong>R</strong> ON';
}
else
{
btn_panner_right.classList.add ('pk_inact');
btn_panner_right.innerHTML = '<strong>R</strong> OFF';
}
}
});
// zoom btns
var btn_zoom_cnt = d.createElement ('div');
btn_zoom_cnt.className = 'pk_zoombtn';
var btn_zoom_in_h = d.createElement ('button');
btn_zoom_in_h.className = 'pk_btn pk_zoom_in_h';
btn_zoom_in_h.innerHTML = '+<span>Zoom In Horiz (+)</span>';
btn_zoom_in_h.setAttribute ('tabIndex', -1);
btn_zoom_in_h.onclick = function () {
app.fireEvent ('RequestZoomUI', 'h', -1);
this.blur();
};
var btn_zoom_out_h = d.createElement ('button');
btn_zoom_out_h.className = 'pk_btn pk_zoom_out_h pk_inact';
btn_zoom_out_h.innerHTML = '&ndash;<span>Zoom Out Horiz (-)</span>';
btn_zoom_out_h.setAttribute ('tabIndex', -1);
btn_zoom_out_h.onclick = function () {
app.fireEvent ('RequestZoomUI', 'h', 1);
this.blur();
};
var btn_zoom_reset = d.createElement ('button');
btn_zoom_reset.className = 'pk_btn pk_zoom_reset pk_inact';
btn_zoom_reset.innerHTML = '[R] <span>Reset Zoom (0)</span>';
btn_zoom_reset.setAttribute ('tabIndex', -1);
btn_zoom_reset.onclick = function () {
app.fireEvent ('RequestZoomUI', 0);
this.blur();
};
UI.KeyHandler.addCallback ('Key0', function ( key ) {
if (UI.InteractionHandler.on) return ;
app.fireEvent ('RequestZoomUI', 0);
}, [48]);
UI.KeyHandler.addCallback ('KeyZO', function ( key ) {
if (UI.InteractionHandler.on) return ;
app.fireEvent ('RequestZoomUI', 'h', 1);
}, [189]);
UI.KeyHandler.addCallback ('KeyZI', function ( key ) {
if (UI.InteractionHandler.on) return ;
app.fireEvent ('RequestZoomUI', 'h', -1);
}, [187]);
var btn_zoom_in_v = d.createElement ('button');
btn_zoom_in_v.className = 'pk_btn pk_zoom_in_v';
btn_zoom_in_v.innerHTML = '&#x2195; +<span>Zoom In Vertically</span>';
btn_zoom_in_v.setAttribute ('tabIndex', -1);
btn_zoom_in_v.onclick = function () {
app.fireEvent ('RequestZoomUI', 'v', -1);
this.blur();
};
var btn_zoom_out_v = d.createElement ('button');
btn_zoom_out_v.className = 'pk_btn pk_zoom_out_v';
btn_zoom_out_v.innerHTML = '&#x2195; &ndash;<span>Zoom Out Vertically</span>';
btn_zoom_out_v.setAttribute ('tabIndex', -1);
btn_zoom_out_v.onclick = function () {
app.fireEvent ('RequestZoomUI', 'v', 1);
this.blur();
};
btn_zoom_cnt.appendChild ( btn_zoom_in_h );
btn_zoom_cnt.appendChild ( btn_zoom_out_h );
btn_zoom_cnt.appendChild ( btn_zoom_reset );
btn_zoom_cnt.appendChild ( btn_zoom_in_v );
btn_zoom_cnt.appendChild ( btn_zoom_out_v );
footer.appendChild ( btn_zoom_cnt );
// end of zoom btns
var wavezoom = d.createElement ( 'div' );
wavezoom.className = 'pk_wavescroll';
var wavepoint_visible = false;
var wavepoint = d.createElement ( 'div' );
wavepoint.className = 'pk_wavepoint';
var wavedrag = d.createElement ( 'div' );
var wavedrag_style = wavedrag.style;
wavedrag.className = 'pk_wavedrag pk_inact';
var wavedrag_left = d.createElement ( 'div' );
wavedrag_left.className = 'pk_wavedrag_l';
var wavedrag_right = d.createElement ( 'div' );
wavedrag_right.className = 'pk_wavedrag_r';
wavezoom.appendChild ( wavepoint );
wavedrag.appendChild ( wavedrag_left );
wavedrag.appendChild ( wavedrag_right );
wavezoom.appendChild ( wavedrag );
footer.appendChild ( wavezoom );
var temp = 0;
var wavedrag_width = 100;
wavezoom.onclick = function( e ) {
if (window.performance.now() - temp < 20)
{
return ;
}
var rect = e.target.getBoundingClientRect();
var x = e.clientX - rect.left;
UI.fireEvent ('RequestPan', x, 2);
};
// add zoom event, and add seek event....
UI.listenFor ('DidZoom', function ( v ) {
var e = v[0];
var o = v[1];
if (e === 1) {
btn_zoom_out_h.classList.add ('pk_inact');
btn_zoom_reset.classList.add ('pk_inact');
} else {
btn_zoom_out_h.classList.remove ('pk_inact');
btn_zoom_reset.classList.remove ('pk_inact');
}
if (v[2] != 1) {
btn_zoom_reset.classList.remove ('pk_inact');
}
if (e === 1) {
if (wavepoint_visible)
{
wavepoint.style.display = 'none';
wavepoint_visible = false;
}
} else {
if (!wavepoint_visible)
{
wavepoint.style.display = 'block';
wavepoint_visible = true;
}
var perc = (v[3] !== undefined) ?
v[3] :
app.engine.wavesurfer.getCurrentTime() / app.engine.wavesurfer.getDuration ();
// wavepoint.style.left = ((perc * 100).toFixed(2)/1) + '%';
wavepoint.style.left = ((perc * 10000)>>0)/100 + '%';
}
// get zoom value and left...
if ((100/e) > 99)
{
wavedrag_width = 100;
wavedrag_style.width = '100%';
wavedrag_style.left = '0%';
//wavedrag_style.transform = 'translate(0,0)';
wavedrag.classList.add ('pk_inact');
}
else
{
wavedrag_width = (100/e);
wavedrag_style.width = wavedrag_width + '%';
wavedrag_style.left = o + '%';
//wavedrag_style.transform = 'translate(' + (e * o) + '%,0)';
wavedrag.classList.remove ('pk_inact');
}
});
UI.listenFor ('DidCursorCenter', function( val, zoom ) {
requestAnimationFrame(function () {
wavedrag_style.left = (val * 100) + '%';
});
});
// update wavedrag position during non-zoomed playback too
UI.listenFor ('DidAudioProcess', function( val ) {
var mt_on = activeMultitrackFor ( app );
if (mt_on || !app.engine || !app.engine.wavesurfer) return;
var wv = app.engine.wavesurfer;
if (wv.ZoomFactor > 1) return; // zoomed: handled by DidCursorCenter
var perc = wv.backend.getPlayedPercents ? wv.backend.getPlayedPercents() : 0;
if (perc > 0) wavedrag_style.left = ((perc * (100 - wavedrag_width)) >> 0) + '%';
});
var drag_mode = 0;
var startingX = 0;
var waveScrollMouseMove = function( e ) {
e.stopPropagation(); e.preventDefault();
var clx = e.clientX;
if (e.touches) {
if (e.touches.length > 1) return ;
clx = e.touches[0].clientX;
}
if (drag_mode === 2)
{
var rect = wavezoom.getBoundingClientRect ();
UI.fireEvent ('RequestPan', Math.max (0, Math.min (wavezoom.clientWidth, clx - rect.left)), 2);
return ;
}
var diff = -startingX + clx;
if (drag_mode === 0)
UI.fireEvent ('RequestPan', diff, 1);
else if (drag_mode === -1)
{
UI.fireEvent ('RequestZoom', diff, -1);
}
else if (drag_mode === 1)
{
UI.fireEvent ('RequestZoom', diff, 1);
}
startingX = clx;
},
waveScrollMouseUp = function ( e ) {
if (e.touches && e.touches.length > 1) return ;
PKAudioEditor.engine.wavesurfer.Interacting &= ~(1 << 1);
e.stopPropagation();e.preventDefault();
drag_mode = 0;
temp = window.performance.now();
wavedrag.classList.remove ('pk_drag');
document.removeEventListener('mousemove', waveScrollMouseMove);
document.removeEventListener('mouseup', waveScrollMouseUp);
document.removeEventListener('touchmove', waveScrollMouseMove, {passive:false});
document.removeEventListener('touchend', waveScrollMouseUp);
};
var mdown = function ( e ) {
var mt_on = activeMultitrackFor ( app );
if (!PKAudioEditor.engine.is_ready && !mt_on) return ;
if (e.target === wavezoom && !mt_on) return ;
if (e.target === wavedrag) {
drag_mode = 0;
} else if ( e.target === wavedrag_left) {
drag_mode = -1;
} else if ( e.target === wavedrag_right) {
drag_mode = 1;
}
else if (mt_on) {
drag_mode = 2;
}
else return ;
e.stopPropagation(); e.preventDefault();
wavedrag.className += ' pk_drag';
startingX = e.clientX;
if (drag_mode === 2) waveScrollMouseMove ( e );
PKAudioEditor.engine.wavesurfer.Interacting |= (1 << 1);
if (e.is_touch)
{
document.addEventListener ('touchmove', waveScrollMouseMove, {passive:false});
document.addEventListener ('touchend', waveScrollMouseUp, false);
}
else
{
document.addEventListener ('mousemove', waveScrollMouseMove, false);
document.addEventListener ('mouseup', waveScrollMouseUp, false);
}
};
wavezoom.addEventListener ('mousedown', mdown, false);
if ('ontouchstart' in window) {
wavedrag.addEventListener ('touchstart', function ( e ) {
e.preventDefault ();
e.stopPropagation ();
if (e.touches.length > 1) {
return ;
}
var ev = {
is_touch : true,
target : wavedrag,
clientX: e.touches[0].clientX,
stopPropagation: function(){},
preventDefault: function(){}
};
mdown ( ev );
}, false);
}
this.volumeGauge = d.createElement( 'div' );
this.volumeGauge2 = d.createElement( 'div' );
this.volumeGaugeInner = d.createElement( 'div' );
this.volumeGaugeInner2 = d.createElement( 'div' );
this.volumeGaugePeaker = d.createElement( 'div' );
this.volumeGaugePeaker2 = d.createElement( 'div' );
var volume_parent = d.createElement('div');
this.volumeGauge.className = 'pk_volpar';
this.volumeGauge2.className = 'pk_volpar';
this.volumeGaugeInner.className = 'pk_vol';
this.volumeGaugeInner2.className = 'pk_vol';
this.volumeGaugePeaker.className = 'pk_peaker';
this.volumeGaugePeaker2.className = 'pk_peaker';
this.volumeGauge.appendChild ( this.volumeGaugeInner );
this.volumeGauge.appendChild( this.volumeGaugePeaker );
this.volumeGauge2.appendChild ( this.volumeGaugeInner2 );
this.volumeGauge2.appendChild( this.volumeGaugePeaker2 );
var markers = d.createElement('div');
markers.className = 'pk_markers pk_noselect';
var str = '<span class="pk_mark1">-Inf</span>';
for (var i = 35; i >= 0; --i)
{
str += '<span class="pk_mark1 '+(i%2?'pk_odd':'')+'">' + -(i*2) + '</span>';
}
markers.innerHTML = str;
volume_parent.appendChild( this.volumeGauge );
volume_parent.appendChild( this.volumeGauge2 );
volume_parent.appendChild( markers );
volume_parent.onclick = function() {
q.volumeGaugePeaker.className = 'pk_peaker';
q.volumeGaugePeaker2.className = 'pk_peaker';
};
footer.appendChild( volume_parent );
// change temp message, it's pretty ugly #### TODO
var ttmp = d.createElement('div');
ttmp.className = 'pk_tmpMsg pk_ed_empty';
ttmp.innerHTML = 'Drag n drop an Audio File in this window, or click ' +
'<a style="white-space:nowrap;border:1px solid;border-radius:23px;padding:5px 18px;font-size:0.94em;margin-left:5px" '+
'onclick="PKAudioEditor.engine.LoadSample()">here to use a sample</a>';
main_audio_view.appendChild( ttmp );
var ttmp2 = d.createElement('div');
ttmp2.className = 'pk_tmpMsg2';
ttmp2.innerHTML = '<span>Please Wait...</span><div class="pk_mload"><div></div></div>' +
'<div class="pk_prc"><span>0%</span>' +
'<button tabIndex="-1" class="pk_btn" '+
'onclick="PKAudioEditor.fireEvent(\'RequestCancelModal\');">cancel</button></div>';
d.body.appendChild( ttmp2 );
UI.loaderEl = ttmp2;
UI.listenFor ('WillDownloadFile', function() {
UI.loaderEl.classList.add ('pk_act');
UI.loaderEl.getElementsByTagName('span')[1].style.display = 'none';
});
UI.listenFor ('DidDownloadFile', function() {
UI.loaderEl.classList.remove ('pk_act');
});
UI.listenFor ('DidProgressModal', function ( val ) {
UI.loaderEl.getElementsByTagName('span')[1].style.display = 'block';
UI.loaderEl.getElementsByTagName('span')[1].textContent = val + '%';
});
}
function _bindToolbarTips ( UI, container ) {
if (!container || !UI || !UI.el || UI.el.classList.contains ('pk_mob')) return ;
var tip = d.createElement ('div');
var active = null;
var raf = 0;
tip.className = 'pk_ttip';
UI.el.appendChild ( tip );
function tipButton ( node ) {
while (node && node !== container) {
if (node.classList && node.classList.contains ('pk_btn')) return node;
node = node.parentNode;
}
return null;
}
function hide () {
active = null;
tip.classList.remove ('pk_act');
if (raf) {
w.cancelAnimationFrame ( raf );
raf = 0;
}
}
function place () {
raf = 0;
if (!active) return ;
var span = active.getElementsByTagName ('span')[0];
var txt = span && span.textContent;
if (!txt || active.classList.contains ('pk_inact')) return hide ();
var r = active.getBoundingClientRect ();
tip.textContent = txt;
tip.classList.add ('pk_act');
var tw = tip.offsetWidth;
var x = Math.max (4, Math.min (w.innerWidth - tw - 4, r.left + (r.width - tw) / 2));
tip.style.left = (x >> 0) + 'px';
tip.style.top = ((r.bottom + 6) >> 0) + 'px';
}
function show ( e ) {
var btn = tipButton ( e.target );
if (!btn || btn === active) return ;
active = btn;
if (!raf) raf = w.requestAnimationFrame ( place );
}
container.addEventListener ('mouseover', show, false);
container.addEventListener ('focusin', show, false);
container.addEventListener ('mouseout', function ( e ) {
if (!active || tipButton ( e.relatedTarget ) === active) return ;
hide ();
}, false);
container.addEventListener ('focusout', hide, false);
container.addEventListener ('scroll', hide, false);
w.addEventListener ('resize', hide, false);
}
function _makeUIToolbar (UI) {
var app = PKAE; // fallback: use the singleton when app isn't in closure scope
var container = d.createElement ( 'div' );
container.className = 'pk_tbc';
var toolbar = d.createElement ( 'div' );
toolbar.className = 'pk_tb pk_noselect';
var btn_groups = d.createElement( 'div' );
btn_groups.className = 'pk_btngroup';
var transport = d.createElement( 'div' );
transport.className = 'pk_transport';
// play button
var btn_stop = d.createElement ('button');
btn_stop.setAttribute ('tabIndex', -1);
btn_stop.innerHTML = '<span>Stop Playback (Space)</span>';
btn_stop.className = 'pk_btn pk_stop icon-stop2';
btn_stop.onclick = function() {
UI.fireEvent('RequestStop');
this.blur();
};
transport.appendChild ( btn_stop );
var btn_play = d.createElement ('button');
btn_play.setAttribute ('tabIndex', -1);
btn_play.className = 'pk_btn pk_play icon-play3';
btn_play.innerHTML = '<span>Play (Space)</span>';
transport.appendChild ( btn_play );
btn_play.onclick = function() {
UI.fireEvent('RequestPlay');
this.blur();
};
UI.listenFor ('DidStopPlay', function(){
btn_play.classList.remove ('pk_act');
});
UI.listenFor ('DidPlay', function(){
btn_play.classList.add ('pk_act');
});
var btn_pause = d.createElement ('button');
btn_pause.setAttribute('tabIndex', -1);
btn_pause.className = 'pk_btn pk_pause icon-pause2';
btn_pause.innerHTML = '<span>Pause (Shift+Space)</span>';
transport.appendChild ( btn_pause );
btn_pause.onclick = function() {
UI.fireEvent('RequestPause');
this.blur();
};
var btn_loop = d.createElement ('button');
btn_loop.setAttribute('tabIndex', -1);
btn_loop.className = 'pk_btn pk_loop icon-loop';
btn_loop.innerHTML = '<span>Toggle Loop (L)</span>';
transport.appendChild ( btn_loop );
btn_loop.onclick = function() {
UI.fireEvent('RequestSetLoop');
this.blur();
};
UI.listenFor('DidSetLoop', function( val ) {
val ? btn_loop.classList.add('pk_act') :
btn_loop.classList.remove('pk_act');
});
var btn_back_jump = d.createElement ('button');
btn_back_jump.setAttribute('tabIndex', -1);
btn_back_jump.className = 'pk_btn pk_back_jump icon-backward2';
btn_back_jump.innerHTML = '<span>Seek (left arrow)</span>';
transport.appendChild ( btn_back_jump );
///////////////////////////////////////////////////////////
// REWING / BACK BTN
var btn_back_focus = false;
var btn_back_hold = false;
var btn_back_tm = null;
btn_back_jump.onclick = function() {
if (!btn_back_focus)
{
if (btn_back_tm) {
clearTimeout(btn_back_tm);
btn_back_tm = null;
}
var big_step = activeDurationFor ( app ) / 20;
var zoom = activeZoomFor ( app );
big_step /= ((zoom/2)+0.5);
if (big_step > 1) big_step = big_step << 0;
UI.fireEvent ('RequestSkipBack', big_step);
}
this.blur();
btn_back_focus = false;
btn_back_hold = false;
};
btn_back_jump.onmousedown = function () {
btn_back_hold = true;
this.focus ();
if (!btn_back_tm) this.onfocus ();
};
btn_back_jump.onmouseup = function () {
btn_back_hold = false;
};
btn_back_jump.onmouseleave = function () {
btn_back_hold = false;
if (btn_back_tm) {
clearTimeout(btn_back_tm);
btn_back_tm = null;
}
this.blur();
};
btn_back_jump.onfocus = function() {
var btn = this;
btn_back_focus = false;
if (btn_back_tm) clearTimeout ( btn_back_tm );
var step = function ( num, count ) {
if (btn_back_hold || document.activeElement === btn)
{
btn_back_focus = true;
UI.fireEvent ('RequestSkipBack', num);
if (count >= activeSeekWarmupFor ( app ))
num += num * activeSeekRampFor ( app );
btn_back_tm = setTimeout(function() {
step (num, ++count);
},40);
}
};
btn_back_tm = setTimeout(function(){
var small = activeDurationFor ( app ) / 2000;
var zoom = activeZoomFor ( app );
small /= zoom;
if (small < 0.01) {
small = 0.01;
}
step (small, 0);
},220);
};
////////////////////////
var btn_front_jump = d.createElement ('button');
btn_front_jump.setAttribute('tabIndex', -1);
btn_front_jump.className = 'pk_btn pk_front_jump icon-forward3';
btn_front_jump.innerHTML = '<span>Seek (right arrow)</span>';
transport.appendChild ( btn_front_jump );
var btn_frnt_focus = false;
var btn_frnt_hold = false;
var btn_frnt_tm = null;
btn_front_jump.onclick = function() {
if (!btn_frnt_focus)
{
if (btn_frnt_tm) {
clearTimeout(btn_frnt_tm);
btn_frnt_tm = null;
}
var big_step = activeDurationFor ( app ) / 20;
var zoom = activeZoomFor ( app );
big_step /= ((zoom/2)+0.5);
if (big_step > 1) big_step = big_step << 0;
UI.fireEvent ('RequestSkipFront', big_step);
}
this.blur();
btn_frnt_focus = false;
btn_frnt_hold = false;
};
btn_front_jump.onmousedown = function () {
btn_frnt_hold = true;
this.focus ();
if (!btn_frnt_tm) this.onfocus ();
};
btn_front_jump.onmouseup = function () {
btn_frnt_hold = false;
};
btn_front_jump.onmouseleave = function () {
btn_frnt_hold = false;
if (btn_frnt_tm) {
clearTimeout(btn_frnt_tm);
btn_frnt_tm = null;
}
this.blur();
};
btn_front_jump.onfocus = function() {
var btn = this;
btn_frnt_focus = false;
if (btn_frnt_tm) clearTimeout ( btn_frnt_tm );
var step = function ( num, count ) {
if (btn_frnt_hold || document.activeElement === btn)
{
btn_frnt_focus = true;
UI.fireEvent ('RequestSkipFront', num);
if (count >= activeSeekWarmupFor ( app ))
num += num * activeSeekRampFor ( app );
btn_frnt_tm = setTimeout(function() {
step (num, ++count);
},40);
}
};
btn_frnt_tm = setTimeout(function(){
var small = activeDurationFor ( app ) / 2000;
var zoom = activeZoomFor ( app );
small /= zoom;
if (small < 0.01) {
small = 0.01;
}
step (small, 0);
},220);
};
////////////////////////
var k_arr_bck_time = 0;
var k_arr_bck_mult = 1;
var k_arr_bck_skip_frames = 4;
UI.KeyHandler.addCallback ('KeyArrowBack', function ( key, c, ev ) {
var mt_on = activeMultitrackFor ( app );
if (UI.InteractionHandler.on || (!PKAudioEditor.engine.is_ready && !mt_on)) return ;
if (c[16] || (ev && ev.shiftKey)) return ;
if (mt_on && ev) ev.preventDefault ();
var time = ev ? ev.timeStamp : w.performance.now ();
var diff = time - k_arr_bck_time;
if (diff > 158) {
k_arr_bck_mult = 1;
k_arr_bck_skip_frames = mt_on ? activeSeekWarmupFor ( app ) : 4;
} else {
if (--k_arr_bck_skip_frames < 0 && k_arr_bck_mult < 6.0)
k_arr_bck_mult += mt_on ? activeSeekRampFor ( app ) : 0.05;
}
k_arr_bck_time = time;
// get zoom factor
var jump = 0.5;
var zoom = mt_on ? activeZoomFor ( app ) : PKAudioEditor.engine.wavesurfer.ZoomFactor;
var total_dur = mt_on ? activeDurationFor ( app ) : PKAudioEditor.engine.wavesurfer.getDuration ();
jump = Math.max(total_dur / 200, 0.05);
jump /= zoom;
jump *= k_arr_bck_mult;
UI.fireEvent( 'RequestSkipBack', jump );
}, [37]);
var k_arr_frnt_time = 0;
var k_arr_frnt_mult = 1;
var k_arr_frnt_skip_frames = 4;
UI.KeyHandler.addCallback ('KeyArrowFront', function ( key, c, ev ) {
var mt_on = activeMultitrackFor ( app );
if (UI.InteractionHandler.on || (!PKAudioEditor.engine.is_ready && !mt_on)) return ;
if (c[16] || (ev && ev.shiftKey)) return ;
if (mt_on && ev) ev.preventDefault ();
var time = ev ? ev.timeStamp : w.performance.now ();
var diff = time - k_arr_frnt_time;
if (diff > 158) {
k_arr_frnt_mult = 1;
k_arr_frnt_skip_frames = mt_on ? activeSeekWarmupFor ( app ) : 4;
} else {
if (--k_arr_frnt_skip_frames < 0 && k_arr_frnt_mult < 6.0)
k_arr_frnt_mult += mt_on ? activeSeekRampFor ( app ) : 0.05;
}
k_arr_frnt_time = time;
var jump = 0.5;
var zoom = mt_on ? activeZoomFor ( app ) : PKAudioEditor.engine.wavesurfer.ZoomFactor;
var total_dur = mt_on ? activeDurationFor ( app ) : PKAudioEditor.engine.wavesurfer.getDuration ();
jump = Math.max(total_dur / 200, 0.05);
jump /= zoom;
jump *= k_arr_frnt_mult;
UI.fireEvent( 'RequestSkipFront', jump );
}, [39]);
function mtSelectChannelKey ( diff, ev ) {
var mt_on = activeMultitrackFor ( app );
var target = ev && ev.target;
if (!mt_on ||
UI.InteractionHandler.on ||
(UI.TopHeader.getOpenElement && UI.TopHeader.getOpenElement ()) ||
(target && /INPUT|TEXTAREA|SELECT/.test (target.tagName))) return ;
ev && ev.preventDefault ();
ev && ev.stopPropagation ();
UI.fireEvent ('RequestChannelSelect', diff);
}
UI.KeyHandler.addCallback ('KeyMtChannelUp', function ( key, c, ev ) {
mtSelectChannelKey ( -1, ev );
}, [38]);
UI.KeyHandler.addCallback ('KeyMtChannelDown', function ( key, c, ev ) {
mtSelectChannelKey ( 1, ev );
}, [40]);
UI.KeyHandler.addCallback ('KeyShiftArrowBack', function ( key, c, ev ) {
var mt_on = activeMultitrackFor ( app );
if (UI.InteractionHandler.on ||
(ev && (ev.ctrlKey || ev.metaKey)) ||
(!PKAudioEditor.engine.is_ready && !mt_on)) return ;
ev && ev.preventDefault ();
seekRegionMarkerEdgeFor (PKAE, -1);
}, [16, 37]);
UI.KeyHandler.addCallback ('KeyShiftArrowFront', function ( key, c, ev ) {
var mt_on = activeMultitrackFor ( app );
if (UI.InteractionHandler.on ||
(ev && (ev.ctrlKey || ev.metaKey)) ||
(!PKAudioEditor.engine.is_ready && !mt_on)) return ;
ev && ev.preventDefault ();
seekRegionMarkerEdgeFor (PKAE, 1);
}, [16, 39]);
UI.KeyHandler.addCallback ('killctx', function ( e ) {
var event = new Event ('killCTX', {bubbles: true});
document.body.dispatchEvent (event);
}, [27]);
var btn_back_total = d.createElement ('button');
btn_back_total.setAttribute('tabIndex', -1);
btn_back_total.className = 'pk_btn icon-previous2';
btn_back_total.innerHTML = '<span>Seek Start (Shift + left arrow)</span>';
transport.appendChild ( btn_back_total );
btn_back_total.onclick = function() {
seekRegionMarkerEdgeFor (PKAE, -1);
this.blur();
};
var btn_front_total = d.createElement ('button');
btn_front_total.setAttribute('tabIndex', -1);
btn_front_total.className = 'pk_btn icon-next2';
btn_front_total.innerHTML = '<span>Seek End (Shift + right arrow)</span>';
btn_front_total.onclick = function() {
seekRegionMarkerEdgeFor (PKAE, 1);
this.blur();
};
transport.appendChild ( btn_front_total );
var btn_rec = d.createElement ('button');
btn_rec.setAttribute('tabIndex', -1);
btn_rec.className = 'pk_btn icon-rec';
btn_rec.innerHTML = '<span>Record (R)</span>';
btn_rec.onclick = function() {
if (this.getAttribute('disabled') === 'disabled') {
this.blur (); return ;
}
UI.fireEvent('RequestActionRecordToggle');
this.blur();
};
UI.listenFor ('ErrorRec', function() {
btn_rec.style.opacity = 0.6;
btn_rec.setAttribute("disabled", "disabled");
});
transport.appendChild ( btn_rec );
UI.KeyHandler.addCallback ('KeyRecR', function( k ) {
if (UI.InteractionHandler.on) return ;
btn_rec.click ();
}, [82]);
UI.listenFor ('DidActionRecordStart', function () {
btn_rec.classList.add ('pk_act');
});
UI.listenFor ('DidActionRecordStop', function () {
btn_rec.classList.remove ('pk_act');
});
UI.KeyHandler.addCallback ('KeyTab', function ( key ) {
if (UI.InteractionHandler.on || !activeReadyFor ( app )) return ;
UI.fireEvent ('RequestViewCenterToCursor');
}, [9]);
var is_chrome = !!window.chrome;
var timing = d.createElement( 'div' );
timing.className = 'pk_timecontainer';
var timingspan = d.createElement( 'span' );
if (!is_chrome)
{
timingspan.textContent = '00:00:000';
timingspan.className = 'pk_timing';
timing.appendChild( timingspan );
}
/////
var pk_timingcnv = d.createElement( 'canvas' );
pk_timingcnv.className = 'pk_timingcnv';
pk_timingcnv.width = 150;
pk_timingcnv.height = 40;
var pk_timingnum = '00:00:000';
var pk_timingctx = pk_timingcnv.getContext('2d', {alpha:false});
var timing_caches = {};
if (is_chrome)
{
timing.appendChild( pk_timingcnv );
pk_timingctx.fillStyle = "#000";
pk_timingctx.fillRect(0, 0, 150, 40);
for (var ii = 0; ii < 11; ++ii)
{
var curr_cache = d.createElement('canvas');
curr_cache.width = 18;
curr_cache.height = 26;
var curr_ctx = curr_cache.getContext('2d', {alpha:false});
curr_ctx.font = "29px Helvetica, Arial, sans-serif";
curr_ctx.textAlign = "center";
curr_ctx.fillStyle = "#000";
curr_ctx.fillRect(0, 0, 18, 26);
curr_ctx.fillStyle = "#fff";
curr_ctx.textBaseline = 'middle';
if (ii === 10) {
curr_ctx.fillText (':', 8, 14);
timing_caches[':'] = curr_cache;
}
else {
curr_ctx.fillText (ii + '', 9, 14);
timing_caches[ii+''] = curr_cache;
}
// timing_caches.push (curr_cache);
// document.body.appendChild( curr_cache );
}
(function (pk_timingctx, timing_caches){
var ttm = '00:00:000';
for (var jk = 0; jk < ttm.length; ++jk)
{
pk_timingctx.drawImage (timing_caches[ttm[jk]], jk * 16, 10);
}
})(pk_timingctx, timing_caches);
}
/////
var total_duration = d.createElement( 'span' );
total_duration.textContent = '00:00:000';
total_duration.className = 'pk_total_dur';
timing.appendChild( total_duration );
var hover_duration = d.createElement( 'span' );
hover_duration.textContent = '00:00:000';
hover_duration.className = 'pk_hover_dur';
timing.appendChild( hover_duration );
var tb = null, tc = 0, td = 0;
function closeTB () {
if (!tb) return ;
d.removeEventListener ('mousedown', tb._off);
tb.parentNode && tb.parentNode.removeChild (tb);
tb = null;
}
function tnav ( b, a, go, cl ) {
b.onkeydown = function (ev) {
var k = ev.keyCode, j;
ev.stopPropagation ();
if (k === 13) go ();
else if (k === 27) cl ();
else if (k > 36 && k < 41 && (j = a.indexOf (ev.target)) > -1) {
if ((k === 37 || k === 39) && ev.target.tagName === 'INPUT' &&
(ev.target.selectionStart !== ev.target.selectionEnd ||
(k === 37 && ev.target.selectionStart > 0) ||
(k === 39 && ev.target.selectionEnd < ev.target.value.length))) return ;
j = (j + (k < 39 ? -1 : 1) + a.length) % a.length;
a[j].focus ();
a[j].tagName === 'INPUT' && a[j].select ();
ev.preventDefault ();
}
};
}
function openTB ( e ) {
e && e.stopPropagation ();
e && e.preventDefault ();
var dur = activeDurationFor ( app ) || td || 0;
closeTB ();
var t = Math.max (0, Math.min (dur, tc || activeCursorTimeFor ( app ) || 0));
var s = t >> 0;
var ms = ((t - s) * 1000 + 0.5) >> 0;
if (ms > 999) { ms = 0; ++s; }
var m = (s / 60) >> 0;
s %= 60;
var b = tb = d.createElement ('div');
b.className = 'pk_pgeq_freq';
b.style.padding = '3px 16px';
b.style.paddingRight = '6px';
b.innerHTML =
'<input class="pk_mtbeat_bpm" style=width:46px> <b>:</b> <input class="pk_mtbeat_bpm" style=width:46px>' +
' <b>:</b> <input class="pk_mtbeat_bpm" style=width:46px> <button class="pk_modal_a_bottom pk_modal_a_accpt" style="float:none;display:inline-block;vertical-align:middle">Go</button>';
d.body.appendChild ( b );
var i = b.getElementsByTagName ('input');
var g = b.lastChild;
var a = [i[0], i[1], i[2], g];
i[0].value = m; i[1].value = s; i[2].value = ms;
var r = timing.getBoundingClientRect ();
b.style.left = (r.left|0) + 'px';
b.style.top = ((r.top + 3)|0) + 'px';
function go () {
var durr = activeDurationFor ( app ) || td || 0;
if (!(durr > 0)) return closeTB ();
var v = Math.max (0, Math.min (durr, ((i[0].value|0) * 60) + (i[1].value|0) + ((i[2].value|0) / 1000)));
tc = v;
drawT (v);
UI.fireEvent ('RequestSeekTo', v / durr);
closeTB ();
}
b._off = function ( ev ) { if (!b.contains (ev.target) && !timing.contains (ev.target)) closeTB (); };
tnav ( b, a, go, closeTB );
g.onclick = go;
d.addEventListener ('mousedown', b._off);
i[0].focus ();
i[0].select ();
}
timing.onmousedown = openTB;
setTimeout(function () {
UI.listenFor ('DidZoom', function (v, f) {
// do something smarter for f (event) ####
if (f)
hover_duration.textContent = formatTime (
PKAudioEditor.engine.wavesurfer.drawer.handleEvent(f) *
PKAudioEditor.engine.wavesurfer.VisibleDuration +
PKAudioEditor.engine.wavesurfer.LeftProgress );
});
var old_refresh = 0;
var avv = d.getElementsByClassName('pk_av')[0];
if (!avv) return;
avv.addEventListener ('mousemove', function ( e ) {
// re-run the mousemove fam on zoom based on the pointer position)
// throttle this as well #### violation
var new_refresh = e.timeStamp;
if (new_refresh - old_refresh < 58) {
return ;
}
old_refresh = new_refresh;
hover_duration.textContent = formatTime (
PKAudioEditor.engine.wavesurfer.drawer.handleEvent( e ) *
PKAudioEditor.engine.wavesurfer.VisibleDuration +
PKAudioEditor.engine.wavesurfer.LeftProgress );
}, false);
var main_context = PKAudioEditor._deps.ContextMenu ( avv );
main_context.addOption ('Select Visible View', function( e,x,i ) {
UI.fireEvent ('RequestRegionSet');
}, false );
main_context.addOption ('Reset Zoom', function( e ) {
UI.fireEvent ('RequestZoomUI', 0);
}, false );
UI.listenFor ('DidHoverTime', function ( time ) {
hover_duration.textContent = formatTime ( time );
});
main_context.addOption ('Set Volume/Gain', function( e ) {
UI.fireEvent ('RequestFXUI_Gain');
}, false );
main_context.addOption ('Seamless Loop...', function( e ) {
UI.fireEvent ('RequestActionFXUI_SeamlessLoop');
}, false );
main_context.addOption ('Copy', function( e ) {
var region = PKAudioEditor.engine.wavesurfer.regions.list[0];
if (!region) return ;
UI.fireEvent( 'RequestActionCopy');
}, false );
main_context.addOption ('Paste', function( e ) {
if (!copable) return ;
UI.fireEvent( 'RequestActionPaste');
}, false );
main_context.addOption ('Cut', function( e ) {
var region = PKAudioEditor.engine.wavesurfer.regions.list[0];
if (!region) return ;
UI.fireEvent( 'RequestActionCut', 1);
}, false );
main_context.addOption ('Insert Silence', function( e ) {
UI.fireEvent ('RequestFXUI_Silence', 0); // #### call effect
}, false );
// ---
var copable = false;
UI.listenFor ('DidSetClipboard', function ( val ) {
if (val)
copable = true;
else
copable = false;
});
main_context.onOpen = function ( menu, div ) {
var divs = div.childNodes;
if (!copable) divs[5].className += ' pk_inact';
UI.fireEvent ('RequestPause');
var region = PKAudioEditor.engine.wavesurfer.regions.list[0];
if (region) return ;
divs[3].className += ' pk_inact';
divs[4].className += ' pk_inact';
divs[6].className += ' pk_inact';
};
}, 1000);
UI.listenFor ('DidUpdateLen', function( val ) {
td = val || 0;
total_duration.textContent = formatTime (val);
});
function formatTime( time ) {
var time_s = time >> 0;
var miliseconds = time - time_s;
if (time_s < 10)
{
if (time === 0) return '00:00:000';
time_s = '00:0' + time_s;
}
else if (time_s < 60)
{
time_s = '00:' + time_s;
}
else
{
var m = (time_s / 60) >> 0;
var s = (time_s % 60);
time_s = ((m<10)?'0':'') + m + ':' + (s < 10 ? '0'+s : s);
}
if (miliseconds < 0.1)
{
return time_s + ':0' + (miliseconds < 0.01 ? '0' : '') + ((miliseconds*1000)>>0);
}
return time_s + ':' + ((miliseconds*1000)>>0); // (miliseconds+'').substr(2, 3);
}
UI.formatTime = formatTime;
function drawT ( time ) {
var ttm = formatTime (time);
if (!is_chrome)
{
timingspan.textContent = ttm;
return ;
}
var exit = false;
for (var jk = 0; jk < ttm.length; ++jk)
{
if (!exit)
{
if (ttm[jk] === pk_timingnum[jk]) continue;
exit = true;
}
pk_timingctx.drawImage (timing_caches[ttm[jk]], jk * 16, 10);
}
pk_timingnum = ttm;
}
function formatTimelineTime ( time, format ) {
var time_s = time >> 0;
var miliseconds = time - time_s;
if (time_s < 10)
time_s = '00:0' + time_s;
else if (time_s < 60)
time_s = '00:' + time_s;
else
{
var m = (time_s / 60) >> 0;
var s = (time_s % 60);
time_s = ((m<10)?'0':'') + m + ':' + (s < 10 ? '0'+s : s);
}
if (format === 1)
return time_s + ':' + (miliseconds+'').substr(2, 2);
return time_s;
}
UI.formatTimelineTime = formatTimelineTime;
function timelineRuler ( total, width, left_offset, visible_width ) {
var data = {step: 0, ticks: [], halves: []};
if (!total || !width) return data;
var pixel_distance = width / total;
if (pixel_distance < 60)
pixel_distance = 60;
else if (pixel_distance > 160)
pixel_distance /= ((pixel_distance / 160) >> 0) + 1;
data.step = pixel_distance;
left_offset = left_offset || 0;
visible_width = visible_width || width;
var step_time = pixel_distance / width * total;
var format = step_time < 1.0 ? 1 : (step_time < 60 ? 2 : 3);
var x = Math.max (0, (((left_offset - 2) / pixel_distance) >> 0) * pixel_distance);
var end = left_offset + visible_width + 2;
for (; x <= end && x < width - 2; x += pixel_distance)
{
if (x >= left_offset - 2)
data.ticks.push ({
x: x,
time: x / width * total,
label: formatTimelineTime ( x / width * total, format )
});
}
x = Math.max (pixel_distance / 2,
((((left_offset - 2 - pixel_distance / 2) / pixel_distance) >> 0) * pixel_distance) + pixel_distance / 2);
for (; x <= end && x < width - 2; x += pixel_distance)
if (x >= left_offset - 2) data.halves.push ( x );
return data;
}
UI.timelineRuler = timelineRuler;
function drawTimelineRuler ( ctx, total, width, left_offset, visible_width ) {
var data = timelineRuler ( total, width, left_offset, visible_width );
ctx.fillStyle = '#111';
ctx.fillRect (0, 0, visible_width, 24);
ctx.fillStyle = '#aaa';
ctx.strokeStyle = '#aaa';
ctx.textAlign = 'center';
for (var i = 0; i < data.ticks.length; ++i)
ctx.fillText ( data.ticks[i].label, data.ticks[i].x - left_offset, 12 );
ctx.beginPath ();
for (i = 0; i < data.ticks.length; ++i) {
var x = data.ticks[i].x - left_offset;
ctx.moveTo (x, 16);
ctx.lineTo (x, 24);
}
for (i = 0; i < data.halves.length; ++i) {
x = data.halves[i] - left_offset;
ctx.moveTo (x, 19);
ctx.lineTo (x, 24);
}
ctx.stroke ();
return data;
}
UI.drawTimelineRuler = drawTimelineRuler;
var volume1 = 0;
var volume2 = 0;
var old_refresh = 0;
var wvpnt = document.querySelector('.pk_wavepoint');
UI.listenFor ('DidAudioProcess', function( val ) {
var time = val[0];
var loudness = val[1];
if (time > -1) tc = time;
var new_refresh = val[2] || w.performance.now ();
if (new_refresh - old_refresh < 50) {
return ;
}
old_refresh = new_refresh;
if (time > -1)
{
drawT (time);
var mt_on = activeMultitrackFor ( app );
var zoomed = mt_on ?
mt_on.GetZoomFactor () > 1 :
PKAudioEditor.engine.wavesurfer.ZoomFactor > 1;
if (zoomed)
{
var perc = mt_on ?
mt_on.GetCursorPercent () :
time / PKAudioEditor.engine.wavesurfer.getDuration ();
if (!wvpnt) wvpnt = document.querySelector('.pk_wavepoint');
wvpnt.style.left = ((perc * 10000)>>0)/100 + '%';
// wvpnt.style.left = ((perc * 100).toFixed(2)/1) + '%';
}
}
if (!loudness)
{
UI.footer.volumeGaugePeaker.className = 'pk_peaker';
UI.footer.volumeGaugePeaker2.className = 'pk_peaker';
UI.footer.volumeGaugeInner.style.transform = 'translate3d(0,0,0)';
UI.footer.volumeGaugeInner2.style.transform = 'translate3d(0,0,0)';
// UI.footer.volumeGaugeInner.style.width = '100%';
// UI.footer.volumeGaugeInner2.style.width = '100%';
}
else if (loudness[0] > 0) {
UI.footer.volumeGaugePeaker.className = 'pk_peaker pk_act';
UI.footer.volumeGaugeInner.style.transform = 'translate3d(100%,0,0)';
// UI.footer.volumeGaugeInner.style.width = '0%';
volume1 = 100;
var peak_time = activeCursorTimeFor ( app );
UI.footer.volumeGaugePeaker.setAttribute ('title', 'Peak at ' + peak_time.toFixed(2) );
if (loudness[1] > 0) {
UI.footer.volumeGaugePeaker2.className = 'pk_peaker pk_act';
UI.footer.volumeGaugeInner2.style.transform = 'translate3d(100%,0,0)';
// UI.footer.volumeGaugeInner2.style.width = '0%';
volume2 = 100;
UI.footer.volumeGaugePeaker2.setAttribute ('title', 'Peak at ' + peak_time.toFixed(2) );
}
}
else if (loudness[1] > 0) {
UI.footer.volumeGaugePeaker2.className = 'pk_peaker pk_act';
UI.footer.volumeGaugeInner2.style.transform = 'translate3d(100%,0,0)';
// UI.footer.volumeGaugeInner2.style.width = '0%';
volume2 = 100;
var peak_time2 = activeCursorTimeFor ( app );
UI.footer.volumeGaugePeaker2.setAttribute ('title', 'Peak at ' + peak_time2.toFixed(2) );
}
else
{
var tmp = (100 + loudness[0]);
if (tmp < -100) volume1 = 0; // tmp = -100;
else
{
volume1 = volume1 + (tmp - volume1)/4;
if (isNaN (volume1)) volume1 = 0;
}
tmp = (100 + loudness[1]);
if (tmp < -100) volume2 = 0; //tmp = -100;
else
{
volume2 = volume2 + (tmp - volume2)/4;
if (isNaN (volume2)) volume2 = 0;
}
UI.footer.volumeGaugeInner.style.transform = 'translate3d(' + volume1 + '%,0,0)';
UI.footer.volumeGaugeInner2.style.transform = 'translate3d(' + volume2 + '%,0,0)';
// UI.footer.volumeGaugeInner.style.width = (100 - volume1) + '%';
// UI.footer.volumeGaugeInner2.style.width = (100 - volume2) + '%';
}
});
var actions = d.createElement( 'div' );
actions.className = 'pk_ctns';
var copy_btn = d.createElement ('button');
copy_btn.setAttribute('tabIndex', -1);
copy_btn.className = 'pk_btn icon-files-empty pk_inact';
copy_btn.innerHTML = '<span>Copy Selection (Shift + C)</span>';
actions.appendChild ( copy_btn );
copy_btn.onclick = function() {
UI.fireEvent( 'RequestActionCopy');
this.blur();
};
UI.listenFor ('DidSetClipboard', function ( val ) {
if (val)
paste_btn.classList.remove ('pk_inact');
else
paste_btn.classList.add ('pk_inact');
});
var paste_btn = d.createElement ('button');
paste_btn.setAttribute('tabIndex', -1);
paste_btn.className = 'pk_btn icon-file-text2 pk_inact';
paste_btn.innerHTML = '<span>Paste Selection (Shift + V)</span>';
actions.appendChild ( paste_btn );
paste_btn.onclick = function() {
UI.fireEvent( 'RequestActionPaste');
this.blur();
};
var cut_btn = d.createElement ('button');
cut_btn.setAttribute('tabIndex', -1);
cut_btn.className = 'pk_btn icon-scissors pk_inact';
cut_btn.innerHTML = '<span>Cut Selection (Shift + X)</span>';
actions.appendChild ( cut_btn );
cut_btn.onclick = function() {
UI.fireEvent( 'RequestActionCut', 1);
this.blur();
};
UI.listenFor ('DidSelectClip', function () {
copy_btn.classList.remove ('pk_inact');
cut_btn.classList.remove ('pk_inact');
btn_clear_selection.classList.remove ('pk_inact');
});
UI.listenFor ('DidDeselectClip', function () {
copy_btn.classList.add ('pk_inact');
cut_btn.classList.add ('pk_inact');
});
var silence_btn = d.createElement ('button');
silence_btn.setAttribute('tabIndex', -1);
silence_btn.className = 'pk_btn icon-silence';
silence_btn.innerHTML = '<span>Insert Silence (Shift + N)</span>';
actions.appendChild ( silence_btn );
UI.KeyHandler.addCallback ('KeyShiftN', function( k, m, e ) {
if (UI.InteractionHandler.on || (e && (e.ctrlKey || e.metaKey))) return ;
silence_btn.click ();
},[16, 78]);
silence_btn.onclick = function() {
UI.fireEvent( 'RequestFXUI_Silence');
this.blur();
};
var selection = d.createElement( 'div' );
selection.className = 'pk_selection';
selection.innerHTML = '<div class="pk_sellist">' +
'<span class="pk_title">Selection:</span>' +
'<div><span class="title">Start:</span><span class="s_s pk_dat">-</span></div>' +
'<div><span class="title">End:</span><span class="s_e pk_dat">-</span></div>' +
'<div><span class="title">Duration:</span><span class="s_d pk_dat">-</span></div>' +
'</div>';
var btn_clear_selection = d.createElement ('button');
btn_clear_selection.setAttribute('tabIndex', -1);
btn_clear_selection.className = 'pk_btn icon-clearsel pk_inact';
btn_clear_selection.innerHTML = '<span>Clear Selection (Q key)</span>';
var sel_spans = selection.getElementsByClassName('pk_dat');
var sb = null, sr = null, sd = 0;
function closeSB () {
if (!sb) return ;
d.removeEventListener ('mousedown', sb._off);
sb.parentNode && sb.parentNode.removeChild (sb);
sb = null;
}
function openSB ( e ) {
var rg = sr, dur = sd || activeDurationFor ( app );
if (!rg || !(dur > 0)) return ;
e.stopPropagation ();
e.preventDefault ();
closeSB ();
var b = sb = d.createElement ('div');
b.className = 'pk_pgeq_freq';
b.style.cssText = 'padding:6px 10px;width:auto;white-space:nowrap';
b.innerHTML = '<b style=font-size:12px>Start</b> <input class="pk_mtbeat_bpm" style=width:62px> <b style=font-size:12px>End</b> <input class="pk_mtbeat_bpm" style=width:62px> <button class="pk_modal_a_bottom pk_modal_a_accpt" style="float:none;display:inline-block;vertical-align:middle">Go</button>';
d.body.appendChild ( b );
var i = b.getElementsByTagName ('input');
var g = b.lastChild;
var a = [i[0], i[1], g];
i[0].value = rg.start.toFixed (3);
i[1].value = rg.end.toFixed (3);
var r = selection.getBoundingClientRect ();
b.style.left = (r.left|0) + 'px';
b.style.top = ((r.top + 3)|0) + 'px';
function go () {
var rg = sr;
var a = parseFloat (i[0].value), z = parseFloat (i[1].value);
if (!rg) return closeSB ();
dur = sd || activeDurationFor ( app ) || dur;
if (!(a >= 0)) a = rg.start;
if (!(z >= 0)) z = rg.end;
a = Math.max (0, Math.min (dur, a));
z = Math.max (0, Math.min (dur, z));
if (Math.abs (z - a) > 0.001) UI.fireEvent ('RequestRegionSet', a, z);
closeSB ();
}
b._off = function ( ev ) { if (!b.contains (ev.target) && !selection.contains (ev.target)) closeSB (); };
tnav ( b, a, go, closeSB );
g.onclick = go;
d.addEventListener ('mousedown', b._off);
i[e.target === sel_spans[1] ? 1 : 0].focus ();
}
sel_spans[0].onmousedown = sel_spans[1].onmousedown = sel_spans[2].onmousedown = openSB;
UI.listenFor ('DidCreateRegion', function ( region ) {
if (region && region.mt)
{
copy_btn.classList.add ('pk_inact');
cut_btn.classList.add ('pk_inact');
}
else
{
copy_btn.classList.remove ('pk_inact');
cut_btn.classList.remove ('pk_inact');
}
btn_clear_selection.classList.remove ('pk_inact');
if (region)
{
sr = region;
sd = activeDurationFor ( app ) || region.end || 0;
if (!sel_spans[0]) sel_spans = document.querySelectorAll('.pk_sellist .pk_dat');
sel_spans[0].textContent = region.start.toFixed(3);
sel_spans[1].textContent = region.end.toFixed(3);
sel_spans[2].textContent = (region.end - region.start).toFixed(3);
}
});
UI.listenFor ('DidDestroyRegion', function () {
copy_btn.classList.add ('pk_inact');
cut_btn.classList.add ('pk_inact');
btn_clear_selection.classList.add ('pk_inact');
closeSB ();
sr = null;
sd = 0;
if (!sel_spans[0]) sel_spans = document.querySelectorAll('.pk_sellist .pk_dat');
sel_spans[0].textContent = '-';
sel_spans[1].textContent = '-';
sel_spans[2].textContent = '-';
});
btn_clear_selection.onclick = function () {
UI.fireEvent( 'RequestRegionClear');
this.blur ();
};
selection.appendChild ( btn_clear_selection );
toolbar.appendChild ( timing );
UI.listenFor ('DidChanToggle', function ( chan, val ) {
var region = PKAudioEditor.engine.wavesurfer.regions.list[0];
if (!region) return ;
if (val === 1) {
region.element.style.top = '0';
region.element.style.height = '100%';
return ;
}
if (chan === 0) {
region.element.style.top = '50%';
region.element.style.height = '50%';
return ;
}
if (chan === 1) {
region.element.style.top = '0';
region.element.style.height = '50%';
}
//
});
// end
toolbar.appendChild ( btn_groups );
btn_groups.appendChild ( transport );
btn_groups.appendChild ( actions );
toolbar.appendChild ( selection );
container.appendChild ( toolbar );
UI.el.appendChild ( container );
_bindToolbarTips ( UI, container );
var _appEl = UI.el || d.getElementById('app');
_appEl.addEventListener('dragover', function ( e ) {
var mt = PKAudioEditor && PKAudioEditor.multitrack;
if (mt && mt.IsOn && mt.IsOn ()) {
e.preventDefault ();
}
}, true);
_appEl.addEventListener('drop', function ( e ) {
var mt = PKAudioEditor && PKAudioEditor.multitrack;
if (!mt || !mt.IsOn || !mt.IsOn ()) return ;
var t = e.target;
while (t && t !== _appEl) {
if (t.classList && (
t.classList.contains ('pk_mt_lane') ||
t.classList.contains ('pk_mt_track')
)) return ;
t = t.parentNode;
}
if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) return ;
e.preventDefault ();
e.stopPropagation ();
mt.AddFilesAuto ( e.dataTransfer.files );
}, true);
dragNDrop( _appEl, 'pk_overlay', function ( e, name ) {
var mt = PKAudioEditor && PKAudioEditor.multitrack;
if (mt && mt.IsOn && mt.IsOn ()) return ;
if (mt && mt.LoadSessionBuffer) {
if (mt.LoadSessionBuffer ( e, name )) return ;
if (/\.amss$/i.test (name || '')) {
OneUp ('Could not load session', 1400);
return ;
}
}
PKAudioEditor.engine.LoadArrayBuffer ( new Blob([e]) );
}, 'arrayBuffer' );
// -
};
function _makeMobileScroll (UI) {
var isControlTouch = function ( target ) {
while (target && target !== d.body) {
if (/^(BUTTON|A|INPUT|SELECT|TEXTAREA|LABEL)$/i.test (target.tagName || '')) return true;
if (target.classList && (
target.classList.contains ('pk_btn') ||
target.classList.contains ('pk_mt') ||
target.classList.contains ('pk_mt_topbtn') ||
target.classList.contains ('pk_modal_a_bottom')
)) return true;
target = target.parentNode;
}
return false;
};
var getFactor = function () {
var screen_h = window.screen.height;
var screen_w = window.screen.width;
var iw = window.innerWidth;
var ih = window.innerHeight;
var bars_visible = false;
var ratio = 0;
if (window.orientation === 0) {
ratio = ih / screen_h;
}
else if (window.orientation === 90 || window.orientation === -90) {
ratio = ih / screen_w;
}
if (ratio < 0.8) bars_visible = true;
return (bars_visible);
};
var ex = -1;
var ey = -1;
var allow = false;
// var first = false;
d.body.addEventListener ('touchstart', function( e ) {
ex = e.touches[0].pageX;
ey = e.touches[0].pageY;
// first = true;
allow = false;
});
d.body.addEventListener ('touchend', function( e ) {
ex = -1;
ey = -1;
// first = false;
allow = false;
});
d.body.addEventListener ('touchmove', function( e ) {
if (isControlTouch ( e.target )) return ;
if (allow) return ;
var ny = e.touches[0].pageY;
var nx = e.touches[0].pageX;
var direction = ey - ny;
var direction2 = ex - nx;
// if (first) {
// first = false;
// }
if ( direction === 0 || (Math.abs (direction) < 3 && Math.abs (direction2) > 3 ) || (Math.abs (direction) < 6 && Math.abs (direction2) > 10 ) ) {
ey = ny;
ex = nx;
allow = true;
return ;
}
ey = ny;
ex = nx;
var xx = document.getElementsByClassName ('pk_modal_back');
if (xx[0])
{
xx = xx[0];
if ( xx.scrollHeight > window.innerHeight )
{
var scrolled = xx.scrollTop;
if (direction > 0)
{
var modal_h = document.getElementsByClassName ('pk_modal')[0].clientHeight;
if ((modal_h - scrolled) < (window.innerHeight - 80))
{
e.preventDefault ();
}
}
else
{
if (scrolled <= 0)
{
e.preventDefault ();
}
}
allow = true;
return ;
}
else
{
e.preventDefault ();
allow = true;
return ;
}
}
if (!getFactor ()) {
e.preventDefault ();
allow = true;
}
}, {passive:false});
};
// ---
PKAE._deps.ui = PKUI;
})( window, document, PKAudioEditor );