Files
homeclaw/web-ui/audiomass/fx-auto.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

501 lines
11 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;
var mt = app.multitrack;
var mt_buffer = mt && mt.IsOn && mt.IsOn () && mt.GetFxBuffer ?
mt.GetFxBuffer () :
null;
if (mt_buffer) q.wv = {
backend:{buffer:mt_buffer},
regions:{list:[]},
getDuration:function () { return mt_buffer.duration; }
};
q.points = {};
q.act = null;
q.act_point = null;
q.in_auto = false;
q.rbuff = null;
q.waveDarken = filter_modal.waveDarken || 0;
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.DelAct = function ( min ) {
var p = q.act && q.points[q.act.id], i = p && p.indexOf (q.act_point);
if (!p || i < 0 || p.length <= min) return ;
p.splice (i, 1);
q.act_point = p[Math.min (i, p.length - 1)];
q.Render ();
return 1;
};
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);
if (q.waveDarken) {
ctx.fillStyle = 'rgba(0,0,0,' + q.waveDarken + ')';
ctx.fillRect (0, 0, cw, ch);
}
}
// 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, seek_t = 0, no_seek = 0;
q.canvas.addEventListener ('click', function ( e ) {
if (!q.act) return;
var h = q.app.engine.FXPreviewHost;
if (seek_t) { clearTimeout (seek_t); seek_t = 0; }
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 ();
// ----
}
else if (!no_seek && preview_cb && h && (h.previewing || h.MTPreviewing))
{
var bounds = q.canvas.getBoundingClientRect ();
var sx = Math.max (0, Math.min (1, (e.clientX - bounds.left) / bounds.width));
seek_t = setTimeout (function () { seek_t = 0; preview_cb (sx); }, 260);
}
no_seek = 0;
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;
no_seek = 1;
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;
no_seek = 1;
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;
if (!buff) return ([cc, ctx]);
var img = new Image();
img.onload = function () {
ctx.drawImage (img, 0, 0);
if (q.waveDarken) {
ctx.fillStyle = 'rgba(0,0,0,' + q.waveDarken + ')';
ctx.fillRect (0, 0, q.cw, q.ch);
}
if (q.act) q.Render ();
};
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 ) {
if (!buffer) return ;
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 rate = buffer.sampleRate;
var from = Math.min (buffer.length, Math.max (0, (offs * rate) >> 0));
var to = Math.min (buffer.length, ((offs + durr) * rate) >> 0);
var len = Math.max (1, to - from);
durr = len / rate;
var audio_ctx = getOfflineAudioContext (
1, // orig_buffer.numberOfChannels,
8000,
Math.max (1, (durr * 8000) >> 0)
);
var newbuffer = audio_ctx.createBuffer (1, len, rate);
newbuffer.getChannelData ( 0 ).set (
buffer.getChannelData ( 0 ).subarray ( from, to )
);
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;
// 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() {});
else
audio_ctx.oncomplete = function ( e ) {
offline_callback ( e.renderedBuffer );
};
// ---------
};
};
PKAudioEditor._deps.FxAUT = FXAutomation;
})( window, document, PKAudioEditor );