Files
ace-step-ui/audiomass-editor/src/fx-auto.js
T

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 );