457 lines
9.9 KiB
JavaScript
457 lines
9.9 KiB
JavaScript
(function ( w, d, PKAE ) {
|
|
'use strict';
|
|
|
|
var _pid = 0;
|
|
var _aid = 0;
|
|
|
|
function FXAutomation ( app, filter_modal, val_cb, preview_cb ) {
|
|
var q = this;
|
|
|
|
q.modal = filter_modal;
|
|
q.app = app;
|
|
q.wv = app.engine.wavesurfer;
|
|
q.points = {};
|
|
q.act = null;
|
|
q.act_point = null;
|
|
q.in_auto = false;
|
|
q.rbuff = null;
|
|
|
|
q.btn_auto = _make_btn_auto ( q );
|
|
|
|
q.GetValue = function () {
|
|
var data = [];
|
|
|
|
var inputs = q.modal.el_body.getElementsByTagName('input');
|
|
var plen = q.points.length;
|
|
|
|
for (var i = 0; i < inputs.length; ++i)
|
|
{
|
|
var curr = inputs[i];
|
|
if (q.points[curr.id])
|
|
{
|
|
var arr = [];
|
|
var p = q.points[curr.id];
|
|
for (var j = 0; j < p.length; ++j)
|
|
{
|
|
var tmp = {
|
|
time: p[j].time,
|
|
val: p[j].val
|
|
};
|
|
arr.push(tmp);
|
|
val_cb && val_cb (tmp, curr);
|
|
}
|
|
data.push (arr);
|
|
}
|
|
else
|
|
{
|
|
var tmp = {
|
|
val: curr.value
|
|
};
|
|
|
|
data.push (tmp);
|
|
val_cb && val_cb (tmp, curr);
|
|
}
|
|
}
|
|
|
|
return (data);
|
|
};
|
|
|
|
q.cw = 500;
|
|
q.ch = 200;
|
|
var els = _make_canvas ( q, q.cw, q.ch );
|
|
q.canvas = els[0];
|
|
q.ctx = els[1];
|
|
|
|
|
|
var _fillstyle = '#d9d955';
|
|
q.Render = function () {
|
|
var ctx = q.ctx;
|
|
var cw = q.cw;
|
|
var ch = q.ch;
|
|
|
|
if (q.rbuff)
|
|
q.app.engine.GetWave (q.rbuff, 500, 200, null, null, q.canvas, q.ctx);
|
|
|
|
// ctx.clearRect (0, 0, q.cw, q.ch);
|
|
ctx.fillStyle = _fillstyle;
|
|
ctx.strokeStyle = '#FF0000';
|
|
|
|
if (!q.act) return ;
|
|
|
|
ctx.beginPath ();
|
|
ctx.moveTo ( 0, ch / 2 );
|
|
var last_y = ch / 2;
|
|
|
|
for (var o = 0; o < q.points[q.act.id].length; ++o)
|
|
{
|
|
var curr = q.points[q.act.id][ o ];
|
|
|
|
var center_x = curr.ax;
|
|
var center_y = curr.ay;
|
|
|
|
ctx.lineTo ( center_x, center_y );
|
|
last_y = center_y;
|
|
}
|
|
|
|
ctx.lineTo ( cw, last_y );
|
|
ctx.stroke ();
|
|
|
|
var radius = 6;
|
|
for (var o = 0; o < q.points[q.act.id].length; ++o)
|
|
{
|
|
var curr = q.points[q.act.id][ o ];
|
|
|
|
var center_x = curr.ax;
|
|
var center_y = curr.ay;
|
|
|
|
ctx.beginPath ();
|
|
ctx.arc (center_x, center_y, radius, 0, 2 * Math.PI, false);
|
|
|
|
if (curr === q.act_point) {
|
|
ctx.shadowBlur = 24;
|
|
|
|
if (curr._on)
|
|
ctx.fillStyle = '#fff';
|
|
else
|
|
ctx.fillStyle = '#686868';
|
|
|
|
ctx.stroke ();
|
|
ctx.fill ();
|
|
|
|
ctx.shadowBlur = 0;
|
|
ctx.fillStyle = _fillstyle;
|
|
}
|
|
else if (curr._hov) {
|
|
|
|
if (curr._on)
|
|
ctx.fillStyle = 'blue';
|
|
else
|
|
ctx.fillStyle = 'darkblue';
|
|
|
|
ctx.stroke ();
|
|
ctx.fill ();
|
|
|
|
ctx.fillStyle = _fillstyle;
|
|
}
|
|
else if (curr._on) {
|
|
ctx.fill ();
|
|
}
|
|
else {
|
|
ctx.fillStyle = '#555';
|
|
ctx.fill ();
|
|
ctx.fillStyle = _fillstyle;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
_make_controls ( q );
|
|
|
|
// -------
|
|
function _make_controls ( q ) {
|
|
var click_time = 0;
|
|
q.canvas.addEventListener ('click', function ( e ) {
|
|
if (!q.act) return;
|
|
if (e.timeStamp - click_time < 260)
|
|
{
|
|
var bounds = q.canvas.getBoundingClientRect ();
|
|
var cw = q.cw;
|
|
var ch = q.ch;
|
|
var posx = e.clientX - bounds.left;
|
|
var posy = e.clientY - bounds.top;
|
|
|
|
var rel_x = posx / cw;
|
|
var rel_y = posy / ch;
|
|
|
|
if (!q.points[q.act.id]) q.points[q.act.id] = [];
|
|
|
|
var duration;
|
|
var region = q.wv.regions.list[0];
|
|
if (region) {
|
|
duration = region.end - region.start;
|
|
} else {
|
|
duration = q.wv.getDuration();
|
|
}
|
|
|
|
q.points[q.act.id].push ({
|
|
// el:q.act.el,
|
|
id: ++_pid,
|
|
x: rel_x,
|
|
y: rel_y,
|
|
ax: rel_x * cw,
|
|
ay: rel_y * ch,
|
|
time: duration * rel_x,
|
|
val : ((1 - rel_y) * (q.act.max - q.act.min)) + q.act.min,
|
|
_on: true,
|
|
_hov: false,
|
|
});
|
|
|
|
q.points[q.act.id].sort( _compare );
|
|
q.act_point = q.points[q.act.id][q.points[q.act.id].length - 1];
|
|
|
|
//_process ( q, q.wv.backend.buffer );
|
|
|
|
q.Render ();
|
|
// ----
|
|
}
|
|
|
|
click_time = e.timeStamp;
|
|
}, false);
|
|
|
|
var is_dragging = false;
|
|
var skip = 3;
|
|
q.canvas.addEventListener ('mousemove', function ( e ) {
|
|
if (!is_dragging || !q.act_point) return ;
|
|
|
|
var ex = 0;
|
|
var ey = 0;
|
|
|
|
if (e.touches) {
|
|
if (e.touches.length > 1) { return ; }
|
|
|
|
ex = e.touches[0].clientX;
|
|
ey = e.touches[0].clientY;
|
|
} else {
|
|
ex = e.clientX;
|
|
ey = e.clientY;
|
|
}
|
|
|
|
var bounds = q.canvas.getBoundingClientRect ();
|
|
var cw = q.cw;
|
|
var ch = q.ch;
|
|
|
|
var posx = ex - bounds.left;
|
|
var posy = ey - bounds.top;
|
|
|
|
var rel_x = posx / cw;
|
|
var rel_y = posy / ch;
|
|
|
|
q.act_point.ax = posx;
|
|
q.act_point.ay = posy;
|
|
|
|
q.act_point.x = rel_x;
|
|
q.act_point.y = rel_y;
|
|
|
|
var duration;
|
|
var region = q.wv.regions.list[0];
|
|
if (region) {
|
|
duration = region.end - region.start;
|
|
} else {
|
|
duration = q.wv.getDuration();
|
|
}
|
|
|
|
q.act_point.time = duration * rel_x;
|
|
q.act_point.val = ((1 - rel_y) * q.act.max - q.act.min) + q.act.min;
|
|
|
|
q.Render ();
|
|
|
|
if (--skip === 0) {
|
|
skip = 4;
|
|
_process ( q, q.wv.backend.buffer );
|
|
}
|
|
});
|
|
|
|
q.canvas.addEventListener ('mousedown', function ( e ) {
|
|
is_dragging = false;
|
|
if (!q.act) return ;
|
|
|
|
var bounds = q.canvas.getBoundingClientRect ();
|
|
var cw = q.cw;
|
|
var ch = q.ch;
|
|
|
|
var posx = e.clientX - bounds.left;
|
|
var posy = e.clientY - bounds.top;
|
|
|
|
var dist_x = e.is_touch ? 20 : 10;
|
|
var dist_y = e.is_touch ? 20 : 9;
|
|
|
|
if (!q.points[q.act.id]) q.points[q.act.id] = [];
|
|
|
|
for (var o = 0; o < q.points[q.act.id].length; ++o)
|
|
{
|
|
var curr = q.points[q.act.id][ o ];
|
|
if ( Math.abs (curr.ax - posx) < dist_x && Math.abs (curr.ay - posy) < dist_y)
|
|
{
|
|
is_dragging = true;
|
|
q.act_point = curr;
|
|
q.Render ();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!is_dragging)
|
|
{
|
|
q.act_point = null;
|
|
q.Render ();
|
|
}
|
|
});
|
|
|
|
q.canvas.addEventListener ('mouseup', function ( e ) {
|
|
is_dragging = false;
|
|
});
|
|
|
|
|
|
var act_el = null;
|
|
q.modal.el_body.addEventListener ('mouseover', function(e) {
|
|
if (!q.in_auto) return ;
|
|
if (e.target.tagName === 'INPUT') {
|
|
e.target.classList.add ('pk_aut');
|
|
}
|
|
});
|
|
q.modal.el_body.addEventListener ('mouseout', function(e) {
|
|
if (!q.in_auto) return ;
|
|
if (e.target.tagName === 'INPUT') {
|
|
e.target.classList.remove ('pk_aut');
|
|
}
|
|
});
|
|
q.modal.el_body.addEventListener ('click', function(e) {
|
|
if (!q.in_auto) return ;
|
|
if (e.target.classList.contains ('pk_aut'))
|
|
{
|
|
if (act_el) {
|
|
act_el.classList.remove ('pk_aut_act');
|
|
act_el = null;
|
|
}
|
|
|
|
e.target.classList.add ('pk_aut_act');
|
|
act_el = e.target;
|
|
|
|
if (!e.target.id) e.target.id = 'pk' + (++_aid);
|
|
|
|
q.act = {
|
|
id: e.target.id,
|
|
el: e.target,
|
|
type:e.target.range,
|
|
min:e.target.min/1,
|
|
max:e.target.max/1,
|
|
step:e.target.step/1
|
|
};
|
|
|
|
if (!q.points[q.act.id]) q.points[q.act.id] = [];
|
|
|
|
q.Render ();
|
|
}
|
|
|
|
// console.log( 'click ', e.target );
|
|
});
|
|
};
|
|
|
|
|
|
function _make_btn_auto ( q ) {
|
|
var btn_automate = d.createElement ('a');
|
|
btn_automate.className = 'pk_modal_a_bottom';
|
|
btn_automate.innerHTML = 'AUTOMATE';
|
|
|
|
var in_auto = false;
|
|
btn_automate.onclick = function () {
|
|
q.in_auto = !q.in_auto;
|
|
|
|
if (q.in_auto) {
|
|
btn_automate.classList.add ('pk_act');
|
|
} else {
|
|
btn_automate.classList.remove ('pk_act');
|
|
}
|
|
};
|
|
|
|
q.modal.el_body.appendChild( btn_automate );
|
|
|
|
return (btn_automate);
|
|
};
|
|
|
|
function _make_canvas ( q ) {
|
|
var cc = document.createElement ('canvas');
|
|
cc.width = 500; cc.height = 200;
|
|
cc.style.background = '#000';
|
|
var ctx = cc.getContext('2d');
|
|
|
|
q.modal.el_body.appendChild( cc );
|
|
|
|
var buff = q.wv.backend.buffer;
|
|
|
|
var img = new Image();
|
|
img.onload = function () {
|
|
ctx.drawImage (img, 0, 0);
|
|
};
|
|
|
|
var offset; var length;
|
|
var region = q.wv.regions.list[0];
|
|
if (region) {
|
|
offset = (region.start * buff.sampleRate) >> 0;
|
|
length = (region.end * buff.sampleRate) >> 0;
|
|
}
|
|
|
|
_process ( q, buff );
|
|
|
|
img.src = q.app.engine.GetWave (buff, 500, 200, offset, length);
|
|
|
|
return ([cc, ctx]);
|
|
};
|
|
|
|
function _compare ( a, b ) {
|
|
if (a.x > b.x) return 1;
|
|
return -1;
|
|
};
|
|
|
|
function _process ( q, buffer ) {
|
|
var getOfflineAudioContext = function (channels, sampleRate, duration) {
|
|
return new (window.OfflineAudioContext ||
|
|
window.webkitOfflineAudioContext)(channels, duration, sampleRate);
|
|
};
|
|
|
|
var region = q.wv.regions.list[0];
|
|
var offs = 0;
|
|
var durr = buffer.duration;
|
|
if (region) {
|
|
offs = region.start;
|
|
durr = region.end - region.start;
|
|
}
|
|
|
|
var audio_ctx = getOfflineAudioContext (
|
|
1, // orig_buffer.numberOfChannels,
|
|
8000,
|
|
(durr * 8000) >> 0
|
|
);
|
|
|
|
var newbuffer = audio_ctx.createBuffer (1, durr * buffer.sampleRate, buffer.sampleRate);
|
|
newbuffer.getChannelData ( 0 ).set (
|
|
buffer.getChannelData ( 0 ).slice ( (offs * buffer.sampleRate) / 4, ((offs + durr) * buffer.sampleRate)/4 )
|
|
);
|
|
|
|
var source = audio_ctx.createBufferSource ();
|
|
source.buffer = newbuffer;
|
|
|
|
//var fx = q.app.engine.GetFX ('Gain', q.GetValue ());
|
|
//console.log ( fx.filter ( audio_ctx, audio_ctx.destination, source ) );
|
|
|
|
source.connect (audio_ctx.destination);
|
|
source.start (0); //, offs, durr);
|
|
|
|
var offline_callback = function( rendered_buffer ) {
|
|
q.rbuff = rendered_buffer;
|
|
|
|
debugger;
|
|
|
|
// var img = new Image();
|
|
// img.src = q.app.engine.GetWave (rendered_buffer, 500, 200);
|
|
|
|
q.Render ();
|
|
|
|
};
|
|
var offline_renderer = audio_ctx.startRendering();
|
|
if (offline_renderer)
|
|
offline_renderer.then( offline_callback ).catch(function(err) {
|
|
console.log('Rendering failed: ' + err);
|
|
});
|
|
else
|
|
audio_ctx.oncomplete = function ( e ) {
|
|
offline_callback ( e.renderedBuffer );
|
|
};
|
|
|
|
// ---------
|
|
};
|
|
};
|
|
|
|
PKAudioEditor._deps.FxAUT = FXAutomation;
|
|
|
|
})( window, document, PKAudioEditor ); |