Files
ace-step-ui/server/audio-editor/fx-pg-eq.js
T

3067 lines
76 KiB
JavaScript
Executable File

(function ( w, d, PKAE ) {
'use strict';
var modal_name = 'modalfx';
var modal_esc_key = modal_name + 'esc';
var max_db_val = 35;
function PK_FX_PGEQ () {
var q = this;
var _id = 0;
var _is_render_scheduled = false;
var _is_render_scheduled2 = false;
q.act = null;
q.ranges = [];
q.ui = {};
this.Callback = function(){};
this.Init = function ( container ) {
var q = this;
q.el = container;
_make_ui ( q );
_make_evs ( q );
q.Render ();
};
this.Add = function (type, is_on, freq, gain, qval, coords_x, coords_y) {
var q = this;
var new_range = {
id: (++_id),
type: type ? type : 'peaking',
freq: freq || 0,
gain: gain || 0,
q: qval || 5,
// interface
_on: is_on,
_hov: false,
_el: null,
_coords: {
x: coords_x || 0,
y: coords_y || 0
},
_arr:[]
};
q.ranges.push (new_range);
q.ranges.sort (_compare);
if (q.act) {
q.act.el.classList.remove ('pk_act');
}
q.act = new_range;
_range_compute_arr (new_range);
new_range.el = _range_render_el (q, new_range, ' pk_act');
q.Callback && q.Callback ();
q.Render ();
};
this.Remove = function (range) {
var q = this;
var l = q.ranges.length;
while (l-- > 0) {
if (q.ranges[l] === range) {
q.ranges.splice (l, 1);
break;
}
}
if (range.el) {
range.el.parentNode.removeChild (range.el);
range.el = null;
}
if (q.act && q.act === range) {
q.act = null;
}
q.Render ();
};
var _fillstyle = '#d9d955';
var _anim_render = function () {
_render ( q );
};
this.Render = function () {
var q = this;
if (_is_render_scheduled) return ;
_is_render_scheduled = true;
requestAnimationFrame (_anim_render);
};
this.RenderBars = function (_, freq) {
var q = this;
if (_is_render_scheduled2) return ;
_is_render_scheduled2 = true;
requestAnimationFrame (function () {
_render_bars ( q, freq );
});
};
var _render_bars = function( q, freq ) {
_is_render_scheduled2 = false;
if (!freq) return ;
var ctx = q.ui.ctx_bars;
var canvas = q.ui.canvas_bars;
var cw = canvas.width;
var ch = canvas.height;
// ctx.fillStyle = '#000';
// ctx.fillRect (0, 0, cw, ch);
ctx.clearRect (0, 0, cw, ch);
var bufferLength = 512; // 256
var max_bars = 117 * 2;
var barWidth = (cw / max_bars).toFixed(1)/1;
var barHeight = 0;
var x = 0;
//
for (var i = 0; i < 117; ++i)
{
barHeight = freq[i];
// map.push ( i * 43 );
var newheight = ((barHeight / 256) * ch) >> 0;
ctx.fillRect (x, ch - newheight, barWidth, newheight);
x += barWidth;// + 1;
}
for (var i = 0; i < 117; ++i)
{
// (116*3.4)
barHeight = freq[117 + ((i * 3.34) >> 0)];
// map.push ( (120 + (i * 3)) * 43 );
var newheight = ((barHeight / 256) * ch) >> 0;
ctx.fillRect (x, ch - newheight, barWidth, newheight);
x += barWidth;// + 1;
}
// console.log( map );
// what if we care for the small bars first
/*
var steps = (total_freq/bufferLength) >> 0;
// we care for
// 256 bars
// 32
// 64
// 125
// 250
// 500
// 1000
// 2000
// 4000
// 8000
// 16000
// 20000
var arr = [32, 64, 125, 250, 500, 1000, 2000, 4000, 8000, 16000, 20000];
var curr = 0;
var curr_bars = 0;
var bars_per_entry = (bufferLength / 10) >> 0;
for (var i = 0; i < bufferLength; ++i) {
if (++curr_bars < bars_per_entry)
{
var ff = arr[ curr ];
var ff_next = arr[ curr + 1];
var m = 0;
for (; m < bufferLength; ++m)
{
if (m * steps > ff) {
--m;
break;
}
}
barHeight = freq[ m ];
var newheight = ((barHeight / 256) * ch) >> 0;
ctx.fillRect (x, ch - newheight, barWidth, newheight);
x += barWidth;// + 1;
}
else
{
++curr;
curr_bars = 0;
}
}
*/
// for (var i = 0; i < bufferLength; ++i) {
// barHeight = freq[i];
// var newheight = ((barHeight / 256) * ch) >> 0;
// ctx.fillRect (x, ch - newheight, barWidth, newheight);
// x += barWidth;// + 1;
// }
};
var line_arr = new Array (1000);
var _render = function ( q ) {
_is_render_scheduled = false;
var ctx = q.ui.ctx_eq;
var canvas = q.ui.canvas_eq;
var cw = canvas.width;
var ch = canvas.height;
var ch_half = ch / 2;
// --------------------
ctx.clearRect (0, 0, cw, ch);
ctx.fillStyle = _fillstyle;
if (q.ranges.length === 0)
{
ctx.beginPath ();
ctx.moveTo (0, ch_half);
ctx.lineTo (cw, ch_half);
ctx.stroke ();
return ;
}
// render the line based on the elements
var first = true;
var arr = [];
for (var i = 0; i < total; ++i) {
arr[i] = 0;
}
for (var o = 0; o < q.ranges.length; ++o)
{
var curr = q.ranges[ o ];
if (!curr._on) continue;
if (first)
{
first = false;
for (var i = 0; i < total; ++i)
{
line_arr[i] = curr._arr[i];
}
}
else
{
for (var i = 0; i < total; ++i)
{
line_arr[i] += curr._arr[i];
}
}
// ---
}
if (first)
{
ctx.beginPath ();
ctx.moveTo (0, ch_half);
ctx.lineTo (cw, ch_half);
ctx.stroke ();
}
else
{
// --
ctx.beginPath ();
ctx.moveTo ( 0, ch_half - (line_arr[ 0 ] * (ch_half / max_db_val)) );
for (var i = 0; i < (total / 4); i += 1) {
var el = line_arr[ i ];
var x = (i * 2) * (cw / total);
var y = ch_half - (el * (ch_half / max_db_val));
ctx.lineTo ( x, y );
}
var hh = 0;
for (var i = (total / 4); i < total; i += 3) {
var el = line_arr[ i ];
hh += 2;
var x = ((total / 2) + hh) * (cw / total);
var y = ch_half - (el * (ch_half / max_db_val));
ctx.lineTo ( x, y );
}
ctx.stroke ();
}
// ---
// draw the dots
var radius = 6;
for (var o = 0; o < q.ranges.length; ++o)
{
var curr = q.ranges[ o ];
var center_x = curr._coords.x;
var center_y = curr._coords.y;
ctx.beginPath ();
ctx.arc (center_x, center_y, radius, 0, 2 * Math.PI, false);
if (curr === q.act) {
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;
}
}
// ---
};
////////////////////////////////////////////
// helpers
var _dbncr = null;
var total_freq = 20000; // 22000
var total = 1000;
var jump = (total_freq / total) >> 0;
function _range_update ( q, range, new_range, compute_coords ) {
var modified = false;
var old_val = null;
for (var key in new_range)
{
if (range[key] !== new_range[key])
{
modified = true;
old_val = range[key];
range[key] = new_range[key];
if (key === '_on')
{
var el = document.getElementById ('pgon' + range.id);
el.checked = range[key];
}
else if (key === 'freq')
{
var el = range.el.getElementsByClassName('pk_freq')[0];
//requestAnimationFrame (function () {
el.value = range[key];
//});
}
else if (key === 'gain')
{
var el = range.el.getElementsByClassName('pk_gain')[0];
//requestAnimationFrame (function () {
el.value = range[key];
//});
}
else if (key === 'q')
{
var el = range.el.getElementsByClassName('pk_q')[0];
//requestAnimationFrame (function () {
el.value = range[key];
//});
}
else if (key === 'type')
{
// -----
var el = range.el.getElementsByTagName('select')[0];
if (range[key] === 'peaking') el.options[0].selected = true;
else if (range[key] === 'lowpass') el.options[1].selected = true;
else if (range[key] === 'highpass') el.options[2].selected = true;
_range_compute_arr (range);
q.ranges.sort (_compare);
}
// ---
}
}
if (modified)
{
if (compute_coords)
{
// compute coords of the canvas
var canvas = q.ui.canvas_eq;
var cw = canvas.width;
var ch = canvas.height;
var tmp_x = 0;
if (range.freq <= 5000) {
range._coords.x = ((range.freq / 5000) * (cw / 2) ).toFixed(1)/1;
} else {
range._coords.x = ((cw / 2) + (((range.freq - 5000) / 15000) * (cw / 2))).toFixed(1)/1;
}
// range._coords.x = ((range.freq / total_freq) * cw).toFixed(1)/1;
if (range.type === 'peaking')
range._coords.y = ((1.0 - ((range.gain + max_db_val) / (max_db_val * 2))) * ch).toFixed(1)/1;
else
range._coords.y = (ch / 2).toFixed(1)/1;
}
if (_dbncr) {
clearTimeout (_dbncr);
}
_dbncr = setTimeout (function () {
q.Callback ();
_dbncr = null;
}, 38);
q.Render ();
}
// ---
};
function _ease (t) { return t*t*t*t*t };
function _ease_out (t) { return t*t*t*t };
function _range_compute_arr ( range ) {
var arr = [];
for (var i = 0; i < total; ++i) {
arr[i] = 0;
}
range._arr = arr;
// -------------
var rounding = total_freq * (2 / range.q);
var half_rounding = (rounding / jump) >> 0;
if (range.type === 'peaking')
{
var edge_left = range.freq - (rounding / 2);
var edge_right = range.freq + (rounding / 2);
var start = (edge_left / jump) >> 0;
var end = (edge_right / jump) >> 0;
var j = 0;
for (var i = start; i < end; ++i)
{
var ii = (i * jump);
if (ii < range.freq)
{
++j;
arr[i] += _ease (j / (half_rounding / 2)) * range.gain;
}
else
{
--j;
arr[i] += _ease (j / (half_rounding / 2)) * range.gain;
}
}
return ;
}
if (range.type === 'highpass')
{
var edge_left = range.freq - rounding;
var start = (edge_left / jump) >> 0;
var end = (range.freq / jump) >> 0;
for (var i = 0; i < start; ++i)
{
arr[i] = -max_db_val;
}
// todo improve this!!!
var j = half_rounding;
for (var i = start; i < end; ++i)
{
--j;
arr[i] -= _ease_out (j / half_rounding) * max_db_val;
}
return ;
}
if (range.type === 'lowpass')
{
var edge_right = range.freq + rounding;
var start = (range.freq / jump) >> 0;
var end = (edge_right / jump) >> 0;
for (var i = end; i < total; ++i)
{
arr[i] = -max_db_val;
}
// todo improve this!!!
var j = 0;
for (var i = start; i < end; ++i)
{
++j;
arr[i] -= _ease_out (j / half_rounding) * max_db_val;
}
return ;
}
// -------------
}
function _make_ui ( q ) {
var el_drawer = d.createElement ('div');
el_drawer.className = 'pk_row';
var canvas_bars = d.createElement ('canvas');
var canvas_eq = d.createElement ('canvas');
canvas_bars.className = 'pk_peq2';
canvas_eq.className = 'pk_peq';
canvas_bars.width = 450 / 2;
canvas_bars.height = 224 / 2;
canvas_eq.width = 450;
canvas_eq.height = 225;
var ctx_bars = canvas_bars.getContext ('2d', {alpha:true, antialias:false});
var ctx_eq = canvas_eq.getContext ('2d', {alpha:true, antialias:false});
ctx_bars.fillStyle = '#365457'; // '#486a6e';
// ctx_eq.lineWidth = 2;
ctx_eq.strokeStyle = '#FF0000';
ctx_eq.shadowColor = '#FF2222';
ctx_eq.shadowBlur = 0;
// render the decibel and the frequencies
var marker_freqs = d.createElement ('div');
marker_freqs.className = 'pk_peq3 pk_noselect';
marker_freqs.innerHTML = '<span>32</span>' +
// '<span>32</span>' +
// '<span>64</span>' +
// '<span>128</span>' +
// '<span>250</span>' +
// '<span>500</span>' +
'<span style="position:absolute;left:3.5%">500<span></span></span>' +
'<span style="position:absolute;left:9%">1k<span></span></span>' +
'<span style="position:absolute;left:19%">2k<span></span></span>' +
'<span style="position:absolute;left:38%">4k<span></span></span>' +
'<span style="position:absolute;left:50%">5k<span></span></span>' +
'<span style="position:absolute;left:59%">8k<span></span></span>' +
'<span style="position:absolute;left:72%">12k<span></span></span>' +
'<span style="position:absolute;left:85%">16k<span></span></span>' +
'<span style="float:right">20k</span>';
var marker_dbs = d.createElement ('div');
marker_dbs.className = 'pk_peq4 pk_noselect';
marker_dbs.innerHTML = '<span style="top:0">35</span>' +
'<span style="top:10%">28<span></span></span>' +
'<span style="top:20%">21<span></span></span>' +
'<span style="top:30%">14<span></span></span>' +
'<span style="top:40%">7<span></span></span>' +
'<span>0<span></span></span>' +
'<span style="top:60%">-7<span></span></span>' +
'<span style="top:70%">-14<span></span></span>' +
'<span style="top:80%">-21<span></span></span>' +
'<span style="top:90%">-28<span></span></span>' +
'<span style="top:100%">35</span>';
el_drawer.appendChild ( canvas_bars );
el_drawer.appendChild ( canvas_eq );
el_drawer.appendChild ( marker_freqs );
el_drawer.appendChild ( marker_dbs );
q.el.appendChild ( el_drawer );
// element's area
var el_list = document.createElement ('div');
el_list.className = 'pk_row pk_noselect pk_pglst';
el_list.innerHTML = '<div class="pk_pgeq_els">' +
'<span class="pk_txlft"> #</span><span>type</span><span>gain</span><span>freq</span><span>Q</span>' +
'</div>';
q.el.appendChild ( el_list );
q.ui.ctx_bars = ctx_bars;
q.ui.ctx_eq = ctx_eq;
q.ui.canvas_bars = canvas_bars;
q.ui.canvas_eq = canvas_eq;
q.ui.el_list = el_list;
}
function _make_evs ( q ) {
var ctx = q.ui.ctx_eq;
var canvas = q.ui.canvas_eq;
var click_time = 0;
var is_dragging = false;
var _move = function ( e ) {
if (!is_dragging || !q.act) 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 = canvas.getBoundingClientRect ();
var cw = canvas.width;
var ch = canvas.height;
var posx = ex - bounds.left;
var posy = ey - bounds.top;
var rel_x = posx / cw;
var rel_y = posy / ch;
q.act._coords.x = posx;
q.act._coords.y = posy;
// up until half it's 0 - 5000, second half 5000 -> 2200
var freq = 0;
if (rel_x <= 0.5) {
freq = (5000 * (rel_x * 2)) >> 0
} else {
freq = 5000 + ((((rel_x - 0.5) * 2) * 15000) >> 0);
}
// var freq = (rel_x * (total_freq) + 0) >> 0; // + 16 (min freq)
var gain = (((rel_y - 0.5) * -2) * max_db_val).toFixed (2) / 1;
_range_update (q, q.act, {
'freq': freq,
'gain': gain
});
_range_compute_arr (q.act);
};
var _end = function ( e ) {
is_dragging = false;
canvas.removeEventListener ('mousemove', _move);
canvas.removeEventListener ('mouseup', _end);
canvas.removeEventListener ('touchmove', _move);
canvas.removeEventListener ('touchup', _end);
};
var mdown = function ( e ) {
var unchecked = !!q.act;
if (q.ranges.length === 0)
{
if (unchecked) q.Render ();
return ;
}
var bounds = canvas.getBoundingClientRect ();
var cw = canvas.width;
var ch = canvas.height;
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;
for (var o = 0; o < q.ranges.length; ++o)
{
var curr = q.ranges[ o ];
if ( Math.abs (curr._coords.x - posx) < dist_x && Math.abs (curr._coords.y - posy) < dist_y)
{
if (unchecked) {
q.act.el.classList.remove ('pk_act');
}
q.act = curr;
q.act.el.classList.add ('pk_act');
is_dragging = true;
q.Render ();
// check if we are targetting a circle
if (!e.is_touch)
{
canvas.addEventListener ('mousemove', _move, false);
canvas.addEventListener ('mouseup', _end, false);
}
else
{
e.ev.preventDefault ();
e.ev.stopPropagation ();
canvas.addEventListener ('touchmove', _move, false);
canvas.addEventListener ('touchup', _end, false);
}
return ;
}
// ---
}
if (unchecked) {
q.act.el.classList.remove ('pk_act');
// un-highlight
q.act = null;
q.Render ();
}
// ----
};
canvas.addEventListener ('mousedown', mdown, false);
canvas.addEventListener ('touchstart', function ( e ) {
if (e.touches.length > 1) {
e.preventDefault ();
e.stopPropagation ();
return ;
}
var ev = {
clientX : e.touches[0].clientX,
clientY : e.touches[0].clientY,
is_touch : true,
ev : e
};
mdown ( ev );
});
canvas.addEventListener ('click', function ( e ) {
if (e.timeStamp - click_time < 260)
{
var bounds = canvas.getBoundingClientRect ();
var cw = canvas.width;
var ch = canvas.height;
var posx = e.clientX - bounds.left;
var posy = e.clientY - bounds.top;
var rel_x = posx / cw;
var rel_y = posy / ch;
var freq = 0;
if (rel_x <= 0.5) {
freq = (5000 * (rel_x * 2)) >> 0
} else {
freq = 5000 + ((((rel_x - 0.5) * 2) * 15000) >> 0);
}
// var freq = (rel_x * (total_freq) + 0) >> 0; // + 16 (min freq)
var gain = (((rel_y - 0.5) * -2) * max_db_val).toFixed(2)/1;
var qval = 5;
var type = 'peaking';
q.Add (type, true, freq, gain, qval, posx, posy);
}
click_time = e.timeStamp;
}, false);
// ---
}
function _range_render_el ( q, range, clss ) {
var el_list = q.ui.el_list;
var el = d.createElement ('div');
el.className = 'pk_pgeq_els' + (clss ? clss : '');
el.setAttribute ('data-id', range.id);
el.addEventListener ('click', function ( e ) {
if (!range.el) return ;
if (range !== q.act)
{
if (q.act)
{
q.act.el.classList.remove ('pk_act');
}
q.act = range;
q.act.el.classList.add ('pk_act');
q.Render ();
}
}, false);
el.addEventListener ('mouseover', function ( e ) {
if (!range.el) return ;
if (!range._hov)
{
range._hov = true;
q.Render ();
}
}, false);
el.addEventListener ('mouseleave', function ( e ) {
if (!range.el) return ;
if (range._hov)
{
range._hov = false;
q.Render ();
}
}, false);
// # & on or off
var chckd = range._on ? 'checked' : '';
var num = '<i>' + range.id + '</i>';
var el_num = d.createElement ('div');
el_num.className = 'pk_txlft';
el_num.innerHTML = num +
'<input type="checkbox" id="pgon' + range.id + '" class="pk_check" name="onoff" ' + chckd +'>' +
'<label for="pgon' + range.id + '">ON</label>';
el_num.getElementsByTagName('input')[0].onchange = function ( e ) {
_range_update (q, range, {'_on': !!this.checked});
var lbl = this.parentNode.getElementsByTagName('label')[0];
lbl.innerHTML = this.checked ? 'ON' : 'OFF';
};
el.appendChild (el_num);
// type
var sel1 = range.type === 'lowpass' ? 'selected' : '';
var sel2 = range.type === 'highpass' ? 'selected' : '';
var el_type = d.createElement ('div');
el_type.innerHTML = '<select><option>peaking</option><option ' + sel1 + '>lowpass</option><option ' + sel2 + '>highpass</option></select>';
el_type.getElementsByTagName('select')[0].onchange = function ( e ) {
var val = this.options[this.selectedIndex].value;
if (val === 'peaking') {
el.classList.remove ('pk_dis');
} else {
el.classList.add ('pk_dis');
}
_range_update (q, range, {'type': val}, 1);
};
el.appendChild (el_type);
// gain
var el_gain = d.createElement ('div');
el_gain.innerHTML = '<input type="number" class="pk_val pk_gain" min="-35" max="35" value="' + range.gain + '">';
el_gain.getElementsByClassName('pk_gain')[0].onchange = function ( e ) {
if (!this.value) {
this.value = 0;
}
if (this.hasAttribute ('data-open')) {
this.parentNode.getElementsByClassName('pk_horiz')[0].value = this.value;
}
_range_update (q, range, {'gain': this.value / 1}, 1);
_range_compute_arr (range);
};
el_gain.getElementsByClassName('pk_gain')[0].onfocus = function ( e ) {
if (this.hasAttribute ('data-open')) return ;
var self = this;
var parent = this.parentNode;
var bar = document.createElement ('div');
bar.className = 'pk_pgeq_freq pk_gain';
bar.innerHTML = '<div class="pk_arr"></div><input type="range" min="-35" max="35" class="pk_horiz pk_gain" step="0.1" value="' + range.gain + '">';
bar.getElementsByClassName('pk_horiz')[0].oninput = function ( e ) {
if (self.value != this.value) {
self.value = this.value;
self.onchange ();
}
};
parent.appendChild (bar);
this.setAttribute('data-open', '1');
var down = function ( e ) {
if ( !e.target.classList.contains ('pk_gain') || (e.target.type === self.type && e.target !== self) )
{
self.removeAttribute ('data-open');
parent.removeChild (bar);
q.el.removeEventListener ('mousedown', down);
return ;
}
};
q.el.addEventListener ('mousedown', down, false);
};
el.appendChild (el_gain);
// freq
var el_freq = d.createElement ('div');
el_freq.innerHTML = '<input type="number" class="pk_val pk_freq" min="16" max="20000" value="' + range.freq + '">';
el_freq.getElementsByClassName('pk_freq')[0].onchange = function ( e ) {
if (!this.value) {
this.value = 500;
}
if (this.hasAttribute ('data-open')) {
this.parentNode.getElementsByClassName('pk_horiz')[0].value = this.value;
}
_range_update (q, range, {'freq': this.value / 1}, 1);
_range_compute_arr (range);
};
el_freq.getElementsByClassName('pk_freq')[0].onfocus = function ( e ) {
if (this.hasAttribute ('data-open')) return ;
var self = this;
var parent = this.parentNode;
var bar = document.createElement ('div');
bar.className = 'pk_pgeq_freq pk_freq';
bar.innerHTML = '<div class="pk_arr"></div><input type="range" min="16" max="20000" class="pk_horiz pk_freq" step="1" value="' + range.freq + '">';
bar.getElementsByClassName('pk_horiz')[0].oninput = function ( e ) {
if (self.value != this.value) {
self.value = this.value;
self.onchange ();
}
};
parent.appendChild (bar);
this.setAttribute('data-open', '1');
var down = function ( e ) {
if ( !e.target.classList.contains ('pk_freq') || (e.target.type === self.type && e.target !== self) )
{
self.removeAttribute ('data-open');
parent.removeChild (bar);
q.el.removeEventListener ('mousedown', down);
}
};
q.el.addEventListener ('mousedown', down, false);
};
el.appendChild (el_freq);
// q
var el_q = d.createElement ('div');
el_q.innerHTML = '<input type="number" class="pk_val pk_q" min="1" max="50" value="' + range.q + '">';
el_q.getElementsByClassName('pk_q')[0].onchange = function ( e ) {
if (!this.value) {
this.value = 1;
}
if (this.hasAttribute ('data-open')) {
this.parentNode.getElementsByClassName('pk_horiz')[0].value = this.value;
}
_range_update (q, range, {'q': this.value / 1}, 1);
_range_compute_arr (range);
};
el_q.getElementsByClassName('pk_q')[0].onfocus = function ( e ) {
if (this.hasAttribute ('data-open')) return ;
var self = this;
var parent = this.parentNode;
var bar = document.createElement ('div');
bar.className = 'pk_pgeq_freq pk_q';
bar.innerHTML = '<div class="pk_arr"></div><input type="range" min="1" max="50" class="pk_horiz pk_q" step="0.1" value="' + range.q + '">';
bar.getElementsByClassName('pk_horiz')[0].oninput = function ( e ) {
if (self.value != this.value) {
self.value = this.value;
self.onchange ();
}
};
parent.appendChild (bar);
this.setAttribute('data-open', '1');
var down = function ( e ) {
if ( !e.target.classList.contains ('pk_q') || (e.target.type === self.type && e.target !== self) )
{
self.removeAttribute ('data-open');
parent.removeChild (bar);
q.el.removeEventListener ('mousedown', down);
}
};
q.el.addEventListener ('mousedown', down, false);
};
el.appendChild (el_q);
// delete
var el_del = d.createElement ('div');
el_del.className = 'pk_del';
el_del.innerHTML = '<a style="cursor:pointer">DELETE</a>';
el_del.getElementsByTagName('a')[0].onclick = function ( e ) {
q.Remove (range);
};
el.appendChild (el_del);
// ----------------------
el_list.appendChild (el);
return (el);
}
function _compare ( a, b ) {
if (a.type === 'peaking' && b.type !== 'peaking') return -1;
if (b.type === 'peaking' && a.type !== 'peaking') return 1;
return 0;
}
// ---
};
var ParagraphicModal = function ( app, custom_presets ) {
app.fireEvent ('RequestSelect', 1);
var filter_id = 'paragraphic_eq';
// -------
var PGEQ = new PK_FX_PGEQ ();
var DrawBars = function (_, freq) {
PGEQ.RenderBars (_, freq);
};
var updateFilter = function () {
if (!PGEQ) return ;
var val = [];
var ranges = PGEQ.ranges;
for (var i = 0; i < ranges.length; ++i)
{
var range = ranges [ i ];
if (range._on)
{
val.push ({
'type' : range.type,
'freq' : range.freq,
'val' : range.gain,
'q' : range.q
});
}
}
return (val);
};
var x = new PKAudioFXModal ({
id: filter_id,
title: 'Paragraphic EQ',
ondestroy: function ( q ) {
app.stopListeningFor ('DidAudioProcess', DrawBars);
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback (modal_esc_key);
PGEQ = null;
},
preview: function ( q ) {
app.fireEvent ('RequestActionFX_PREVIEW_PARAMEQ', updateFilter ());
},
body: '',
presets:[
{name:'Old Telephone',val:'1,highpass,0,5800,5.8,1,lowpass,0,7060,5'}
],
custom_pres:custom_presets.Get (filter_id),
onpreset: function ( val ) {
var l = PGEQ.ranges.length;
while (l-- > 0) {
PGEQ.Remove (PGEQ.ranges[l]);
}
var canvas = PGEQ.ui.canvas_eq;
var cw = canvas.width;
var ch = canvas.height;
var list = val.split(',');
var len = list.length;
var els = (len / 5) >> 0;
for (var j = 0; j < els; ++j)
{
var curr = [];
var offset = j * 5;
curr[0] = !!(list[ offset + 0 ] / 1);
curr[1] = list[ offset + 1 ];
curr[2] = list[ offset + 2 ] / 1;
curr[3] = list[ offset + 3 ] / 1;
curr[4] = list[ offset + 4 ] / 1;
var x = 0;
var y = 0;
if (curr[3] < 5000) {
x = (curr[3] / 5000) * (cw / 2);
} else {
x = ((cw / 2) + (((curr[3] - 5000) / 15000) * (cw / 2))).toFixed(1)/1;
}
if (curr[1] === 'peaking')
y = ((1.0 - (((curr[2]/1) + max_db_val) / (max_db_val * 2))) * ch).toFixed(1)/1;
else
y = (ch / 2).toFixed(1)/1;
// (type, is_on, freq, gain, qval, coords_x, coords_y)
PGEQ.Add (curr[1], !!curr[0], curr[3]/1, curr[2]/1, curr[4]/1, x, y);
}
},
buttons: [{
title:'Apply EQ',
clss:'pk_modal_a_accpt',
callback: function( q ) {
app.fireEvent ('RequestActionFX_PARAMEQ', updateFilter ());
q.Destroy ();
}
}],
setup:function( q ) {
PGEQ.Init ( q.el_body );
PGEQ.Callback = function () {
app.fireEvent ('RequestActionFX_UPDATE_PREVIEW', updateFilter ());
};
app.listenFor ('DidAudioProcess', DrawBars);
app.fireEvent ('RequestPause');
app.ui.InteractionHandler.checkAndSet (modal_name);
app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) {
if (!app.ui.InteractionHandler.check (modal_name)) return ;
q.Destroy ();
}, [27]);
}
}, app);
x.Show ();
};
PKAudioEditor._deps.FxEQ = ParagraphicModal;
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
function getOfflineAudioContext (channels, sampleRate, duration) {
return new (window.OfflineAudioContext ||
window.webkitOfflineAudioContext)(channels, duration, sampleRate);
};
function _normalize_array (data) {
var new_array = [];
for (var i = 0; i < data.length; ++i) {
new_array.push ( Math.abs (Math.round ((data[i + 1] - data[i]) * 1000)) );
}
return (new_array);
};
function _normalize_array2 (data) {
var new_array = [];
for (var i = 0; i < data.length; ++i) {
new_array.push ( Math.round (Math.abs (data[i] * 1000)) );
}
return (new_array);
};
function _group_rhythm ( data, diff_arr ) {
if (diff_arr.length <= 1) return ;
var peak_median = 0;
for (var i = 0; i < data.length; ++i) {
peak_median += data[i];
}
peak_median /= diff_arr.length;
peak_median -= peak_median * 0.2;
var diff_median = 0;
for (var i = 0; i < diff_arr.length; ++i) {
diff_median += diff_arr[i];
}
diff_median /= diff_arr.length;
if (diff_median > 1) diff_median -= (diff_median * 0.2);
var existing = 0;
for (var i = 0; i < diff_arr.length; ++i) {
if (diff_arr[i] <= diff_median) continue;
++existing;
}
// console.log (" DIFF MEDIAN IS ", diff_median, " and total beats: ", existing, " out of: ", diff_arr.length);
// clean-up the drums array - based on the median.
// console.log ( JSON.stringify( data ) );
// console.log ("----------");
for (var i = 0, j = 0; i < data.length; ++i)
{
if (data[i] !== 0) {
if (diff_arr[j] && diff_arr[j] < diff_median) {
if (data[i] > peak_median && diff_arr[j] > (diff_median * 0.6)){
//console.log ( 'ZEROEDC NOOOOT ', i, ' ', data[i], ' with median ', peak_median , ' but diff was ', diff_arr[j], ' yet. ', diff_median );
}
else {
//console.log ( 'ZEROEDC ', i, ' ', data[i], ' with median ', peak_median , ' but diff was ', diff_arr[j], ' yet. ', diff_median );
data[i] = 0;
}
}
++j;
}
// ----
}
// console.log( data );
window.final_arr = data;
// console.log ( JSON.stringify( data ) );
// now count distance between peaks
var distances = {};
var unique_distances = [];
var first_found = 0;
var is_first = true;
for (var i = 0; i < data.length - 1; ++i) // #### do not litter the last data
{
if (data[i] === 0) {
++first_found;
continue;
}
//if (first_found < 1 && !is_first) {
// continue;
//}
if (is_first) {
is_first = false;
}
first_found = 0;
var own = [];
unique_distances.push (own);
// console.log ('----------------------------------');
// console.log ('COMPUTING DISTANCE OF ' + i + ' value ' + data[i] );
var interval = 0;
var total = 12;
var last_found = 0;
for (var j = i + 1; j < 1000; ++j) {
if (data[j] === 0) { ++interval; ++last_found; continue; }
else if (!data[j]) { break; }
if (last_found < 0) {
continue;
}
last_found = 0;
if (--total === 0) break;
own.push (interval);
// if it exists, immediately reach out for the next one.
if (!distances[interval]) distances[interval] = 0;
distances[interval] += 1;
// console.log ('distance with index ' + j + ' value ' + data[j] + ' is ' + interval );
}
// break;
}
console.log(unique_distances);
// grab only the big peaks.
function getmax (a) {
var m = -Infinity,
i = 0,
n = a.length;
for (; i != n; ++i) {
if (a[i] > m) {
m = a[i];
}
}
return m;
}
function getmin (a) {
var m = Infinity,
i = 0,
n = a.length;
for (; i != n; ++i) {
if (a[i] !== 0 && a[i] < m) {
m = a[i];
}
}
return m;
}
var max = getmax (data);
var min = getmin (data);
var count = 0;
var threshold = Math.round ((max - min) * 0.3);
var velocities = [];
for (var i = 0; i < data.length; ++i) {
if (data[i] === 0) continue;
if (data[i] >= (max - threshold)) {
velocities.push (3);
}
else if (data[i] >= (max - (threshold * 2))) {
velocities.push (2);
}
else if (data[i] >= (max - (threshold * 3))) {
velocities.push (1);
}
else {
velocities.push (0);
}
}
return ([distances, velocities]);
};
var TempoToolsModal = function ( app ) {
app.fireEvent ('RequestSelect', 1);
var filter_id = 'tempo_tools';
var act_index = 1;
var act_tool = null;
// ------
var TempoMetro = function ( app, modal ) {
var q = this;
q.app = app;
var bpm = 120;
var tick = null;
var count = 0;
var time = ((60.0 / bpm) * 1000) >> 0;
var audioContext = null; // new AudioContext();
var osc = null;
var amp = null;
var ready = false;
var volume = 0.5;
var accentuate = true;
var DidStopPlay = null;
var DidPlay = null;
var MetronomeAct = null;
var MetronomeInAct = null;
q.Init = function ( container ) {
var q = this;
q.el = container;
_make_ui ( q );
_make_evs ( q );
};
q.Destroy = function () {
q.app.stopListeningFor ('DidStopPlay', DidStopPlay);
q.app.stopListeningFor ('DidPlay', DidPlay);
q.app.stopListeningFor ('DidStartMetro', MetronomeAct);
q.app.stopListeningFor ('DidStopMetro', MetronomeInAct);
DidStopPlay = null;
DidPlay = null;
MetronomeAct = null;
MetronomeInAct = null;
if (ready) {
if (tick) {
clearTimeout (tick);
tick = null;
}
if (audioContext) {
var now = audioContext.currentTime;
osc.stop (now);
amp.disconnect ();
osc.disconnect ();
audioContext = null;
ready = false;
}
}
if (q.body) {
q.body.parentNode.removeChild ( q.body );
q.body = null;
}
q.app = null;
};
function _make_ui ( q ) {
var el_drawer = d.createElement ('div');
el_drawer.className = 'pk_row';
el_drawer.innerHTML = '<div class="pk_row">'+
'<label>BPM</label>'+
'<input type="range" min="20" max="300" class="pk_horiz" step="1" value="120" />'+
'<span class="pk_val">120</span>'+
'</div>'+
'<div class="pk_row">'+
'<label>Volume</label>'+
'<input type="range" min="0.0" max="1.0" class="pk_horiz" step="0.1" value="0.5" />'+
'<span class="pk_val">50%</span>'+
'</div>'+
'<div class="pk_row">'+
'<input type="checkbox" id="xxcjgs" class="pk_check" checked name="metroAccent">'+
'<label for="xxcjgs">Accentuate metronome click</label></div>' +
'<div class="pk_row">'+
'<a class="pk_modal_a_bottom" style="display:inline-block;float:none">Metronome</a>'+
'<a class="pk_modal_a_bottom" style="display:inline-block;float:none">Play Track</a>'+
'<a class="pk_modal_a_bottom" style="display:inline-block;float:none">Play Both</a>'+
'</div>';
q.body = el_drawer;
q.el.appendChild ( el_drawer );
};
function _make_evs ( q ) {
var range = q.body.getElementsByClassName('pk_horiz')[0];
var span = q.body.getElementsByClassName('pk_val')[0];
var range2 = q.body.getElementsByClassName('pk_horiz')[1];
var span2 = q.body.getElementsByClassName('pk_val')[1];
var checkbox = q.body.getElementsByClassName('pk_check')[0];
range.oninput = function() {
bpm = (range.value/1);
span.innerHTML = bpm;
time = ((60.0 / bpm) * 1000) >> 0;
};
range2.oninput = function() {
var val = (range2.value/1);
volume = val;
span2.innerHTML = ((val*100) >> 0) + '%';
};
checkbox.oninput = function() {
accentuate = checkbox.checked;
};
var metronome_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[0];
var play_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[1];
var both_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[2];
metronome_btn.onclick = function () {
if (tick) {
clearTimeout (tick);
tick = null;
count = 0;
q.app.fireEvent ('DidStopMetro');
return ;
}
var play = function () {
tick = setTimeout (function() {
if (!tick) return ;
if (++count % 4 === 0)
_metronome (1);
else
_metronome (0);
play ();
}, time);
};
count = 0;
if (!ready) _prepare ();
q.app.fireEvent ('DidStartMetro');
_metronome (1);
play ();
};
MetronomeInAct = function() {
metronome_btn.classList.remove ('pk_act');
};
MetronomeAct = function() {
metronome_btn.classList.add ('pk_act');
};
q.app.listenFor ('DidStartMetro', MetronomeAct);
q.app.listenFor ('DidStopMetro', MetronomeInAct);
play_btn.onclick = function () {
if (PKAudioEditor.engine.wavesurfer.isPlaying()) {
q.app.fireEvent ('RequestStop');
}
else {
q.app.fireEvent ('RequestPlay');
}
};
if (!PKAudioEditor.engine.wavesurfer.isReady)
{
play_btn.className += ' pk_inact';
both_btn.className += ' pk_inact';
}
if (PKAudioEditor.engine.wavesurfer.isPlaying()) {
play_btn.className += ' pk_act';
}
DidStopPlay = function() {
play_btn.classList.remove ('pk_act');
play_btn.innerText = 'Play Track';
};
DidPlay = function() {
play_btn.classList.add ('pk_act');
play_btn.innerText = 'Stop Track';
};
q.app.listenFor ('DidStopPlay', DidStopPlay);
q.app.listenFor ('DidPlay', DidPlay);
both_btn.onclick = function () {
if (tick) metronome_btn.onclick ();
if (PKAudioEditor.engine.wavesurfer.isPlaying()) play_btn.onclick ();
setTimeout(function() {
if (!tick && !PKAudioEditor.engine.wavesurfer.isPlaying())
{
play_btn.onclick ();
setTimeout(function(){
metronome_btn.onclick ();
},0);
}
},66);
};
};
function _metronome ( type ) {
if (type === 1 && accentuate) {
osc.frequency.value = 880.0;
} else {
osc.frequency.value = 440.0;
}
amp.gain.setValueAtTime (amp.gain.value, audioContext.currentTime);
amp.gain.linearRampToValueAtTime (volume, audioContext.currentTime + 0.01);
amp.gain.linearRampToValueAtTime (0.0, audioContext.currentTime + 0.12);
};
function _prepare () {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
osc = audioContext.createOscillator ();
amp = audioContext.createGain();
amp.gain.value = 0;
osc.connect (amp);
amp.connect (audioContext.destination);
osc.start (0);
ready = true;
// osc.stop( time + 0.05 );
};
};
var TempoTap = function ( app, modal ) {
var q = this;
q.app = app;
var DidStopPlay = null;
var DidPlay = null;
var DidSetLoop = null;
var DidAudioProcess = null;
q.Init = function ( container ) {
var q = this;
q.el = container;
_make_ui ( q );
_make_evs ( q );
};
q.Destroy = function () {
q.app.stopListeningFor ('DidStopPlay', DidStopPlay);
q.app.stopListeningFor ('DidPlay', DidPlay);
q.app.stopListeningFor ('DidSetLoop', DidSetLoop);
q.app.stopListeningFor ('DidAudioProcess', DidAudioProcess);
DidStopPlay = null;
DidPlay = null;
DidSetLoop = null;
DidAudioProcess = null;
q.app.ui.KeyHandler.removeCallback ('tmpTap');
if (q.body) {
q.body.parentNode.removeChild ( q.body );
q.body = null;
}
q.app = null;
};
function _make_ui ( q ) {
var el_drawer = d.createElement ('div');
el_drawer.className = 'pk_row';
// Estimate tempo for selected area button
el_drawer.innerHTML = '<div class="pk_row pk_pgeq_els">' +
'<span>Average BPM</span>'+
'<input style="margin-left:2px;min-width:64px;max-width:64px" '+
'type="text" class="pk_val pk_gain" value="-">'+
'</div>'+
'<div class="pk_row pk_pgeq_els">'+
'<span>Nearest BPM</span>'+
'<input style="margin-left:2px;min-width:64px;max-width:64px" '+
'type="text" class="pk_val pk_gain" value="-">'+
'</div>'+
'<div class="pk_row pk_pgeq_els">'+
'<span>Timing Taps</span>'+
'<input style="margin-left:2px;min-width:64px;max-width:64px" '+
'type="text" class="pk_val pk_gain" value="-">'+
'<a class="pk_modal_a_bottom" style="display:inline-block;float:none">Reset</a>'+
'<a class="pk_modal_a_bottom" style="display:inline-block;float:none">Play Track</a>'+
'<a class="pk_modal_a_bottom" style="display:inline-block;float:none">Loop</a>'+
'</div>'+
'<div><div id="pk_tmp_tap">'+
'<span style="opacity:0" class="pk_obj2">CLEARED...</span>'+
'<span class="pk_obj2">STAND BY...</span>'+
'</div>'+
'<div id="pk_tmp_tap2" style="position:relative">'+
'<canvas width="1000" height="200" style="image-rendering:pixelated;width:500px;height:100px;display:block;background:#000"></canvas>'+
'<span style="z-index:3;background:red;position:absolute;display:block;width:2px;height:100px;'+
'left:50%;margin-left:-1px;top:0"></span>'+
'</div></div>'+
'<div id="pk_tmp_tap3">'+
'<span style="position:absolute;top:50%;display:block;width:80%;left:10%;font-size:12px;'+
'margin-top:-20px;user-select:none;text-align:center;pointer-events:none;color:#ccc">'+
'Tap in this area, or hit [SPACE] rhythmically, to measure BPM.'+
'</span>'+
'</div>';
q.body = el_drawer;
q.el.appendChild ( el_drawer );
};
function _make_evs ( q ) {
var tap_graph = q.body.querySelectorAll('#pk_tmp_tap')[0];
var tap_area = q.body.querySelectorAll('#pk_tmp_tap3')[0];
var reset_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[0];
var play_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[1];
var loop_btn = q.body.getElementsByClassName ('pk_modal_a_bottom')[2];
var canvas = q.body.getElementsByTagName('canvas')[0];
var ctx = canvas.getContext('2d', {alpha:false,antialias:false});
var tempCanvas = document.createElement('canvas');
tempCanvas.width = 500 * 2;
tempCanvas.height = 100 * 2;
var tempCtx = tempCanvas.getContext ('2d', {alpha:false,antialias:false});
ctx.imageSmoothingEnabled = true;
tempCtx.imageSmoothingEnabled = true;
var value_els = q.body.getElementsByClassName ('pk_val');
var tap_msg = tap_graph.getElementsByClassName ('pk_obj2');
var tap_msg2 = tap_area.getElementsByTagName('span')[0];
var bpm_el = value_els[ 0 ];
var bpm_el_round = value_els[ 1 ];
var bpm_el_count = value_els[ 2 ];
var reset_wait = 3000;
var time_msec = 0;
var time_msec_prev = 0;
var time_msec_first = 0;
var count = 0;
var bpm = 0;
var steps_count = 0;
var first = true;
var is_playing = false;
var _reset_count = function ( force ) {
if (first) {
tap_msg[1].style.opacity = '0';
}
count = 0;
steps_count = 0;
first = true;
setTimeout(function() {
if (!first) return ;
tap_msg[0].style.opacity = '0.5';
if (!force) {
reset_btn.className += ' pk_act';
setTimeout(function() {
reset_btn.classList.remove ('pk_act');
},140);
}
setTimeout(function() {
if (first) {
tap_msg[0].style.opacity = '0';
tap_msg[1].style.opacity = '0.5';
} else {
tap_msg[0].style.opacity = '0';
tap_msg[1].style.opacity = '0';
}
}, force ? 490 : 874);
}, (force ? 0 : 150));
if (force)
{
bpm_el.value = '-';
bpm_el_round.value = '-';
bpm_el_count.value = '-';
var els = tap_graph.parentNode.getElementsByClassName('pk_obj');
var l = els.length;
while (l-- > 0) {
if (els[l]) {
els[l].parentNode.removeChild (els[l]);
}
}
}
};
reset_btn.onclick = function () {
_reset_count (true);
};
play_btn.onclick = function () {
if (PKAudioEditor.engine.wavesurfer.isPlaying()) {
q.app.fireEvent ('RequestStop');
}
else {
q.app.fireEvent ('RequestPlay');
}
};
if (!PKAudioEditor.engine.wavesurfer.isReady)
{
play_btn.className += ' pk_inact';
loop_btn.className += ' pk_inact';
}
if (PKAudioEditor.engine.wavesurfer.isPlaying()) {
play_btn.className += ' pk_act';
}
DidStopPlay = function() {
is_playing = false;
play_btn.classList.remove ('pk_act');
play_btn.innerText = 'Play Track';
};
DidPlay = function() {
is_playing = true;
play_btn.classList.add ('pk_act');
play_btn.innerText = 'Stop Track';
};
q.app.listenFor ('DidStopPlay', DidStopPlay);
q.app.listenFor ('DidPlay', DidPlay);
var old_left_time = -999999;
var old_right_time = -999999;
var peaks = [];
var skipp = false;
var remaining = 0;
DidAudioProcess = function() {
//if (skipp) {
// skipp = false;
// return ;
//}
//skipp = true;
var wv = PKAudioEditor.engine.wavesurfer;
var buffer = wv.backend.buffer;
var chan_data = buffer.getChannelData ( 0 );
var sample_rate = buffer.sampleRate;
var curr_time = wv.getCurrentTime ();
var width = 500;
var height = 100;
var half_height = (height / 2) * 2;
var new_width = width;
var cached_index = 0;
var pixels = 0;
var raw_pixels = 0;
var limit = 3;
var left_time = curr_time - (limit/2);
var right_time = curr_time + (limit/2);
var quick_render = false;
var start_offset = (left_time * sample_rate) >> 0;
var end_offset = ((left_time + limit) * sample_rate) >> 0;
var length = end_offset - start_offset;
var mod = (length / width) >> 0;
if (left_time < old_right_time)
{
// find pixels
var diff = right_time - old_right_time;
// pixels = Math.round ( (diff / limit) * width);
raw_pixels = ( (diff / limit) * width);
pixels = Math.round ( raw_pixels );
raw_pixels = ((raw_pixels*1000) >> 0)/1000;
if (pixels >= 0) {
if (pixels === 0) return ;
new_width = pixels;
start_offset = (old_right_time * sample_rate) >> 0;
end_offset = (right_time * sample_rate) >> 0;
length = end_offset - start_offset;
mod = (length / pixels) >> 0;
peaks = peaks.slice (pixels * 2);
cached_index = width - pixels;
quick_render = true;
}
}
old_right_time = right_time;
var max = 0;
var min = 0;
for (var i = 0; i < new_width; ++i) {
var new_offset = start_offset + (mod * i);
max = 0;
min = 0;
if (new_offset >= 0)
{
for (var j = 0; j < mod; j += 3) {
if ( chan_data[ new_offset + j] > max ) {
max = chan_data[ new_offset + j];
}
else if ( chan_data[ new_offset + j] < min ) {
min = chan_data[ new_offset + j];
}
}
}
peaks[2 * (i + cached_index)] = max;
peaks[2 * (i + cached_index) + 1 ] = min;
}
if (quick_render)
{
// var imgdata = ctx.getImageData(0, 0, width, height);
// tempCtx.putImageData (imgdata, 0, 0);
tempCtx.drawImage (canvas, 0, 0); //, width, height, 0, 0, width, height);
}
ctx.fillStyle = "#000";
// ctx.clearRect( 0, 0, width, height );
ctx.fillRect ( 0, 0, width * 2, height * 2 );
ctx.fillStyle = '#99c2c6';
if (quick_render)
{
var forward = Math.round (raw_pixels * 2);
remaining += forward - raw_pixels * 2;
if (remaining > 1) {
forward -= 1;
remaining = 0;
}
// ctx.translate(-1.5, 0);
ctx.translate (-forward, 0);
ctx.drawImage (tempCanvas, 0, 0); //, width, height, 0, 0, width, height);
ctx.setTransform (1, 0, 0, 1, 0, 0);
// ctx.drawImage (tempCanvas, 0, 0, width, 100, -(raw_pixels.toFixed(1)/1), 0, width, 100);
ctx.beginPath ();
var peak = peaks[ (width - pixels - 2) * 2];
var _h = Math.round (peak * half_height);
ctx.moveTo ( (width - pixels - 2) * 2, half_height - _h);
for (var i = (width - pixels - 1); i < width; ++i) {
peak = peaks[i * 2];
_h = Math.round (peak * half_height);
ctx.lineTo ( i* 2, half_height - _h);
}
for (var i = width - 1; i >= (width - pixels - 1); --i) {
var peak = peaks[ (i * 2) + 1];
var _h = Math.round (peak * half_height);
ctx.lineTo ( i* 2, half_height - _h);
}
ctx.closePath();
ctx.fill();
}
else
{
ctx.beginPath ();
ctx.moveTo ( 0, half_height );
for (var i = 0; i < width; ++i) {
var peak = peaks[i * 2];
var _h = Math.round (peak * half_height);
ctx.lineTo ( i * 2, half_height - _h);
}
for (var i = width - 1; i >= 0; --i) {
var peak = peaks[ (i * 2) + 1];
var _h = Math.round (peak * half_height);
ctx.lineTo ( i * 2, half_height - _h);
}
ctx.closePath();
ctx.fill();
}
//console.log( peaks );
};
q.app.listenFor ('DidAudioProcess', DidAudioProcess);
if (PKAudioEditor.engine.wavesurfer.regions.list[0])
{
if (PKAudioEditor.engine.wavesurfer.regions.list[0].loop)
loop_btn.className += ' pk_act';
}
loop_btn.onclick = function() {
q.app.fireEvent('RequestSetLoop');
};
DidSetLoop = function( val ) {
val ? loop_btn.classList.add('pk_act') :
loop_btn.classList.remove('pk_act');
};
q.app.listenFor('DidSetLoop', DidSetLoop);
tap_graph.parentNode.addEventListener ('transitionend', function ( e ) {
if (!tap_graph) return ;
var el = e.target;
if (el.tagName !== 'DIV') return ;
el.parentNode.removeChild ( el );
--steps_count;
if (steps_count === 0) {
if (is_playing)
setTimeout(function() {
if (steps_count === 0)
_reset_count ();
},1100);
else
_reset_count ();
}
});
tap_area.onclick = function ( ev ) {
if (ev) {
ev.preventDefault ();
ev.stopPropagation ();
}
if (first) {
first = false;
tap_msg[1].style.opacity = '0';
}
time_msec = Date.now ();
if ((time_msec - time_msec_prev) > reset_wait) {
count = 0;
}
if (count === 0)
{
time_msec_first = time_msec;
count = 1;
bpm_el.value = 'First Beat';
bpm_el_round.value = 'First Beat';
bpm_el_count.value = count;
}
else
{
bpm = 60000 * count / (time_msec - time_msec_first);
++count;
bpm_el.value = Math.round (bpm * 100) / 100;
bpm_el_round.value = Math.round (bpm);
bpm_el_count.value = count;
}
var step = document.createElement ('div');
step.className = 'pk_obj';
if (is_playing) {
canvas.parentNode.appendChild (step);
}
else {
tap_graph.appendChild (step);
}
++steps_count;
tap_area.classList.add ('pk_act');
requestAnimationFrame(function() {
step.style.transform = 'translate3d(-10%,0,0)';
setTimeout(function() {
tap_area.classList.remove ('pk_act');
},56);
});
time_msec_prev = time_msec;
};
app.ui.KeyHandler.addCallback ('tmpTap', function ( e, o, ev ) {
if (!app.ui.InteractionHandler.check (modal_name)) return ;
ev.preventDefault ();
ev.stopPropagation ();
tap_area.onclick (null);
}, [32]);
// ---
};
};
// events
var TempoEstimation = function ( app, modal ) {
var q = this;
q.app = app;
q.Init = function ( container ) {
var q = this;
q.el = container;
_make_ui ( q );
_make_evs ( q );
};
q.Destroy = function () {
if (q.body) {
q.body.parentNode.removeChild ( q.body );
q.body = null;
}
q.app = null;
};
q.Est = function ( selection ) {
var q = this;
var wavesurfer = q.app.engine.wavesurfer;
var buffer = wavesurfer.backend.buffer;
var starting_time = 20.375;
var ending_time = wavesurfer.getDuration ();
var sample_rate = buffer.sampleRate;
var look_ahead = 10 * sample_rate;
var offset_rate = starting_time * sample_rate;
var duration_rate = ending_time * sample_rate;
var dist_rhythm = {};
// now run offline
var audio_ctx = getOfflineAudioContext (
1,
buffer.sampleRate,
buffer.length
);
var source = audio_ctx.createBufferSource ();
source.buffer = buffer;
var filter = audio_ctx.createBiquadFilter ();
filter.type = 'highpass';
filter.frequency.value = 50;
filter.Q.value = 1.1;
source.connect (filter);
var filter2 = audio_ctx.createBiquadFilter ();
filter2.type = 'lowpass';
filter2.frequency.value = 140;
filter2.Q.value = 2.5;
filter.connect (filter2);
filter2.connect (audio_ctx.destination);
source.start (0);
var offline_callback = function( rendered_buffer ) {
_pass ( rendered_buffer, offset_rate, duration_rate );
};
var _pass = function ( rendered_buffer, offset, duration ) {
var chan_data = rendered_buffer.getChannelData ( 0 );
var new_arr = [];
var diff_arr = [];
var currval = 0;
var prev_val = 0;
var bottom = 100000;
var top = -100000;
var found_pick = false;
var going_up = false;
var peak_dist = 0;
var peak_prev = 0;
var next_offset = offset + look_ahead;
var trimmed_arr = [];
var modulus_coefficient = Math.round (look_ahead / 200);
var plus_one = look_ahead + modulus_coefficient;
for (var i = 0; i < plus_one; ++i) {
if (i % modulus_coefficient === 0) {
// look into 50 neighboring entries for higher values.
var val_clean = chan_data[ offset + i ];
var val = Math.abs (val_clean);
//console.log( "was ", val_clean );
var tmp_val = 0;
for (var uu = 1; uu < 50; ++uu) {
tmp_val = Math.abs (chan_data[ offset + i - uu ]);
if (tmp_val > val) {
val_clean = chan_data[ offset + i - uu ];
val = Math.abs (val_clean);
}
}
for (var uu = 1; uu < 50; ++uu) {
tmp_val = Math.abs (chan_data[ offset + i + uu ]);
if (tmp_val > val) {
val_clean = chan_data[ offset + i + uu ];
val = Math.abs (val_clean);
}
}
//console.log( "added ", val_clean );
//console.log("-----");
trimmed_arr.push ( val_clean );
}
}
trimmed_arr = _normalize_array2 (trimmed_arr);
trimmed_arr.pop ();
// ------------
prev_val = trimmed_arr[0];
for (var j = 1; j < trimmed_arr.length; ++j) {
currval = trimmed_arr[j];
if (currval > prev_val) {
if (!going_up) {
if (bottom > prev_val) {
bottom = prev_val;
top = -100000;
}
}
going_up = true;
}
else if (currval < prev_val ) {
if (going_up) {
// console.log (":: peak: ", prev_val.toFixed(2)/1, " bottom: ", bottom.toFixed(2)/1, " diff: ", Math.abs(prev_val-bottom).toFixed(2)/1 );
found_pick = true;
if (peak_dist < 3 && Math.abs (new_arr[peak_prev] - prev_val) < 150) {
// debugger;
if (prev_val > new_arr[peak_prev]) {
new_arr[peak_prev] = 0;
diff_arr.pop ();
}
else {
found_pick = false;
}
}
if (found_pick) {
diff_arr.push (Math.abs (prev_val - bottom));
peak_dist = 0;
new_arr.push ( prev_val );
peak_prev = new_arr.length - 1;
if (prev_val > top) {
top = prev_val;
bottom = 100000;
}
}
// -----
}
going_up = false;
}
prev_val = currval;
if (!found_pick) {
new_arr.push ( 0 );
//console.log( "ZEROED ", new_arr.length - 1 );
++peak_dist;
}
else {
found_pick = false;
}
}
// console.log( trimmed_arr );
// console.log( new_arr );
// window.trimmed_arr = trimmed_arr;
// window.new_arr = new_arr;
// window.chan = chan_data;
// ----
var ret = _group_rhythm ( new_arr, diff_arr );
if (!ret) {
console.log ("something weird happened, error 244");
return ;
}
var distances = ret[0];
// console.log( diff_arr );
// console.log( ret[1] );
for (var k in distances) {
if (!dist_rhythm[ k ]) dist_rhythm[ k ] = 0;
dist_rhythm[ k ] += distances[ k ];
}
console.log ( distances );
// console.log( ' ---------------- ' );
// console.log ('--------- END OF PASS ------- ', offset, ' / ', duration);
if (next_offset + look_ahead >= duration) {
// Done...
console.log ( dist_rhythm );
} else {
// _pass ( rendered_buffer, next_offset, duration );
}
// ----
};
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 );
};
};
function _make_ui ( q ) {
var el_drawer = d.createElement ('div');
el_drawer.className = 'pk_row';
// Estimate tempo for selected area button
el_drawer.innerHTML = '<div class="pk_row">' +
'<input type="radio" class="pk_check" id="tt4" name="xport" checked value="whole">'+
'<label for="tt4">Whole track</label>'+
'<input type="radio" class="pk_check" id="tt5" name="xport" value="sel">'+
'<label class="pk_lblmp3" for="tt5">Estimate for Selection Only</label></div>' +
'<div class="pk_row">' +
'<a class="pk_modal_a_bottom" style="margin:0;float:left">Estimate</a>'+
'</div>';
q.body = el_drawer;
q.el.appendChild ( el_drawer );
};
function _make_evs ( q ) {
var btn_est = q.body.getElementsByTagName ('a')[0];
if (!btn_est) return ;
btn_est.onclick = function () {
q.Est && q.Est (1);
// q.app && q.app.fireEvent ('ReqEst', 1);
};
};
};
var x = new PKAudioFXModal ({
id: filter_id,
title: 'Tempo & Rhythm Tools',
ondestroy: function ( q ) {
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback (modal_esc_key);
act_tool.Destroy ();
act_tool = null;
app.fireEvent ('RequestStop');
},
body: '<div class="pk_tbs">' +
'<a class="pk_tbsa pk_inact">Tempo Estimation</a>' +
'<a class="pk_tbsa">Tempo Tap</a>' +
'<a class="pk_tbsa">Metronome</a></div>',
// buttons: [{
// title:'Apply EQ',
// clss:'pk_modal_a_accpt',
// callback: function( q ) {
// q.Destroy ();
// }
// }],
setup:function( q ) {
var toplinks = q.el_body.getElementsByClassName('pk_tbsa');
var destroy = function () {
if (act_tool) {
act_tool.Destroy ();
act_tool = null;
toplinks[act_index].classList.remove('pk_act');
}
};
var activate = function () {
// get the active state
if (act_index === 0) {
// toplinks[0].className += ' pk_act';
// act_tool = new TempoEstimation ( app, q );
return ;
}
else if (act_index === 1) {
toplinks[1].className += ' pk_act';
act_tool = new TempoTap ( app, q );
}
else if (act_index === 2) {
toplinks[2].className += ' pk_act';
act_tool = new TempoMetro ( app, q );
}
act_tool && act_tool.Init ( q.el_body );
};
//toplinks[0].onclick = function() {
// destroy ();
// act_index = 0;
// activate ();
//};
toplinks[1].onclick = function() {
if (act_index === 1) return ;
destroy (); act_index = 1;
activate ();
};
toplinks[2].onclick = function() {
if (act_index === 2) return ;
destroy (); act_index = 2;
activate ();
};
activate ();
// ---
app.fireEvent ('RequestPause');
app.ui.InteractionHandler.checkAndSet (modal_name);
app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) {
if (!app.ui.InteractionHandler.check (modal_name)) return ;
q.Destroy ();
}, [27]);
}
}, app);
x.Show ();
// ------
};
PKAudioEditor._deps.FxTMP = TempoToolsModal;
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
var RecModal = function ( app ) {
var filter_id = 'rec_tools';
var audio_stream = null;
var audio_context = null;
var script_processor = null;
var media_stream_source = null;
var temp_buffers = []
var newbuff = null;
var sample_rate = 44100;
var buffer_size = 2048; // * 2 ?
var channel_num = 1;
var channel_num_out = 1;
var stop_audio = function () {
if (!audio_stream) return ;
audio_stream.getTracks().forEach(function (stream) {
stream.stop ();
});
if (script_processor) {
script_processor.onaudioprocess = null;
}
media_stream_source && media_stream_source.disconnect ();
script_processor && script_processor.disconnect ();
media_stream_source = null;
audio_stream = null; audio_context = null;
};
var x = new PKAudioFXModal ({
id: filter_id,
title: 'New Recording',
ondestroy: function ( q ) {
// destroy audio...
stop_audio ();
temp_buffers = [];
newbuff = null;
app.ui.InteractionHandler.on = false;
app.ui.KeyHandler.removeCallback (modal_esc_key);
app.fireEvent ('RequestStop');
},
body: '<div class="pk_rec" style="user-select:none">' +
'<div class="pk_row">' +
'<label>Devices:</label>' +
'<select style="max-width:220px"></select>' +
'</div>' +
'<div class="pk_row">' +
'<div style="float:left"><label>Volume</label>' +
'<canvas width="200" height="40"></canvas></div>' +
'<div style="float:left;margin-left:20px;"><label>Time</label>' +
'<span style="font-size: 24px;line-height: 50px;">0.0</span></div>' +
'<div style="clear:both;height:10px"></div>' +
'<div><label>Waveform</label><canvas width="1000" height="200" style="image-rendering:pixelated;width:500px;height:100px;display:block;background:#000"></canvas></div>'+
'</div>' +
'<div class="pk_row">' +
'<a class="pk_tbsa pk_inact" style="text-align: center;">START RECORDING</a>' +
'<a class="pk_tbsa pk_inact" style="margin-left: 24px; text-align: center;">PAUSE</a>' +
'</div>' +
'<div class="pk_row">' +
'<a class="pk_tbsa" style="float:left;display:none;text-align:center;box-shadow:0 0 7px #3a6b79 inset;">OPEN RECORDING</a>' +
'<a class="pk_tbsa" style="float:left;display:none;margin-left: 24px; text-align: center;">APPEND TO EXISTING</a>' +
'</div>' +
'</div>',
// buttons: [{
// title:'Apply EQ',
// clss:'pk_modal_a_accpt',
// callback: function( q ) {
// q.Destroy ();
// }
// }],
setup:function( q ) {
var is_ready = false;
var is_active = false;
var is_paused = false;
var has_recorded = false;
var mainbtns = q.el_body.getElementsByClassName('pk_tbsa');
var btn_start = mainbtns[0];
var btn_pause = mainbtns[1];
var btn_open = mainbtns[2];
var btn_add = mainbtns[3];
var time_span = q.el_body.getElementsByTagName('span')[0];
var devices_sel = q.el_body.getElementsByTagName('select')[0];
var devices = [];
var volcanvas = q.el_body.getElementsByTagName('canvas')[0];
var volctx = volcanvas.getContext('2d', {alpha:false,antialias:false});
var freqcanvas = q.el_body.getElementsByTagName('canvas')[1];
var freqctx = freqcanvas.getContext('2d', {alpha:false,antialias:false});
var tempCanvas = document.createElement('canvas');
tempCanvas.width = 500 * 2;
tempCanvas.height = 100 * 2;
var tempCtx = tempCanvas.getContext ('2d', {alpha:false,antialias:false});
var first_skip = 12;
var curr_offset = 0;
var temp_buffer_index = -1;
var volume = 0;
var currtime = 0;
var has_devices = false;
var old_left_time = -999999;
var old_right_time = -999999;
var peaks = [];
var skipp = false;
var remaining = 0;
var debounce = false;
temp_buffers = [];
newbuff = null;
var draw_volume = function () {
volctx.fillStyle = "#000";
volctx.fillRect(0,0,200,40);
if (!is_active) {
return ;
}
volctx.fillStyle = "green";
volctx.fillRect(0, 0, volume*200*1.67, 40);
time_span.innerText = ((currtime * 10) >> 0) / 10;
window.requestAnimationFrame( draw_volume );
};
var fetchBufferFunction = function (ev) {
if (first_skip > 0) {
--first_skip;
return ;
}
if (is_paused) {
return ;
}
curr_offset += ev.inputBuffer.duration * sample_rate;
var float_array = ev.inputBuffer.getChannelData (0).slice (0);
temp_buffers[ ++temp_buffer_index ] = float_array;
var sum = 0;
var x;
for (var i = 0; i < buffer_size; i += 2) {
x = float_array[i];
sum += x * x;
}
var rms = Math.sqrt(sum / (buffer_size / 2) );
volume = Math.max(rms, volume * 0.9);
var curr_time = (temp_buffer_index * buffer_size) / sample_rate;
currtime = curr_time;
var width = 500;
var height = 100;
var half_height = (height / 2) * 2;
var new_width = width;
var cached_index = 0;
var pixels = 0;
var raw_pixels = 0;
var limit = 3;
var left_time = curr_time - limit;
var right_time = curr_time; // + (limit/2);
var quick_render = false;
var start_offset = (left_time * sample_rate) >> 0;
var end_offset = ((left_time + limit) * sample_rate) >> 0;
var length = end_offset - start_offset;
var mod = (length / width) >> 0;
if (left_time < old_right_time)
{
// find pixels
var diff = right_time - old_right_time;
// pixels = Math.round ( (diff / limit) * width);
raw_pixels = ( (diff / limit) * width);
pixels = Math.round ( raw_pixels );
raw_pixels = ((raw_pixels*1000) >> 0)/1000;
if (pixels >= 0) {
if (pixels === 0) return ;
new_width = pixels;
start_offset = (old_right_time * sample_rate) >> 0;
end_offset = (right_time * sample_rate) >> 0;
length = end_offset - start_offset;
mod = (length / pixels) >> 0;
peaks = peaks.slice (pixels * 2);
cached_index = width - pixels;
quick_render = true;
}
}
old_right_time = right_time;
var max = 0;
var min = 0;
for (var i = 0; i < new_width; ++i)
{
var new_offset = start_offset + (mod * i);
max = 0;
min = 0;
if (new_offset >= 0)
{
for (var j = 0; j < mod; j += 3) {
var temp = new_offset + j;
var temp2 = (temp/2048) >> 0;
var temp3 = temp % 2048;
if (!temp_buffers[temp2]) continue;
if ( temp_buffers[temp2][ temp3 ] > max ) {
max = temp_buffers[temp2][ temp3 ];
}
else if ( temp_buffers[temp2][ temp3 ] < min ) {
min = temp_buffers[temp2][ temp3 ];
}
}
}
peaks[2 * (i + cached_index)] = max;
peaks[2 * (i + cached_index) + 1 ] = min;
}
if (quick_render)
{
// var imgdata = ctx.getImageData(0, 0, width, height);
// tempCtx.putImageData (imgdata, 0, 0);
tempCtx.drawImage (freqcanvas, 0, 0); //, width, height, 0, 0, width, height);
}
freqctx.fillStyle = "#000";
// freqctx.clearRect( 0, 0, width, height );
freqctx.fillRect ( 0, 0, width * 2, height * 2 );
freqctx.fillStyle = '#99c2c6';
if (quick_render)
{
var forward = Math.round (raw_pixels * 2);
remaining += forward - raw_pixels * 2;
if (remaining > 1) {
forward -= 1;
remaining = 0;
}
// freqctx.translate(-1.5, 0);
freqctx.translate (-forward, 0);
freqctx.drawImage (tempCanvas, 0, 0); //, width, height, 0, 0, width, height);
freqctx.setTransform (1, 0, 0, 1, 0, 0);
// freqctx.drawImage (tempCanvas, 0, 0, width, 100, -(raw_pixels.toFixed(1)/1), 0, width, 100);
freqctx.beginPath ();
var peak = peaks[ (width - pixels - 2) * 2];
var _h = Math.round (peak * half_height);
freqctx.moveTo ( (width - pixels - 2) * 2, half_height - _h);
for (var i = (width - pixels - 1); i < width; ++i) {
peak = peaks[i * 2];
_h = Math.round (peak * half_height);
freqctx.lineTo ( i* 2, half_height - _h);
}
for (var i = width - 1; i >= (width - pixels - 1); --i) {
var peak = peaks[ (i * 2) + 1];
var _h = Math.round (peak * half_height);
freqctx.lineTo ( i* 2, half_height - _h);
}
freqctx.closePath();
freqctx.fill();
}
else
{
freqctx.beginPath ();
freqctx.moveTo ( 0, half_height );
for (var i = 0; i < width; ++i) {
var peak = peaks[i * 2];
var _h = Math.round (peak * half_height);
freqctx.lineTo ( i * 2, half_height - _h);
}
for (var i = width - 1; i >= 0; --i) {
var peak = peaks[ (i * 2) + 1];
var _h = Math.round (peak * half_height);
freqctx.lineTo ( i * 2, half_height - _h);
}
freqctx.closePath();
freqctx.fill();
}
};
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function( _stream ) {
_stream.getTracks().forEach(function (stream) {
stream.stop ();
});
enumerate ();
}).catch(function(error) {
alert("no microphone permissions found!");
});
var enumerate = function () {
if (navigator.mediaDevices.enumerateDevices) {
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'audioinput');
has_devices = true;
var len = devices.length;
for (var i = 0; i < len; ++i) {
var el = document.createElement('option');
el.value = devices[i].deviceId;
el.innerText = devices[i].label;
devices_sel.appendChild (el);
}
is_ready = true;
btn_start.classList.remove ('pk_inact');
});
}
else {
devices_sel.parentNode.style.display = 'none';
has_devices = false;
is_ready = true;
btn_start.classList.remove ('pk_inact');
}
};
var stop = function () {
stop_audio ();
is_active = false;
is_paused = false;
first_skip = 10;
++temp_buffer_index;
var k = -1;
newbuff = new Float32Array (temp_buffer_index * buffer_size);
for (var i = 0; i < temp_buffer_index; ++i)
{
for (var j = 0; j < buffer_size; ++j)
{
newbuff[++k] = temp_buffers[i][j];
}
}
temp_buffer_index = -1;
temp_buffers = [];
// ------
btn_open.style.display = 'block';
// check to see if we are ready
if (app.engine.is_ready) {
btn_add.style.display = 'block';
}
has_recorded = true;
};
// ---
btn_start.onclick = function () {
if (!is_ready) return ;
if (debounce) {
return ;
}
debounce = true;
setTimeout(function() {
debounce = false;
}, 260);
// check if recording exists - ask for confirmation
if (has_recorded) {
if (!window.confirm("Are you sure? This will discard the current recording."))
{
return ;
}
}
if (is_active) {
stop ();
btn_pause.classList.add ('pk_inact');
btn_start.innerText = 'START RECORDING';
btn_start.style.boxShadow = 'none';
return ;
}
temp_buffer_index = -1;
temp_buffers = [];
newbuff = null;
volume = 0;
btn_open.style.display = 'none';
btn_add.style.display = 'none';
audio_context = new (window.AudioContext || window.webkitAudioContext)();
sample_rate = audio_context.sampleRate;
var audio_val = true;
if (has_devices) {
audio_val = {deviceId: devices_sel.value};
// devices_sel.options[devices_sel.selectedIndex].value;
}
navigator.mediaDevices.getUserMedia({ audio: audio_val }).then(function( stream ) {
audio_stream = stream;
media_stream_source = audio_context.createMediaStreamSource ( stream );
script_processor = audio_context.createScriptProcessor (
buffer_size, channel_num, channel_num_out
);
media_stream_source.connect ( script_processor );
script_processor.connect ( audio_context.destination );
is_active = true;
btn_pause.classList.remove ('pk_inact');
btn_start.innerText = 'FINISH RECORDING';
btn_start.style.boxShadow = '#992222 0px 0px 6px inset';
script_processor.onaudioprocess = fetchBufferFunction;
draw_volume ();
}).catch(function(error) {
});
};
btn_pause.onclick = function () {
if (!is_ready) return ;
if (!is_active) return ;
is_paused = !is_paused;
btn_pause.innerText = is_paused ? 'UN-PAUSE' : 'PAUSE';
};
btn_open.onclick = function () {
if (debounce) {
return ;
}
debounce = true;
setTimeout(function() {
debounce = false;
}, 150);
app.engine.wavesurfer.backend._add = 0;
app.engine.LoadDB ({
samplerate: sample_rate,
data: [
newbuff.buffer
]
});
// ----
q.Destroy ();
};
btn_add.onclick = function () {
if (debounce) {
return ;
}
debounce = true;
setTimeout(function() {
debounce = false;
}, 150);
app.engine.wavesurfer.backend._add = 1;
app.engine.LoadDB ({
samplerate: sample_rate,
data: [
newbuff.buffer
]
});
// ----
q.Destroy ();
};
// ---
app.fireEvent ('RequestPause');
app.ui.InteractionHandler.checkAndSet (modal_name);
app.ui.KeyHandler.addCallback (modal_esc_key, function ( e ) {
if (!app.ui.InteractionHandler.check (modal_name)) return ;
q.Destroy ();
}, [27]);
}
}, app);
x.Show ();
};
PKAudioEditor._deps.FxREC = RecModal;
})( window, document, PKAudioEditor );