Groove machine using fluid.buftransientslice~

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];
}

Hi Olivier,

Thanks for sharing this. There seems to be an error in line 48 of the javascript code. I’m not familiar with the language, but there seems to be additional curly brackets.
Max also complains about
jsui: js: no function drawbuffer [op_warpy.js]
Hans

Hello Hans !
Oops, sorry.
That may sound stupid but I wonder if you use the right code. The JS script should be in the same folder and called “op_warpy.js”.
Also, try to send the message “compile” to the JSUI.
Finally, I am re-uploading my code in the same previous post in case I made a mistake and sent you an intermediate version. ===> done.
I am not a pro with JS neither :slight_smile:

Hi Olivier,

this is exactly what I did. I’m still receiving the same error messages in Max 7.3.5

xebra_global: XEBListeningConnection_ListenProc: Error accepting connection: 670008 nodename nor servname provided, or not known
jsui: op_warpy.js: Javascript SyntaxError: syntax error, line 48
jsui: source line: else{
jsui: js: no function drawbuffer [op_warpy.js]

sending comile gives me again the same error.

jsui: op_warpy.js: Javascript SyntaxError: syntax error, line 48
jsui: source line: else{

If I look at the js code from your post, the error seems to be in the function on drag

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

the opening curly bracket of the function matches the one before
lastX, the rest of the code is not part of the function declaration anymore.

I hope I’m not making a stupid mistake here. Just let me know what to do to try it out
Best, Hans

Hello Hans !!

Thank you for your time !!
I now see that every time I copy/paste the JS code, it removes some parts !!!
Probably a character discourse does not like. I do not know and will save us time by adding it here:
https://www.dropbox.com/sh/2s1z8d13w6them6/AAAZl91QQc-PEqbomzflR-Nja?dl=0
I hope it will work…

The code is nevertheless far from perfect but it works ok here. I wanted to share this first step for the ones who may need it as a quick start. Although I personally plan to do something very different I feel I need to go thru this process that could be a start for help or demo files.

woaaaaaa this is amazing! Indeed this would be great to add in the helpfile, I’ll speak with @weefuzzy to see what he thinks.

For the sake of clarity, I’ve compressed the code and join it here: groove_machine_op.zip (8.3 KB)

I can imagine @rodrigo.constanzo making serious use of this, especially with my other post

(unrelated to this thread, but got a crash when playing with the buffalo patch)

buffalo crash.txt.zip (31.4 KB)