Here is a mini early quick way to watch and process markers generated by fluid.buftransientslice~.
The used JSUI interface initially comes from groove~.maxhelp and was improved for the needs. You can stretch the waveform as with an Ableton Live clip. The stretched playback is done using groove~ and can easily be replaced by supervp.play~ in order to keep the transients found by fluid.buftransientslice~. Ask me if you need it.
This “didactic” (and yet buggy) patch could why not be part of the future fluid.buftransientslice~ help patch ?
The JS code, provided after the Max patch in this post, should be called “op_warpy.js”.
----------begin_max5_patcher----------
5113.3oc6cs0iiaaE94Y+UnZjGZSmcBuKoBz1zBjf1GJZQRA5CKBFHaK6Q6J
K4JIOWRQ2e6khjRVxVRlx5hYRyDjY8na9b934NE44+7t6VrL9U+zEV+NqOXc
2c+m2c2chCkef6T+8cK1485pPuTwksXU7tc9QYKtWdtL+WyDG2KLM1ZebZZv
xPeqrXqcwO6asyK4S9IoVKey5Iun0E20l3nrzfezO+Ng3G.pCml8Vn3XKJtv
f0h+Ld4GeOzs5cG4sSdk+oj.uvhyDcXWPTnelfTgpCt2Ka0SAQaeLweUljUY
N17uTKLk8fiM8dKDMmH3+yC.qePcaKOrbojZfGe5wGxJd7f7C9ee26x+08ZB
d67SS815eF3EDEThncCBvhCJojr216KYoEKJo7Zn.pCTvE+PN2igNBt28A9e
.cqfA04X3UvwsIt7O9tu46+dq+x27cei029W+tu+eNHIiKKXHGLSCVKNGtmh
KTHT.TLPNNAonYQXoMnKgqHEuiiQIZJxv5q5AFid.w4WpKKmSoheCsaUv3Z3
tH+W3T2YL2dqdydzVUIV5Ess+pEX.SNZij7MQnczkdQ0mEmrkLshq4RkAg9O
yMBFDGU4puag298UN7cUtkbn5iwhGj88kGJHRdHb4gR7eNn39okG0KgyQYb1
4PhD0dkQVb7wDu1OI5PPoBsXP6cEOvRQdWASCvxgdo4QL6HFvGe2FFu5S9hg
BPwAi26GEDsOwOkK55koHtxSu1ei2gvrGqpl69Pimdi2J+Vu2F0xuaw1jf0w
Q4zPMjN+vEeaefq+J0hqxKhqHxaeC2LWHiiJsbxTNOdHcoWR9.gxB.p3jYww
g0OUIuD5uISc58AQQm.hYw6a+jIAaepi6cYL+j655YKNS5iGhjm8QtJY1iod
OWmBy7BCU5n0e7u5EEryKyOKXW86vOxiylOktJINLrFJIOyyMbl0bI3U9uDr
N6Iwyppn.+xC1WHAsnbLdcvV+zr5GKyaaZ8iblMC9gNrTog9Xl+t8gbdn9ET
KVnppiUskU63cYSqtcss7usOW8LMqAzLoepIOf6oOol0GZznXZv1H9kTJ62l
owVcFJbBZCEdFHmZZrsvFtqvCgxfy3iv+ge+m4xOttiFH6byAYHf7.L2QLgY
N3r+5sinjr8..Yg686OwMeqA5bAnFKb3g0AnQiHPKHyE8ByfnNQk.dHisCF.
c.CYfOHbwu6RnqxYJBX8LhOZs+qisD50.b3goydArygNkX2XJzIogdBdjECS
Ay1QafALTgpiA1EFD0lOcAole9lQrz3CIqJjMJkerpS27nTxBhJiy8CUbPaA
s9AsFy5Ocf5Ec.lJ5n3oqAc3Lozgi1zg8jRG15RG4JSsPGpCVjS1h7.yW+nL
IjG8xxRBVdHSJRWMIydEtbKYewymaoWnJF4R+vcER8w3te2Q1nmEBHKd61vx
Rhs2Kg+EmwiQWlzPEyAWpN.sWZrptD0uHHpx.Pckk6gT76Yn5XpxlpUAPbo8
s7NtxpYQrYpnKwSP8cZi034c81RuUexJcuu+Z83PRe4PD2WrfEQNRVzdNYwz
LujLq3m0rBVt3dWeN9HmXfiVLB5Lir2is7idLKp2ikTY8ZbfhxSigyHq92+t
FqKMRu5R6vZuvzV+43v08FJf3bL.A.h+QFPEv7Gzc5sIJGoIpIcPm6GMi6sT
KFfbM0XtK9CPELFa1csjFFrxuQoZGMkpQirTcwzPIK4rTaGc6FpAi7PMiQqv
dH6yXukaWEGJKs+GxqfkCCQX2mWKTfMDAEeBYSvDt7xrHhvCWxOYebnHrUqW
Bxdxp5DTlGR7p3CxbxP5fo1N81CG.UwRGiLAxDyG2264eChclZtu0oeaSPX3
i8I9SaZemRZ1ECMEIKVfMFIcC7+Wy8FFIrARjEWGYKbR3X69KS91uL4a+xju
cESYQXr257W8FKPup4IsyxEe8y3.iJSeylHbxQsm4I2otmu5P06q7i0+5e9s
V+QqMwIVQwuX89Z+zKj7pqcr7EPgwcDJxyU8p2TMQf17GN8SDVlUn3+pDcfd
nQ2yeS9LZU7+hG8UKmgoBunDaQViN1zSe+tZ.6HyC1c3GCrn8BzXD8mKv6uz
rfo0ruRccUUWAznB50D0dCHN1TQbh87g3Hh8O+f7kVn9MGaDvrMe2THSjaAO
TSDcVmw6KHihf8CyvtymTZgiapDCaQH8lHq8igOjFmzy4zE6bYOQCFrXtNx2
05Y9MqnavZaR7g88yADdN.KlnfmpYjwH.quxBB3we0uHm6VvZCOf7QPMjgrk
dKvNlyqGk70WVfY8CxXC3s5QW6VNp2mLlA8d6kYszZSufJLRKS9WRJ6B9IgX
ZUi8pJSYF5jO6+59DquXC7K+hM3e6WrA8k+Z364e72X80oq7B8RxqzjU+7jh
YWa5tXsdgQ4xd43mss4H5w8Cj3useAEylPu.RjhgE4qgQ1liSf9qjZSmCkTB
QMC3lnV5usmZfL5z4Bf5JWwaP6lWpW2TkvqHXLzTpFxU.UuXL1lVzXeIO019
gTvoLTLJQHIgckYSxLGwpLqf7+qeXE3hJf2W6et9jvgxWtLji5ESRGERrwlE
NcFSBu.5TlxnZYwelfte0W0W0Sp8jpdpr5SMNq9SQDrD5DEAqp5jpPXQt.4p
F+mrAwhlxfXK.K4jagsIFUce5MTAmPnpXBZvRnxfByHHZS7msRyR74D8a8qp
hZXPiiZgAoYGS.PyOLX+t1HfHodDDUc8M2Ml6NhXd8c.h5f95DuWVdXyF+jR
j25KfizRsihFvJs65Ews4A3H.btUAV9GbcMp7+Cx3ncOcy3NglDbQtUldFsl
gg4tlSeE2a8P7R6LQhZJqopbQfn4tnvcoZGDk5mj82DuVcnSTpuLhglHDqPX
qnBclil46sv8Ch.SXoSJxUifLsnnkI4tre040oGI4NroZFCkF+gNx4KEwLoI
L0R7pv2y4nGaO8wCpRWSOKXl7TlhlROk4aRQfxJnXR0n6JEsPNSOZoJZBwfl
LdY4l54qlIDvluJNUXFSkz.kYN0pauu+m9rTZaeLmIS64h5ePEeBeIqYfp9M
c.lS3Ea8yxWJ0Vod612SHCXq2au4vcZJ196rXTywmoL4zAHuAb0q3.CLrCr7
0c.JMy4XPtF1DdHX8CbbLKwKJMvmif4X4m6oZqFumfCV9SouBla019uwtvbF
Bbn2Nhi72nhe+yicDGl60lXIPu2cloB1ts6.S1fITdSU97oB4v2VjCNQBbTj
8jJvwtsvFZhfsxWeloB2H2VbCOgJpDGmIUjida2vuru50rUQI+cvhEbjVHiY
tiek+Nro0F5D47c9oZKUEv8U9kXsoLI6.UB5EpC8legnaO8p6FpV9rv1I9B.
PnbA.Af1h0DjqqCB5LoTutaCaMHFcSPan1aOYftIXWW.AJPYJ.fXtBRGibXr
Ik9A+zRajo61iGFYFzq1aidDfYPv5ZdlZHBDDcEfYlA8p89cI1wLHXcsHSN2
Q4Mgd00hLyPrP.zL9BF0bnWsLP3ZNzKRKENWiP.l5pq.gYH.KnWc.XFzLnWc
cI2fo5aB8p6Nfq.eM.4WltFHLCGbTsS4fLvH3qbi6BVqlqGY58txMkKZ9l3s
3U56ziLULeebt2qjaqVjnj0xcQLvMkGxWLlCmGfSBOPzMuFhYXzm37S4pLPz
0jJxLRZfv5iHtAPuzauIUj7UJwAJdcLKLm5Hmz0ogqM.GItxc4xb1rpWD4eO
U7stYDv5cINlOmHZyD4urh8KJq4yKhnjAZUqZynXSX8axDLygf0JYRyfb00O
GwwbnWntz6sOUGL61awm5Nyt4v55liQLCgJjlBU8O+fIgdQ5lJ.xLTZQ55zA
aFyX.h0mbdM.5U2BZaFYFlSE3aqIQHR18GlQihHMiKf3ZLCRZOoYPifbg5lt
9smbg5mQjY3hTRvPsmjDCfhwZOKIXChf0pr3LCgfc5SQmfWeI9Z2PdQadwFK
2gAT8vC4eNYcBRPe67g25QJsCPvPzc0tmNZHuBDRBF1mlC5MmhY55xzjHXsp
rhYTZkbpfoi07wHp7+uq+k1VejRtQ.yoRq0AxVET502ConWaGzS0Con3YrCZ
4+uO3ENJbM4JaVjJtlLE8RtMgw7Gxf6Ws316ybmsBH6ciCStURQOao6sfy7o
9aBByTk1urS9kryKqZu4pgUG4z0y8H3Qtm6UzFwj3vjzeEquauTYEYmDuJuU
CUtCNc9hksav.Q5a+TCc4lOnqbUDifmIQLbjXjTHrsm.Ehh9HnInPzlDCnot
woqdMiSBo8lw4HJFgIDY+TladUtdwNaSvYDDj5gECLbjsXfnpEP3DZxn8NNY
P1X3tD06fDXTT0nDHjaauWEgG8duJZxcDLV8udmws80Cks6qor60y8rs9XON
uKNWrwNv+11eHqJY2sJdoosOEEuL8IOIdPKtxsQwbtk6b8SUej5Zr6xAOP.D
417J0UtARTsQamSRUxMB15qRwhx1qboA8S52usdmCe.pkl7Z413QQHJeLNZa
3aO3ErY.thf1Wgqnl2wOzW+Vs2dfDd4gPvEBu4ZbaGF7r+Ca8BhJ1jNV7r2w
rKOd1Of9gtTEfchrU6YqUUhgDvCDhKl.y6xMficPZZUowpoL0dZEobUl7gBY
7T02HVOJt9T7KbLao58WpudQ44eHeSfKVW4pcxLVEpc0SdQQ9g0dVmzDBqRL
d6paDUTOgxBIzQIEd1K7fe7lyavuGGd3QttsogR7Obro8d7p4jSRVCWdSWaA
tCZ3b63fY94du8wVtZ8y6I2zAZ7r4QKvUoNWzpoqRNrv+hNVUmJWzA9EUpSS
dW0R4bUkBoE6Mq8V8YKnEZ.FWn3KabQ2fYQX494HytnMOPufYigWlfplL1G5
81RuUe5wz899qudaFc2F6uFqwWug3BEeRQK4pAL8h4TM4Z3Mh7cnhe4qu.7v
iihJrQ0zfnJcwZ3joll2ks47e1my2zmFftJld0ABz+DScY0c3XClfJbzlcsf
UYC.mbbtBbJ+6jGifWxaU6Sv8G3JBxsHgdJ3BIzS5W8784gPTu2m2X9AiuPb
v1OWtgTeUiJtWwnhJzpq2rYwv.lNehuaShie1uRZ.ecdWkW8WbSQecXb79Ag
k3Afk2eATEqApxy8U11vOuoy0oumKJcuzKkqGxCeJ2WIW2f.NN0TggwuHmIp
7FcebMc.gKvnrUwI4TqZttJOaNd6GstRhgK1ktnxNaC+7oYdIYsdE4aG6xT7
xIvxo4JNIXa.GJC8i1l8jBjrAN77aYv7TKVjwSit5Cp3NJYAH5XrpK1+jWpe
Uh3zaee.ePoEtLexgBxdqAxrh3Wo6vq2.wGSODnSsIpHu5dTXOfiUExqw6e7
Euj8u8vGSWL5kY.Ccjc9ZQlrN1iqluLStFBBUt5NzH1ytKXGZBhkzAnpbUKk
retiZrJT0QvhsdYibLhH.XVhRrsoqPvmGagAWP.ALhyBgRvPNWVDxjOUVU0W
dIHZc7KB+eCUoARljY9kh5Tq41m80YPXGJScesirFEA7vsUk5H2pqdEjNh5U
ExNREKl6rpXk8The5SadY8v0qlBmQPDgZ35UmhfcnV04kN10x3FqTUxqZqSg
GScJkbiRmBcCzoxqb0fUpbmBcJHw4mD5TUPvKpT0109yRspblUa0pwLDvBQG
kZk8rpVk9I+WFrB0T7VNAALWCWgpB10gpTaW0HqDcqi2KmM0U8wYL0dTxI2j
Ln16sdcd8xFpBDcBTfbswFt9Sczqq4rp8Kbj0hnPzMVORwq5pJwFQUIkDiTS
hRmUMo09KiODsZ3UhXJJDgiiomuzIvWG5RcckirxDFbqcJUvrZWZuwrxdNUS
VBOAZSsw0qh2sO33quY0I4RTXdcBvcLsqXSD8Xd0rBXSUcbTcfBwkTu8GHQl
SWuXJ74r0IlaskqVKKRLmZqyQ81OoNYuj5rgtQk.qu3k6KABFFApA8UeM6py
Jr6pIGG2QGuFF8Xqi.1LRODMnmqQb5j0FtCTFvsrxpPYWdk31j7GZ5YH6wlg
.1tsyP3omgniLC4pZorMxOjomeHiL+33RamenSO+fPiMCA6fgXSOCAG6QHHV
Vg3l4HvLvQi8PDTsRbaliFVX.N.cD5HymaDcL5lajhNKjisstzCddnGpNdYg
y1vkVAgLaTCyrDdn5naQqsOEMVp05+UCGaaj5HgxlMQBBwrBamf0UFclnGcL
+OaTCVmjrJjsG92D7RxEzaW94ZQfPHcJTgw5nCiGg.2H.Y2EmRIx2tXlpQfd
1AJWAoP.r5AFpX.TW0Qz7n..zkdfyB8fHlkKUj1lOIyC8fzw947UkJDvvFuL
KxA5z+HxlT5g0iv4G12D0vFIzJS54KNHH1vvGczbfynjpVBPD7viI.CkwDXC
ApP.HM92H05gWEO.RtUqLPlTmvAfyoXIzrx2GNo9Wjy5l298O6mjpdlBRYwN
uOJeF12K9yfH4eJlw3EI9x86mx8zjEdIqdJHyeU1gD4bM9JSNA8hk0URzg.U
D5h8VQ4bRdxL8UNy067dkkOgnB1gyxa7NDlUGmxmBTAalOCybZ2+hB8dqV4G
kUCZbxuLGrKRt8maCbc.j52Uss6Dn5YdewVlRYvv2qFSS3eEmNcqK1wo9fhb
DpJCTigESvZWrbMRmfvTjXqZGainDwmP1DJr1X7HPV0l54wZrX41MAggkLT0
2Ghh4edw1Du0AG2voT7Orbriw+w99F+T0WyT4sgJtMaGGNxceie57aq3tPt.
nqPFAqjQx+D+PvStKunsRPFYWcEGlDuONobsD9.1s75OjEWxnmsjhad3qt1g
dihxIcWaoKwXFgKVAPhOw4YNMesRV764+9t+GLU6uzC
-----------end_max5_patcher-----------
and the JSUI called “op_warpy.js”:
mgraphics.init();
mgraphics.relative_coords = 0;
mgraphics.autofill = 0;
var w = box.rect[2] - box.rect[0];
var h = box.rect[3] - box.rect[1];
var active = 0;
var warps = [];
var ow = 2000;
var oh = 200;
var ocan = new MGraphics(ow,oh);
var wave = new Image(ocan);
var bufsize = 1000.
var ddt = new Dict("warps");
function loadbang(){
init();
}
function paint(){
mgraphics.identity_matrix();
mgraphics.set_source_rgb(0.1,0.1,0.1);
mgraphics.rectangle(0,0,w,h);
mgraphics.fill();
mgraphics.set_source_rgb(1.,1.,1.);
var start,sw,sx,dw;
for(var i=0;i<warps.length;i++){
warps[i].draw();
//start = push();
if(i0 && active<(warps.length-1) && shift){
//warps[active+1].position += warps[active].position;
warps[active-1].sw += warps[active].sw;
warps.splice(active,1);
active = -1;
}
bang();
}
function ondrag(x,y,button){
if(button==1){
if(active>0 && activewarps[active+1].position) newpos = warps[active+1].position-0.00001;
}
warps[active].position = newpos;
}
lastX = x;
lastY = y;
}
else{
active = -1;
}
bang();
}
function anything()
{
var li = arrayfromargs(messagename, arguments);
for (i=1;i<=li.length;i++){
index = i;
repos = li[i];
if(repos<=0) newpos= 0.00001;
if(index<(warps.length)){
if(repos>warps[index+1].position) repos = warps[index+1].position-0.00001;
}
warps[index].position = repos;
}
bang();
}
function bang()
{
mgraphics.redraw();
todict();
outlet(0,"dictionary", ddt.name);
}
function init(){
warps = new Array();
warps[0] = new warpMarker(0);
warps[0].sw = 1;
warps[1] = new warpMarker(1);
bang();
}
function getID(x,y){
var found = -1;
var nx = x/w;
var apos = 0;
for (i=0;i<warps.length;i++){
if(warps[i].getPos(nx,y)) found = i;
}
return found;
}
function insertMarker(t){
var after = -1;
var apos = 0;
var aposx = 0;
for (i=0;i<warps.length;i++){
aposx = warps[i].position;
if (aposx<t){
apos = aposx;
after = i;
}
}
var npos = t;
var nslot = new warpMarker(npos);
var afterpos = warps[after].position;
//get the fraction of the original marker that we're splitting
var nposlerp = (npos-afterpos)/(warps[after+1].position-afterpos);
//multiply it by the source length to get source (waveform) position
nposlerp *= warps[after+1].origin-warps[after].origin;
nslot.origin = warps[after].origin+nposlerp;
nslot.sw = warps[after].sw-nposlerp;
//adjust the original marker values
warps[after].sw = nposlerp;
warps.splice(after+1,0,nslot);
return after+1;
}
function insertMarker2(t){
active = insertMarker(t);
bang();
}
function warpMarker(t){
this.origin = t;
this.sw = t;
this.position =t;
this.speed = 1;
this.draw = function(){
mgraphics.translate(this.position*w,10);
mgraphics.move_to(0,0);
mgraphics.line_to(-5,-8);
mgraphics.line_to(5,-8);
mgraphics.line_to(0,0);
mgraphics.line_to(0,h-10);
mgraphics.close_path();
mgraphics.stroke_preserve();
mgraphics.fill();
mgraphics.translate(0,-10);
}
this.getPos=function(x,y){
var negpos = this.position-5/w;
var pospos = this.position+5/w;
if ((xnegpos)) return true;
else return false;
}
}
function drawbuffer(buffer,x){
ocan = new MGraphics(ow,oh);
var xw = ow/x;
//var yh = oh/y;
var u,v;
var buf = new Buffer(buffer);
bufsize = buf.length();
var samps = Math.floor(buf.framecount()/x);
var bank;
with(ocan){
set_source_rgb(.75,.75,.75);
move_to(0,200);
for(u = 0;u<x;u++){
var accum = 0;
bank = buf.peek(1,u*Math.floor(samps),Math.floor(samps));
for(v=0;v<samps;v++){
accum = Math.max(accum,Math.abs(bank[v]));
}
line_to(u*xw,(1-accum)*oh);
}
line_to(ow,oh);
line_to(0,oh);
fill();
}
wave = new Image(ocan);
//oc.fillRect(0,0,500,200);
bang();
}
function push (){
var b = mgraphics.get_matrix();
return b;
}
function pop (mat) {
mgraphics.set_matrix(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5]);
}
function todict(){
ddt.clear();
for (i=0;i<warps.length;i++){
var b = new Dict();
b.set("sourcetime",warps[i].origin*bufsize);
b.set("desttime",warps[i].position*bufsize);
ddt.set("marker"+i,b);
}
}
function onresize(){
w = box.rect[2] - box.rect[0];
h = box.rect[3] - box.rect[1];
}