HISE Logo Forum
    • Categories
    • Register
    • Login
    1. HISE
    2. hujackus
    • Profile
    • Following 0
    • Followers 1
    • Topics 3
    • Posts 36
    • Groups 0

    hujackus

    @hujackus

    24
    Reputation
    13
    Profile views
    36
    Posts
    1
    Followers
    0
    Following
    Joined
    Last Online
    Website hujackus.altervista.org/conwaymatrix
    Location Minnesota

    hujackus Unfollow Follow

    Best posts made by hujackus

    • RE: Circular XY pad

      @hujackus

      An Assortment of Square and Circular XY Pads!

      Ok here it is. I put five XY pads and some fun knobs into one snippet for you all to enjoy. I hope you find the code interesting. It should be possible to cut out the parts you need and put them in your projects. I decided not to use broadcasters to keep things simple, but I did have some difficulty linking the X and Y knobs to processors in the module tree because of this. Let me know what you all think.
      Fun with Circular XY Pads2.png

      // An Assortment of Square and Circular XY Pads
      // By Jack Huppert
      //
      // Helpfull Reading
      // Analytical Methods for Squaring the Disc by Chamberlain Fong
      // 	https://arxiv.org/pdf/1509.06344
      // Elliptification of Rectangular Imagery By Chamberlain Fong
      // 	https://arxiv.org/pdf/1709.07875
      // Square/Disc mappings by Marc B. Reynolds
      // 	https://marc-b-reynolds.github.io/math/2017/01/08/SquareDisc.html 
      
      Content.makeFrontInterface(810, 250);
      
      // init X and Y knobs
      const knbX = Content.getComponent("knbX");
      const knbY = Content.getComponent("knbY");
      knbX.setControlCallback(onknbXYControl);
      knbY.setControlCallback(onknbXYControl);
      
      // button to enable updating all XY pads when one XY pad is changed
      const btnLink = Content.getComponent("btnLink");
      
      reg curRadius = 8;
      const XY_MARGIN = 5;
      const XY_INSET = 5;
      
      
      // init XY pads	
      const var pnlXY = [];
      for(i=0; i<5; i++){
      	pnlXY[i] = Content.getComponent("pnlXY"+i);
      	pnlXY[i].setControlCallback(onpnlXYControl);
      	pnlXY[i].setMouseCallback(pnlXYMouseCallback);
      	pnlXY[i].setPaintRoutine(paintpnlXY);
      	pnlXY[i].data.shape = i;
      	pnlXY[i].data.u = 0;
      	pnlXY[i].data.v = 0;
      	pnlXY[i].data.x = 0;
      	pnlXY[i].data.y = 0;
      }
      
      //just for fun knob to change the cursor size
      inline function onknbCursorSizeControl(component, value)
      {
      	curRadius = value;
      	for(i=0; i<5; i++){
      		pnlXY[i].repaint();
      	}
      };
      Content.getComponent("knbCursorSize").setControlCallback(onknbCursorSizeControl);
      
      //just for fun knob to change the aspect ratio
      inline function onknbAspectRatioControl(component, value)
      {
      	local h = Math.range(150*value,50,150);
      	local w = Math.range(150*(1/value),50,150);
      	for(i=0; i<5; i++){
      		pnlXY[i].set("height",h);
      		pnlXY[i].set("width",w);
      		pnlXY[i].repaint();
      	}
      };
      Content.getComponent("knbAspectRatio").setControlCallback(onknbAspectRatioControl);
      
      
      
      // Update knobs and repaint the panel on control
      inline function onpnlXYControl(component, value)
      {
      	local x = component.data.x;
      	local y = component.data.y;
      	knbX.setValue(x);
      	knbY.setValue(y);
      };
      
      
      
      // Mouse handling
      inline function pnlXYMouseCallback(event)
      {
      	if (!event.drag && !event.clicked){
      		return;
      	}
      
      	// get the mouse position in the right coordnate system	
      	local b = this.getLocalBounds(0);
      	local m = XY_MARGIN+XY_INSET+curRadius;
      	this.data.u = (event.x-m)/(b[2]-2*m);
      	this.data.v = (b[3]-event.y-m)/(b[3]-2*m);
      	
      	// clamp u and v to the bounds
      	if(this.data.shape<=0||this.data.shape>4){//bounds = square
      		this.data.u = Math.range(this.data.u,0,1);
      		this.data.v = Math.range(this.data.v,0,1);
      		// square needs no further calculations so just return
      		this.data.x = this.data.u;
      		this.data.y = this.data.v;
      		if(btnLink.getValue()){ //
      			squareToCircle(this.data.x,this.data.y);
      		}else{
      			this.changed();
      		}
      		return;
      	}// else bounds = circle
      	
      	local uN = this.data.u-.5; //uN is -.5 to .5 if within the circle
      	local vN = this.data.v-.5; //vN is -.5 to .5 if within the circle
      	local dist = Math.sqrt(uN*uN + vN*vN); 
      	if(dist>.5){ 
      		this.data.u = uN *.5 / dist + .5;
      		this.data.v = vN *.5 / dist + .5;
      		dist=.5;	
      	}//dist is now 0 to .5
      	
      	// now convert (u,v) --> (x,y) depending on the transformation
      	if(this.data.shape==1){ // radial stretching (2017 Marc B. Reynolds)
      		//[x,y] = sqrt(u^2 +v^2)/max(|u|,|v|) * [u,v]
      		//we can cheat and use uN, vN, and dist again from above.
      		this.data.x = (uN * dist/Math.max(Math.abs(uN),Math.abs(vN)+.00000001))+.5;
      		this.data.y = (vN * dist/Math.max(Math.abs(uN),Math.abs(vN)+.00000001))+.5;
      		
      	}else if(this.data.shape==2){ // elliptic grid (2005 Philip Nowell)
      		//x = .5*(sqrt(|2+u^2-v^2+sqrt(8)u|)-sqrt(|2+u^2-v^2-sqrt(8)u|))
      		//y = .5*(sqrt(|2-u^2+v^2+sqrt(8)v|)-sqrt(|2-u^2+v^2-sqrt(8)v|))
      		uN = this.data.u*2-1; //uN is now -1 to 1
      		vN = this.data.v*2-1; //vN is now -1 to 1
      		
      		local SQRT8 = Math.sqrt(8);
      		local temp1 = Math.abs(2 + (uN+SQRT8)*uN - vN*vN);
      		local temp2 = Math.abs(2 + (uN-SQRT8)*uN - vN*vN);
      		this.data.x = .25*(Math.sqrt(temp1) - Math.sqrt(temp2))+.5;
      		temp1 = Math.abs(2 - uN*uN + (vN+SQRT8)*vN);
      		temp2 = Math.abs(2 - uN*uN + (vN-SQRT8)*vN);
      		this.data.y = .25*(Math.sqrt(temp1) - Math.sqrt(temp2))+.5;
      		
      	}else if(this.data.shape==3){ //FG-Squircle (2014 Chamberlain Fong)
      		//x = sgn(uv)/(v*sqrt(2)*sqrt(u^2+v^2-sqrt((u^2+v^2)(u^2+v^2-4u^2v^2)))
      		//y = sgn(uv)/(u*sqrt(2)*sqrt(u^2+v^2-sqrt((u^2+v^2)(u^2+v^2-4u^2v^2)))
      		uN = this.data.u*2-1; //uN is now -1 to 1
      		vN = this.data.v*2-1; //vN is now -1 to 1
      		
      		local temp1 = uN*uN + vN*vN;
      		local temp2 = Math.sqrt(temp1*(temp1 - 4*uN*uN*vN*vN));
      		temp2 = Math.sign(uN*vN) * Math.sqrt(temp1 - temp2)/Math.sqrt(2);
      		this.data.x = vN==0 ? this.data.u : .5*temp2/vN + .5;
      		this.data.y = uN==0 ? this.data.v : .5*temp2/uN + .5;
      		
      	}else if(this.data.shape==4){ //Concentric (1997 Peter Shirley and Kenneth Chiu)
      		//x = u^2>v^2 ? sgn(u)sqrt(u^2+v^2) : 4/PI*sqrt(u^2+v^2)atan(u/|v|)
      		//y = u^2>v^2 ? 4/PI*sqrt(u^2+v^2)atan(v/|u|) : sgn(v)sqrt(u^2+v^2)
      		uN = this.data.u*2-1; //uN is now -1 to 1
      		vN = this.data.v*2-1; //vN is now -1 to 1
      		
      		local temp = Math.sqrt(uN*uN + vN*vN);
      		if(uN*uN>vN*vN){
      			this.data.x = .5*temp*Math.sign(uN) + .5;
      			this.data.y = 2/Math.PI*temp*Math.atan(vN/(Math.abs(uN)+.00000001)) + .5;
      		}else{
      			this.data.x = 2/Math.PI*temp*Math.atan(uN/(Math.abs(vN)+.00000001)) + .5;
      			this.data.y = .5*temp*Math.sign(vN) + .5;
      		}
      	}
      	
      	if(btnLink.getValue()){
      		squareToCircle(this.data.x,this.data.y);
      	}else{
      		this.changed();
      	}	
      	return;
      }		
      
      // on paint function for all XY pads
      inline function paintpnlXY(g)
      {	
      	g.fillAll(this.get("bgColour"));
      	
      	// Calculate and store the cursor's XY position 
      	local b = this.getLocalBounds(XY_MARGIN);
      	local u = this.data.u * (b[2]-2*(curRadius+XY_INSET)) + XY_MARGIN + XY_INSET;
      	local v = (1-this.data.v) * (b[3]-2*(curRadius+XY_INSET)) + XY_MARGIN + XY_INSET;
      
      	// draw the xy area outline
      	g.setColour(this.get("itemColour"));
      	local bs = this.get("borderSize");
      	if(this.data.shape==0){
      		g.drawRect(b, bs);
      	}else{
      		b = this.getLocalBounds(XY_MARGIN+bs/2);
      		g.drawEllipse(b, bs);
      	}
      	
      	// draw the XY pad cursor
      	g.setColour(this.get("itemColour2"));
      	g.fillEllipse([u,v,curRadius*2,curRadius*2]);
      }
      
      // update all the XY pads when the knobs are changed
      inline function onknbXYControl(component, value)
      {
      	local x = knbX.getValue();
      	local y = knbY.getValue();
      
      	squareToCircle(x,y);
      }
      
      // helper function to convert (x,y) --> (u,v) for all XY Panels
      inline function squareToCircle(x,y){
      	//square
      	pnlXY[0].data.u = x;
      	pnlXY[0].data.v = y;
      	
      	//radial stretching inverse  (2017 Marc B. Reynolds)
      	local xN = (x*2-1); //xN is -1 to 1
      	local yN = (y*2-1); //yN is -1 to 1
      	local temp = Math.max(Math.abs(xN),Math.abs(yN));
      	local dist = Math.sqrt(xN*xN + yN*yN +.00000001); //dist is (0,sqrt(2)]
      	pnlXY[1].data.u = .5*xN*temp/dist +.5;
      	pnlXY[1].data.v = .5*yN*temp/dist +.5;
      	
      	//elliptic grid inverse  (2005 Philip Nowell)
      	//u = x*sqrt(1-.5*y^2)
      	//v = y*sqrt(1-.5*x^2)
      	//use xN and yN from above
      	pnlXY[2].data.u = .5*(xN * Math.sqrt(1-yN*yN*.5))+.5;
      	pnlXY[2].data.v = .5*(yN * Math.sqrt(1-xN*xN*.5))+.5;
      	
      	//FG-Squircle (2014 Chamberlain Fong)
      	//u = x*sqrt(x^2+y^2-x^2*y^2)/sqrt(x^2+y^2)
      	//v = y*sqrt(x^2+y^2-x^2*y^2)/sqrt(x^2+y^2)
      	//use xN, yN, and dist from above
      	temp = Math.sqrt(xN*xN + yN*yN - xN*xN*yN*yN)/dist;
      	pnlXY[3].data.u = .5*xN*temp + .5;
      	pnlXY[3].data.v = .5*yN*temp + .5;
      	
      	//Concentric (1997 Peter Shirley and Kenneth Chiu)
      	//u = |x|>=|y| ? x*cos(PI/4*y/x) : y*sin(PI/4*x/y)
      	//v = |x|>=|y| ? x*sin(PI/4*y/x) : y*cos(PI/4*x/y)
      	//use xN and yN from above
      	temp = Math.PI/4;
      	if(Math.abs(xN)>=Math.abs(yN)){
      		pnlXY[4].data.u = .5*xN*Math.cos(temp*yN/xN) + .5;
      		pnlXY[4].data.v = .5*xN*Math.sin(temp*yN/xN) + .5;
      	}else{
      		pnlXY[4].data.u = .5*yN*Math.sin(temp*xN/yN) + .5;
      		pnlXY[4].data.v = .5*yN*Math.cos(temp*xN/yN) + .5;
      	}
      	
      	//set x and y as well
      	for(i=0; i<5; i++){
      		pnlXY[i].data.x = x;
      		pnlXY[i].data.y = y;
      		pnlXY[i].changed();
      	}
      }
      
      HiseSnippet 3686.3oc2ZszbabbDdgjfKQ32U4bMdBqTN6h2.DTjxzTlRTR1LVDFVT1EYoh10hcG.rQK1EdeQrQjw9fSk+F4d9Cji9OPNlS4RtjS4R9G3z8L6iYwtfuRbpJ1UhM2Y5tmt+5tmo6Ay.GaMpqqsiToJOKbFUpzqU9fPKuI6NQ0vRZuGhCrqgiluopygGI8fvYpttTcoRkt4GgTTZkaIw9m+0G9.USUKMZ5PRRegsgF8IFSM7RGcvNehgo4iU0oOyXp.081YOMaqcsMs8As4lkaKMSU6Epio8UQxtQYoOV0chTopk06zqynM0Tuylc50USq6laz8tanQUGMhdmNquQuMG0ajpV6tRkdkGoa3Y6bfmpG0Upzsdfsd3ASrOwhu.eggqwPSJ9QGoCfUlO7isM0QSDGUZ2IFl5ChgIWIPJCRAsaxAs2o79F5FIimBduEaBRJGh.XoajU8tYF0qin50VP8JPkJInR2hqRuc4CzbLl4kNCpOuZ48r7nN.7PynJbZktwe5cK2pE49Vj6ir3MkZ4QrGQN3q8UcnDUKcRbv.4viHCT0cq.z+fPxuF7UjO1e1LpiGLDN5GSMmMx2zj7Tpptg03JLIqZF5YnoZR1m5MwV2kLx1gKefDh2DJ4gFtZjggD.EmNj5XBXI4w1b9WYhm2L22uUKUm4FAMscF2Zl9nVcVu8ca19Nq0qGRziLMAiwXDrLdF1VnA7Tplmp0Xlhu2THnxID05qxRrAtDar4FqiDwAjVLUcp5rYft6h579pNZjGzDVuPKHJxMi.mBS1XXCmn4ZN1vah+vlF1vLdSZ0scmMZ0tSq1a1hKdT5Mm3M0jToxt1feyxq4T0WPerC7QheTdyNsqS5tdakspfKmgkgG4Plu5HxKrrG5VAxqb8f+d3gjsIwRZL0aW6oyrsfOjWEmbUPBIjdz4Q5QHoHKMcwor7brM2U0zbHDEHaagybTzvbBO5RQHp9C887.elmMgZoBQ+D+Y5faDhM.1vftYPPG4jITvuZQiFfX3Rzl.NXpdjELzy5IFVuXoFQz7ncTwgNln467THJ02E3XyXX3vi9p8u+S+n85CCttvf60+fG8L9XBPNW0VIhr.HRalk4gHN97i2pBDlKarc6sHFev5v+pVMkWVYEFAO233kplLBVslAnlIDWLTxlMEJyP8919tzDZYyjYnEoe.jO38Tae.1oxyvOXylgLvon1zch5LJn7F4lwGFsctQCJbz4ENZHezyPD923CHJtQwHeKVLMFevc3rsL.uGrcEw032RqXXYBpMRoFO6Gix1kQvAv7QPjrVLHWGbUl9TkJf+PLJfMJnUE53R0UGJCfjQv4rJmsUkklzjpCqprzzgbJJOs3h..U2YvNbDGbCuhQf6yn3oHAmKDXZiaNOA.f8gMkZ5fKgLr+ZUFI0Wuc8NrsZhH7j7DJ2oEWbBDeAfHfFxqNgZLdh2p0mfLrvbmXn6MY05mjcpKO1KX8mC3mGiPzmkh+43tPT99or8ViVaF5OS0hZBvLQiyUAd.wzyyC3wbgjoiROR.6v7SFBSFuQ7WfxRdtBeniRGJDF5rXKgk4SfPGcS7P4EU076NHSCfkioiFiHx+B1mM0cTGSdu2iD8olog1Kn5L2pC0y2wh4SprBrhf2fASSYq7LaWC1JAm4hi5fdcvrrczsPH1Mz0iNckXadHXydSLbQe5SvQdfsuktqrPL3TfjjspqEu+bsjjYfPlDR1XhaQMm2XpRK4gOu6wM5VcpRFxvcpfoV63FbZCincsDZYlllo5zYDeVDQ.lShVzPlFhnkbp.YaU9Aa29zSWXr60S4ksZw4AVTW1Q+.JlUkExwDlnNjfwRIxp3ERbPBwfdyWEhEkBKpkM39c.M2g.vIVcG5ebIt1D19Nb+YlUYdrWgqGYUgvLSFfSBPQzItnejGUpn7RBTo3JqrBWadlMVaoonNOutfTY59YTSWJFjwWunC8k4ykI1CrRjVRBxpwjdkjHK+9YMhFMgslZ0BFFpl.9.cmv+Fh4OAJTKJZMVHbQDjUDAQhH3JHBcC.gibYtesimre+pfJTCjc0f9JaQXwQHU2q45.hkKx.HtJrFs3RpFrd4CHBJjF7isg+bEFZwlx.iFNgzlq3QA43HvNaAPo8DY+5AJjFMtGQdd8PEhNcF0BqtG29CsNOHtyE1teJKHpnjfs2tCyyCmVoa.HfqG3zzlfxPFqANWQzJrX1mCq2wrDDDj9xtjZAeYWEnz44xm5eZ8SCNUgTk7bP+NlQ+I.RqBaIOgp5wxOwMe76Ca4B+e7alAqNFq8eji8Th5P6.Zybg4xH.yHtEyIgKH6OTG5ByoTO4CvcUqYa9+zQA960ymWHG7elzpvy.HEAqc4vJk29iFYrigNBosWmL.ZYzXFou8Ivrb7DsslqWUlgmm1sF.oM.DsF66MU7OUowBS0HcJtHByJhF.c0DDQPpHhmpQ5TnHVLErZ2FcRyAw3tFcvPwN.sKlqESaPAzB+Od10Ae1Se1lYRu1jsUAeV3blYchmEwbHnB820Xrof4gMhyCyvT2BXpQwLkMXpYW.tRUFlB.oSjrC0MM3IuF1fDuCADhDqowKVdcKC4MVf7LglWUc67BEWiEJ93OpAzIKa6NVpcubMbmFJ5N1R1O.NiMnJas5pTMNSOMvI9Kkjg6A+ANfPDYhj7u9R5G8.yXGalc6WRPVp6nJ++.NkdUYbVkGnk246Zfn.aRX+lEDCvO2U1JchtEDsFze6saS9PQff79XFOiaz.yebSHynVju.Q97S467hg5whgfZl0fBvbf8yj6b26tAY.0CJT4fIFNlzP1F4eB0xh5MABtL7SCn.248.+InFr.BEwX.EPc50ZvdYBLTf0FHrEdRRRvTpTVB8AsfSeP4gqRP1U4+UARmW8C7huXCdO9PoUOktsD20TULzQIwIsf2sKOpAPiTd3PQ+VYNKS73qDgsPAbIpvRkpunTCVhTWbqrb1Sff8bF1YxJUVVQoUtJEjlXN4JG8LXEhqF8Lvgg8dg8Ww5ZLocKrmdgK1Je6XI29hLrY4KAYNt4HCSy6aZJG2Vj7pCGyu27UUR5LY2nJ442Zqqmsi3Uk7qbYqXbqXWTyVIcWk1zke13ZXSl3NojSZ7JoWLlmJ81zpkbIZIhi0uUmFBQ+JbQt1UWjL6G5O8DlAOG1jvgpRr88PnEAPV++HdI.gFP.iHHFAHtBHBfyPSpznqvYqhqssMK.ZL1e7I3sNKOrNHkLgJWHJWanaK99wb4vtPaWpfnhbxIFYz0fxctWrI1kai7PoXoikNWOAnq1U7uOVI5l33WGKkEyltvQWHKNPzMj.QawWHagWG0k9xPXWtQZ5Yl6BgcKGhyUYwLWrGkXMeB0bF0IUOvaPKtqFVuLrtZX82HjUN.uam74kErNuDcIwsuyuip1B2F57sVbTLlOLJeMeuPFnpAGMt7lhh.I7TC443gEJ3oEy4MeFeRQDZwHJLgnvhHR7njL8kLWrujv9B4G45dcd+pywrwv9Ug0PXuZbUiawTtc8nZNNNFS5HfTvt2fXPsgyAudyrzEvoKLOcHZlsEHQjrfdgfCiQ2C+r8NMPoxN6FN3EcPBiOOZbrSRvJwMVAiLs4wXkraViA.kL0f0oACcfNxiqkNKaQ1FfzKvFCbEXC0kKUM1YLQvJpAVXC3+xrzVhitncewDyAi5.RHzVsHljqBkrwHMHbyh8kBySlfHqUXTQ7A4YoIaDQLMnFd0KgjiWmN+z6s8ogmBE+Muplsq7f8Z0qZXq4X4d.9XXwGYdqvDXKCOITjvShTh4Y4gRhvFxB+7Fwbx6scljxzaTuWNXiQHt3rxhB6C6RjVOTVlBxxDZCEvTxgYEthgKx779vVNWvJFtnZlkony7fC1fyEX3EQEN2AxguvedgjhLmuUtgCi1DNc3LEwU4Lgys5a6Q+TKY1ITvgJjEmZznBmK5jNSpSgSiOCBmyiQYKeLgV77QjPoR2J66Gn7xe+.hOuAM9ORh.g1V6YY38oynVK6QOHE8KqHAqRjVAj5wdoAuQzKM3Are4VICcoRqTNpvZIlJK9JQjVF6GXZ.0VwX+UJim5mg2uc9e3eb448nL798+ke1e6Rw6aUN6OBz0S6eyxY9c7VTHjcj978dHD5guaiHXEfZ7gSXfdwROjFXnQ4uhiUJ+Pp6K7rmAhM4WzRpzqxW7WO9Mdf0nvV6aWlEF2VZN3nJUAVtvzU9WtC6mQKYfue3N7eyMwQfxdrOI9m9wEsFnUCR5.oEQhOMndcuau6dmM5d20ElnaxLs6rd6tRoUMmpK2dm3dVfwdke3G9g2gM7UvF6f1Xj31gtyOYsytB14ez6mt14Zh14u6mt1YOA6bv28+u1Y4r14STGlXmr+VL+TpmncpuiGctGRH+cNckDqX5v2NpHw9ZkOHoKpqjnEi.2wuHQWobzaKS6JIXQW9NeSQB9MKmTGO9F0tRRecwDmuqXDIsD3hD84dB9x7hFQB+MJydnUQOGvyS74Ogetn3Rk82ONIB4PxmXYO7pH0iVlWTPpGkWp29xWUvRxeSj+qWVj5o7WI6696+me1e9m+W+PnwZwrroF55lzAQWD2BkZjnbqboK1HU3+8uIqtsrUhriqGcFO6ub4NMaGqwwJRFMtWZHU5hJk+4m9Vk22VGu+wruFV7MCGMApDhOAU7AMZAJWn3Z+esmH6kUEe6xCLfsNJVGuQA5HTE2OF5XzCK90K+nQifPoTE7Vke7g+37Jhk3u3uwPSXNFX8i88md.b.fFEVcK7VvvZJuAdJ.+6132HBb.0Rm8AbNwODMYG76RQS1IdRoopZN1eUz6jBe5x2lMBnSVrm48Jk2G+lzYwxlkfvRciuRSKqnxwX2qKiqccYr20kw0utLdmqKiabcYbyKlQ7gteeeOa9C+.HX+AOh0lSoROh8RdYQqR+aPONMfL
      
      posted in Scripting
      hujackusH
      hujackus
    • RE: Help with this noob error please.

      @Chazrox said in Help with this noob error please.:

      Is there a hierarchy in placement of 'var's and const's in respect to functions? Can I declare those anywhere in the script as long as its not inside of a block of code (with the exception of locals's)?

      inline functions, const and vars can be declared before or after they are referenced. But regular functions need to be declared before they are referenced.

      Note that you should try to use const and reg instead of var whenever possible to increase performance.

      posted in Newbie League
      hujackusH
      hujackus
    • RE: Circular XY pad

      @hujackus said in Circular XY pad:

      It's the only transformation that I could think of that I knew how to code.

      Is there any interest in trying a different transformation? There are others out there that have different pros and cons.
      Some equations on stack overflow
      Schwarz-Christoffel transformation
      squircular.blogspot.com<- I think this is the transformation I wrote from scratch. Not sure.
      Square/Disc mappings Includes an interactive demo!

      posted in Scripting
      hujackusH
      hujackus
    • RE: Circular XY pad

      @mmprod said in Circular XY pad:

      Conceptually, how is the distance and angle used to calculate the x and y knob values?

      It's the only transformation that I could think of that I knew how to code. Here's a picture comparing a square XY pad to the circular one I made.
      Circular XY Pad.png

      Basically, I calculate the angle the XY cursor pad makes with the center of the circle relative to the x-axis. Then I calculate the distance between that point from the center. The tricky part is that I multiply this distance by a scaling factor so that every point on the boundary of the circle corresponds to a point on the boundary on the square. Doing it this way allows a one-to-one mapping from XY pad to the knobs and vise versa. The angle relative to the center is also preserved with this transformation.

      posted in Scripting
      hujackusH
      hujackus
    • RE: Circular XY pad

      @mmprod I had some fun working on your Circular XY pad (for a few hours🤣). The solution to your problem is that you need to define a transformation from Knobspace (x,y) to Circlespace (angle, distance) and back. The pixel coordinates of the XY cursor can't be transformed into the knob values in a linear way so I used some trigonometry to make it work.

      HiseSnippet 2356.3oc4Y80TiibDWFv2sVIWt6pJOe0D+RjwFijMdWtkkk+SBUB6Qsr2dPQn1LHM1dJj03SRFrtb7X9NkGy2gT4o7ddNeC1z8LRVi.afPkKuDphBOS+ueS28zc6giBEtrnHQnQIy2kLjYT5mW93jf396zmxCLNXWiR+rx646yGFwN4TisSFRihXdFkJM+uAYnTkELj+7u1XapOMvkkukgw6EbW1umOfGmu6Qa963996S8XuiOPi6U17.WQvNBewH.LyW11XH08RZO1anHayU132Ri5aTZwxdNq3zcUW5yW0YkVttsV8Es95W3xnc6xdtSmWrxpcWoK00tkQoOYOOdrH73XZLKxnzBaK7RNtu35.kAdOOhegOCW3XbLXY016K78viHtqwN849dGk4khL.sbTtOadkO6WV9PtGex949tuPRfjKgtCrzbEg27EfmiN7r0f2TfTIMHsfBReY4icC4CiyonhkGDDyBA2Cq.TT7ZL2+7yKui.3HHt4.5kr8CgESjvpiscCRaa6ZqYZt7xjKCt3jDSHnEEq9LYcxYmulYWQHwhCKrWivIuhzB9S850L+SlUjrcF+bfXlc5wh2QLXnH.VXUUxPURcBGLxD1aFgLEDGJ72g56eAjXXIBjTS2F39FyTrbEMjbxoe3sas6Ae6wfkbZYq.7NgLvSCzHCodMHz.Oh6nPv2nI33jinw80vmqTHbSKvH5LtEPAOxcZzoQq113uvoWoflTOuzqMVJNqsFAfv3DBEEaHviNdU3X1lURVWom43zoA9aKvv1mWaM77oThT22V0ofMUQfSeawn.uHKmlxvYN6CC7O4zVyL.oHWEjQ8ooGZTzxiMn2mGviIw8YfeumOS5883fQiEjHw.VbedPuIZ0iFSapXDxiZ1YsJEnHEDhr1XjEU9aYCg6bJ8OjFv7Ih.hqx9l7.ed.izcTfaLG1+V3yxM630.7.9iXxTUegK0mLF8YYjU1drJPR3QDaD7.Hx3N4tbmH4NoH2lUFH7hNyVlXuUbbH+hQwLK3103kcv6WjTNbtKGIJNLytcnTx6QbakIMXx.QLIZTHiv6RRDiHWSAuiBADHGIGKJs3nokjbs3wFxfrDzYhd1KCDWP.fw.qmeNCU9dLO8FUn9PwnHFoODhAGeOsLEIgI4IYADK1Ufdjdc.spUM8Bo8H+3ORTqb84tWx7pYVAXpBlmFRu9DvcqHOdoIW3WKm9o.8I6ujhSU7nKbIBBJQ7dAni.q0AKoignzPAlGMZHnlTMklrcHdsd.OvB7NMjKh99vXKDGKJAScoMwOeZsZYvXRNrztpUfUbgaePYUhKj3b40bva0MTL.xpPLzDjk2Up4e0510vSbkL8HMLjXEfjOcYjmZfkkL+J6MHsaBcG670sddmWZKAwML+HVAUfB9ZahNuK2h7RxR5qkhp7AvMynhWHk+EOPHI73PUWbHWvhulwBHsO5.Pk3U7kvOUTKo9S7O2mNrWRlehxt7xvU0HgOq4vPLSCOr0q1nZcYPtNo5RultN10PBL4wVK10Zha6hHK4GbEQVJVmDmPFaeGFifvsFiYZS920WG8g.Fseobikk6hmH5UBNVb6JtGbbRH+.KTjJc6ToaOUoa+.R2ROMTtQCoXpdKYNR7lZfHb.0m+CLUQVbvrLWIQUESU.VVhBaIoKAMBqZ.UqulADnjnueDxAz6RVZsPvbbFjx8oKJQ1hM6.AjNp7daxqVGRte05pPZt3IYhm6omk3ISD+1oCjpiWuZccLUuZRgcRH0VqhV1rKTapGyyRt6Ml2f0SyqRcDVN6shQwPWi7hT8fBT.2XeVpu6HebTBzGFAivwjNcUy0ecjbBCQDW1rwTldgtIc.tjVa4yZct79FxWRA9RJxW6b9nE3SceTQIr.E4kLSErgJpWKwY1PHvIDaLZVompKNN5skTVnmuUUdLafZypxz+dXM4qKNUCLOnrWDndPERsisBUsY6l1N1iLBBu8HghXIETUxOyrVBzvYSpQ2XxmNu1cPsZrsrI1dPL2RBZjutv22PNHkRzF41CKYe2PQCHKIusws7+MJvbiBTQPKSkj8.OX2CHoSX3yBiRGwBaqiCMZVQ90rPTuG7EWbAruSeQ3nHmp0ZLShvgx7bUO1KXcw7NXHNP4vEbOzCiNhFjg9LJzQINLABFhKQBzXxr5BWaJyGoOZ8CMdzjwP5kM.AF6xGHZx.F5zMqnONGplwKJmlqv9n3Io6aVQwUKaYigzgvBw6wXQObuIyznjSmyjYvYFPehsogtziyZQe2NzIKOV1ad7zZLOoublbIOldx2TzA8zaHmcvKzVQNPy3Eg5mf6KQ9cJdvlJ4pYq6q8opp9Z57u880WdB+SYreUKP5XYKvsjs.2tl5zCkjciGkZ.Dfp.lKSFFsxB70TEWJ1FoJJibLh6XSXDiF+gXfj5bVWtpdpgQckJgdekaL0tP8FQL6aBrjWc.JjaSpa2oRKu9wTIiufR38InUvnAWvB0u3hLZTZghO8P4Y+zC5uLhq5qDpwnH3.3q08Mv2RXVuWhQ52izvnzbonBXMV9HE+hzGo3XeXVmPCtmQomUVVuv1PhX82Wx3wKsSAo+i+ku5uugw2dvtP3DerjT.AfbHKLlim+R6xth6xTOcRkx6xhtLVLDrzju4K3xdXLOdBd2bzlI4f+caZ7ehhbloh7JnnJJE8YYO0CNbVpdT4iZ5w305540adM2Kte9FAa1mw60OVeGnAg35r1DfS5yKukuOIei7dsfTehgwG+HJmVGX41ez3ip286NOQ0WT9PgGNGUwWLCeWwTBPtbgmoBeJp.XtpD87h+q8LZOVH9kkOhG61e5XbtofQL0+m.Ll93ieVY0LB4.bgx6exOQuz3bZ1+SU1+YkUylHMckzENEr+aAypGx9Nsju+5W8m+GarOi4gIUo6sY61+sM1k4SKFnm+QeJbtemnZ19dPejPNbEo7aFM3XHg0kA9v.3RDVQrzbXsK0ZabMBhiYAdxEeD9IknCttTJQmLhFORGUqY4njUs9+AG0+Krw.pan3CouGHlG+L4Nv4NP9eWnR4Cw0Dma21wvX.2i+AW2hp5NB15oJX6mpfq7TErySUvm+TE7EOUAW8gED++qr0nXw.UkXCiCOZOYi9Rk1KfBY4x6UF+a+In0rA
      
      Content.makeFrontInterface(500, 300);
      
      // knbXy
      const knbXy = [];
      for (i = 0; i < 2; i++)
      {
      	knbXy[i] = Content.getComponent("knbXy" + i);
      	knbXy[i].setControlCallback(onknbXyControl);
      }
      
      const var XY_RADIUS = 120;
      
      // Create XY pad, and cursor
      const var xyPath = Content.createPath();
      const var xyArea = [5,5,230,230];
      xyPath.addEllipse(xyArea); // xy area path
      
      const var cursor = Content.createPath();
      cursor.addEllipse([115,115,20,20]);// Cursor path
      const var cursorArea = cursor.getBounds(1.0);
      
      const var pnlXY2 = Content.getComponent("pnlXY2");
      pnlXY2.setControlCallback(onpnlXY2Control);
      
      // init the angle and dist to something;
      pnlXY2.data.angle = 0.5;	
      pnlXY2.data.dist = 100;
      
      
      // Repaint the panel on control
      inline function onpnlXY2Control(component, value)
      {
      	local x = component.data.x; // x is 0 to 100
      	local y = component.data.y; // y is 0 to 100
      	
      	mods[0].setAttribute(0, x/100); 
      	mods[1].setAttribute(0, y/100);
      
      	knbXy[0].setValue(x/100);  //not sure if you want 0 to 1 or 0 to 100
      	knbXy[1].setValue(y/100);  //depends on the knob mode
      
      	component.repaint();
      };
      
      // Mouse handling
      pnlXY2.setMouseCallback(function(event)
      {
      	if (event.drag || event.clicked)
      	{
      		var rawX = event.x-XY_RADIUS;
      		var rawY = XY_RADIUS-event.y; // flip y sign to make y axis point up
      		
      		var dist = Math.min(100,Math.sqrt(rawX*rawX + rawY*rawY));
      		var angle = 0; // angle is counter clockwise from x axis.
      		if(rawX!=0){
      			angle = Math.atan(rawY/rawX) + (rawX<0? 3.14159265:0);
      		}else{
      			angle = rawY>0 ? 3.14159265/2 : -3.14159265/2;
      		}
      		
      		this.data.angle = angle; //this is a value between 3PI/2 and -PI/2	
      		this.data.dist = dist; //this is a value between 0-100
      		
      		//Console.print(rawX+","+rawY + "->a=" + angle);
      		
      		var dist2 = Math.abs(Math.cos(angle));
      		var dist3 = Math.abs(Math.sin(angle));
      		dist2 = dist2==0 ? 1000: dist/dist2; //avoid divide by zero
      		dist3 = dist3==0 ? 1000: dist/dist3; //avoid divide by zero
      		dist2 = Math.min(dist2,dist3); // this is the normalized distance
      		
      		// data.x and data.y are normalized as if it were a square xy panel
      		this.data.x = Math.cos(angle)*dist2*.5 + 50; // 0 <= x <=100
      		this.data.y = Math.sin(angle)*dist2*.5 + 50; // 0 <= y <=100
      		//Console.print( "x="+this.data.x +"y="+this.data.y );	
      		
      		this.changed();	
      	}
      });
      
      pnlXY2.setPaintRoutine(function(g)
      {	
      	// Calculate and store the cursor's XY position 
      	var x = this.data.x - cursorArea[2]/2;
      	var y = this.data.y - cursorArea[3]/2;
      	var a = this.data.angle;
      	var r = this.data.dist;
      	
      	// draw the xy area outline
      	g.setColour(this.get("itemColour"));
      	g.drawEllipse(xyArea, 3);
      
      	// set the location of the pad using rotation
      	g.rotate(-a, [XY_RADIUS,XY_RADIUS]);
      	
      	// draw the XY pad cursor
      	g.setColour(this.get("itemColour2"));
      
      	g.fillPath(cursor,[XY_RADIUS + r - cursorArea[2]/2,
      		XY_RADIUS-cursorArea[3]/2,cursorArea[2],cursorArea[3]]);
      });
      
      
      // MIDI Controllers
      const mods = [
      	Synth.getEffect("Chorus1"),
      	Synth.getEffect("Chorus2")
      ];
      
      // before understanding this, please try looking at pnlXY2.setMouseCallback()
      inline function onknbXyControl(component, value)
      {
      	local x = knbXy[0].getValue();
      	local y = knbXy[1].getValue();
      
      	pnlXY2.data.x = x*100;
      	pnlXY2.data.y = y*100;
      	
      	x = x*200-100; // x range is -100 to 100
      	y = y*200-100; // y range is -100 to 100
      	
      	local angle = 0; // angle is counter clockwise from x axis.
      	if(x!=0){
      		angle = Math.atan(y/x) + (x<0? 3.14159265:0);
      	}else{
      		angle = y>0 ? 3.14159265/2 : -3.14159265/2;
      	}
      	pnlXY2.data.angle = angle; //this is a value between 3PI/2 and -PI/2	
      
      	local dist2 = Math.sqrt(x*x + y*y);// this is the normalized distance
      	local distA = Math.abs(Math.sin(angle))*dist2;
      	local distB = Math.abs(Math.cos(angle))*dist2;
      	pnlXY2.data.dist = Math.max(distA,distB); //the actual distance from center (0 to 100)
      	
      	//Console.print("dist=" + pnlXY2.data.dist + ",\t" +distA +",\t"+distB);
      	
      	pnlXY2.changed();	
      }
      
      

      Feel free to ask for more details about how it works. I know the comments are not completely understandable.

      posted in Scripting
      hujackusH
      hujackus
    • RE: A snippet to use computer keyboard keys to press buttons on an interface!

      @johnmike I looked at your code and fixed a few bugs, changed the way the buttons and states are initiated, and used const where appropriate.

      HiseSnippet 1908.3ocsZt0biSrDGeT1nCaLWJnJdg2F7CTNjKXo3a4D1EiiSBt33cMqSVfZqsXUjFYOmHqwkz3ciOGRU7QiOR7M.5VWrk2XAqhT7CSxb4+z+TO8zZjsF3ILY99BOhRoymOkQT9.0gyckiOdrA2kzqKQ4iT6a3KYdzvl5LepguOyhnn7fyvFT1ZSRvm+3a5X3X3ZxV1Dg7bA2j8e3S3xksNn82ycbN0vhcNeRhQWqcOSg6wBGwLfmGnVkL0v7JiQrmXfCaCUx2Y3Oln7kpVZ0zraYZznkVMcSS8VM0OroIyv1l0PqdyZsrqYaXVUmn7uNwhKEdCkFRlOQYyNBq4CGKdianAdN2meoCCqnQFBVNr4SENV3kH1J43wbGqAwNJeBLKCV51dPna6SU6ys3KZeo66iC5ftTQRGnxFqh2CVAOsj3UMAdqAIkDHsYHReh5PSO9T4xdPdde0dtvpI3dXqfR3XIaz+gpGKfQ3J2ehwUrS8fJKTToQ0p6ROnZ0sOpTou5qnG6w.voFzKgEpQdhYtVzoFtLGpTPMMlJm4wnWwlO0C.f4WBVd8kzNmQeDM1HiXxiESlJbgJUJ24rxQScWlM2kQkiCl.JvIej6DXP9TagGUuN8xYRILeQSJLnuMwXdD8EknvmxZk2kVVGKN.KpgE0whFXQSrnET.e.i1IbJoZ60JT8gX+UC6+u+SB0GtmV0P4mhx6mQ4ZZ6ooGp+GP8+HVbBV7Lr3br3mwhKvhd2F9C1SOx9CvQbFVLDK5lNIIzqqsmdsP8cJSeG+rPOrxT5kgKgWL0BiNdkOtD65OaBy56YyGDFK7JLDg6Z5LyBBfbbvEP+RcNa+0N5Jqt7FEi7LlMyiAYbnrq49Rt6n3fBpADI5C6rBhfl.FBZgZ34YLOJdIdfPfBfaTs8Aqw7dMqhd8HSzykK4FN7+GKRALq3d0Ulkvsu+CSkIbQhaSBBeubQfF3t3tNXnt8LWSIGrfvMzUhaQ7DNULi2erK80FNyXaW5+WZKGALgTt00fYiMI20hc8SsWJ.r7Vb6Jvnd7ipR+hu.G+WG.zVakD8W.s+RXhBl9iJcC.bIDyJbnwpGQ4zuFVWg+tyNaSAiCNlSYRyw21ue4bZutAAOQs7B9KSe2dvPJS2ALzNZaCXspvnXAzIbbj2qxa4bVqlJkkrqkk2Mx.zx6rZ3CLrUzE6D.RSLQ.qOG8GU19HJszMAgCCYxE4ynKVQASf4od6jfQQywQwKtDhWnqHt7+htyn8OGOlAy0hDdif6f.QXQ0SlaKLLFU4wFgc1CW2Au7piaQ3.Xl8sX9AI3AyhginXtMsRr3GumVLIQzbtXzHmv7uAQ7TgcPESgGbw.qfVKW1WnaE2Y7biq+e9564nEJwqjnMXKhmSNtECDoNre.XDzSfbEgayimfffR+RISOE1CtZDtjtdb19n0Ixbrg6HlEFFf9EO9nQvogB7EQqnKTcSv+cCk43yR3Nw7YBG19S83XXODPPcER3Z1TLxERsX8uo3lfasNQCtO3kyFMB80tB28div6J7+CRVFZwa.pSj53IBI6otUBxQ.Asz2tKa601Wz1IGl2Z6FOnl2emvJtylbIyKYFJbfvgQV8DNpoeBmjG.yLLeQhAJbwTwOcJyMsikQhRx.mF5yhnBFpL3rPeTzYgBSHP3vQd1RMrhFI.4jmikjA454S9A4Sds7Iud9j2HexalO4sxm7CuaxKEG1TMm50xod8bp+fbpuVN0WOm5ajS8Myo9V4TeNi+zyY7mdNi+zyY7mdNi+zyY7m95h+tnWWCoA93zQ2KAt+xTlmji25RoK60bSV3CWukZWl+URwzfwFchVhx6EZ2OL9QuwiAFX1MU6bF45jeyHySV4MbK4X3tiJ+zFDxXFezXIVaWEBANig3MwmczGe.d77CAmnL3FcKr8CeGtUWBBdR6DD731QDD0P6KZGSQ7P51dpA7vVxDVL3hBOp8R2JEuybVXROISV2OLomQlNHASsmd+vzAYjoZIX52d88CS0xHS0Svzu+q2OLUOiL0H0X7yKLlZjQlZlZLdwwTyLxTqTiwKNlZkQlNL0X7hioCeGYJw47RKHu3fpZVgJ0L4seUgA0oYEpTSkWfP0OqPkZt7BDpeHqPkZx7BDpeLqPkZ17BDpSxJTolN+2rKLndVVgJ074EHTmmUnRMgdAB0OmUnRMidAB0EYDJ8TynWfP0KqPkZF8e2ovfZPVgJ0L5EHTmkUnRMidAB0vrBUpYzKPn5lUnRMidABUGB41+zyerZeg0LGC4p+R336KPTGbwpuJA3OwrqOWNO4yiWX+73uqH9IpC3RywqmwMVCiDx8BiQuTAen5I11LS4R.2T8ze594MHf7LwL7WxqugziCgMpOY1jghYdlLv5ttLG7KuWYC7qYOrdUrN5AFxbsBp7mvmnN0v5JQcpE2IYhgom3WLC+VZvWagGFzBvjavq3wVp8w5za8cSQHS3V7ewzb0o5VB0uqBO3tJr1cUX86pvF2UgMuqBa8OKDeIW91YRwjvsMDR+AmD7coonbhqADAFDsR9KPqzCnZ
      

      Screenshot 2025-01-29 205320.png

      posted in Snippet Waiting Room
      hujackusH
      hujackus
    • RE: Help with this noob error please.

      @mmprod said in Help with this noob error please.:

      how do they increase performance? Is there a big difference in cpu usage?

      There is a difference when you have a lot of variables. If you use the var keyword for all your variables, when your program references a variable at runtime the program has to search for the location in memory that variable refers to using a dictionary/hash lookup table.

      If you use const or reg, these variables are optimized at compile time to work more like indexing an array, which is much quicker. If I'm wrong, I would like to know a better explanation.

      posted in Newbie League
      hujackusH
      hujackus
    • RE: Setting colors in paint routines. Colours.fromVec4() troubles.

      I added another test panel and I think I figured it out.

      const Panel10 = Content.getComponent("Panel10");
      const colorConst10 = 0xffddbbaa;
      Panel10.setPaintRoutine(function(g)
      {
      	var vec4 = Colours.toVec4(colorConst10);
      	var c = Colours.fromVec4(vec4);
      
      Console.print(colorConst10); //4292721578
      Console.print(vec4);         //[Array]
      Console.print(trace(vec4));  //[0.8666666746139526,0.7333333492279053,0.6666666865348816,1.0]
      Console.print(c);            //-2245718
      
          g.setColour(c);
          g.fillRect([0,0,20,20]);
      });
      

      The thing that I was getting wrong this whole time was that the vec4 array contains normalized RGB components. I thought the problem was that the colors were out of scope or something.

      posted in Newbie League
      hujackusH
      hujackus
    • RE: How can you tell if you have a VST2 or VST3 license?

      @clevername27 said in How can you tell if you have a VST2 or VST3 license?:

      @hujackus I wouldn't worry about it. Just do your thing. I don't think Steinberg will mind.

      I'm just trying to comply with the open source terms set by HISE. It is impossible for me to release my VST2 version because of not having a VST2 license from Steinberg, and even if I did have a license I would not be able to release it because HISE requires the project to be fully open source under GPLv3 (unless I purchase the Indie commercial license).

      In fact, nobody can release a VST2 under the HISE Open Source License. It was never possible. Therefore, I must consider VST3 only if I am to use HISE. It has taken a lot of review to come to this conclusion. Right now I'm just trying to find out if it is true that I don't need a VST3 license from Steinberg if I only release using GPLv3.

      posted in General Questions
      hujackusH
      hujackus
    • RE: How can you tell if you have a VST2 or VST3 license?

      @d-healey said in How can you tell if you have a VST2 or VST3 license?:

      @hujackus said in How can you tell if you have a VST2 or VST3 license?:

      Would it be easier to search the HISE-develop\tools\SDK\VST3 SDK directory and delete all the files that don't have the dual license and see what compiles?

      You could try it.

      So I tried it. I deleted the HISE-develop\tools\SDK\VST3 SDK directory and I recompiled HISE Standalone without any problems. I opened up my project in HISE and exported it to VST3 and immediately got an error "VST SDK is missing".

      I put back the VST3 SDK directory, but removed the vst2.x subdirectory and I was able to successfully export it as a VST3. I disabled VST3 support and it exported as a VST2 successfully.

      It seems HISE does require some of the files in HISE-develop\tools\SDK\VST3 SDK, but does not use all of them (all the vst2.x files for example).

      posted in General Questions
      hujackusH
      hujackus

    Latest posts made by hujackus

    • RE: Compiling Just an Empty Clone Container Fails

      @clevername27 said in Compiling Just an Empty Clone Container Fails:

      When you say struct, do you mean class?

      Yeah clone_base is a struct. It has a few methods, but no member named ‘isPolyphonic’. I'm assuming there is a wrapper class somewhere trying to cast a clone_base into a class that has a isPolyphonic() function.

      Setting the default return value of NodeBase::isPolyphonic() from false to true is an interesting lead. Looking for subclasses of NodeBase now to see how it relates to the clone_base struct.

      posted in Bug Reports
      hujackusH
      hujackus
    • RE: Compiling Just an Empty Clone Container Fails

      @d-healey said in Compiling Just an Empty Clone Container Fails:

      /HISE/hi_dsp_library/node_api/nodes/Containers.h:116:49: error: ‘const struct scriptnode::wrap::clone_base<scriptnode::wrap::clone_data<scriptnode::container::chain<scriptnode::parameter::empty, scriptnode::wrap::fix<2, scriptnode::core::empty> >, 0, 1>, scriptnode::CloneProcessType::Copy>’ has no member named ‘isPolyphonic’
      >   116 |     bool isPolyphonic() const { return get<0>().isPolyphonic(); }
      

      I'm trying to parse this error. Basically, some code tried calling isPolyphonic() on a clone_base struct when isPolyphonic() is not defined for that struct. This is probably a runtime error only seen when compiling clone containers. The location of that code seems to be in the Containers.h file within the container_base struct.

      The container_base struct has a protected member std::tuple<Processors...> called elements. This is relevant because the error is referring to get<0>().isPolyphonic() and get<0>() is defined further up in the Containers.h file
      as (i'm not sure which one)

      template <int arg> constexpr auto& get() noexcept { return std::get<arg>(elements).getObject(); }
      template <int arg> constexpr const auto& get() const noexcept { return std::get<arg>(elements).getObject(); }
      

      so get<0>().isPolyphonic() is kind of equivalent to std::get<0>(elements).getObject().isPolyphonic() which breaks down in English to get the first object in the elements tuple and ask if it's polyphonic. The error leads me to believe that there is a clone_base struct in that elements tuple of Processors and clone_base doesn't have function isPolyphonic().

      clone_base is a struct defined in duplicate.h and does not seem to have a polyphonic anything related, so I'm guessing there shouldn't be a clone_base struct in that elements tuple. So I'm thinking where does it get in there? So I'm looking for where clone_base is referenced and I stumble on this alias definition in processors.h

      template <typename T, int NumDuplicates>
      using fix_clonecopy = clone_base<clone_data<T, options::no, NumDuplicates>, CloneProcessType::Copy>;
      

      which means I can cut down the size of the error message to this

      /HISE/hi_dsp_library/node_api/nodes/Containers.h:116:49: error: ‘const struct fix_clonecopy’ has no member named ‘isPolyphonic’
      >   116 |     bool isPolyphonic() const { return get<0>().isPolyphonic(); }
      

      I don't know how all this helps anyone. Does anyone else have a different error message related to this problem that I could look at to look for clues?

      posted in Bug Reports
      hujackusH
      hujackus
    • RE: Circular XY pad

      @hujackus

      An Assortment of Square and Circular XY Pads!

      Ok here it is. I put five XY pads and some fun knobs into one snippet for you all to enjoy. I hope you find the code interesting. It should be possible to cut out the parts you need and put them in your projects. I decided not to use broadcasters to keep things simple, but I did have some difficulty linking the X and Y knobs to processors in the module tree because of this. Let me know what you all think.
      Fun with Circular XY Pads2.png

      // An Assortment of Square and Circular XY Pads
      // By Jack Huppert
      //
      // Helpfull Reading
      // Analytical Methods for Squaring the Disc by Chamberlain Fong
      // 	https://arxiv.org/pdf/1509.06344
      // Elliptification of Rectangular Imagery By Chamberlain Fong
      // 	https://arxiv.org/pdf/1709.07875
      // Square/Disc mappings by Marc B. Reynolds
      // 	https://marc-b-reynolds.github.io/math/2017/01/08/SquareDisc.html 
      
      Content.makeFrontInterface(810, 250);
      
      // init X and Y knobs
      const knbX = Content.getComponent("knbX");
      const knbY = Content.getComponent("knbY");
      knbX.setControlCallback(onknbXYControl);
      knbY.setControlCallback(onknbXYControl);
      
      // button to enable updating all XY pads when one XY pad is changed
      const btnLink = Content.getComponent("btnLink");
      
      reg curRadius = 8;
      const XY_MARGIN = 5;
      const XY_INSET = 5;
      
      
      // init XY pads	
      const var pnlXY = [];
      for(i=0; i<5; i++){
      	pnlXY[i] = Content.getComponent("pnlXY"+i);
      	pnlXY[i].setControlCallback(onpnlXYControl);
      	pnlXY[i].setMouseCallback(pnlXYMouseCallback);
      	pnlXY[i].setPaintRoutine(paintpnlXY);
      	pnlXY[i].data.shape = i;
      	pnlXY[i].data.u = 0;
      	pnlXY[i].data.v = 0;
      	pnlXY[i].data.x = 0;
      	pnlXY[i].data.y = 0;
      }
      
      //just for fun knob to change the cursor size
      inline function onknbCursorSizeControl(component, value)
      {
      	curRadius = value;
      	for(i=0; i<5; i++){
      		pnlXY[i].repaint();
      	}
      };
      Content.getComponent("knbCursorSize").setControlCallback(onknbCursorSizeControl);
      
      //just for fun knob to change the aspect ratio
      inline function onknbAspectRatioControl(component, value)
      {
      	local h = Math.range(150*value,50,150);
      	local w = Math.range(150*(1/value),50,150);
      	for(i=0; i<5; i++){
      		pnlXY[i].set("height",h);
      		pnlXY[i].set("width",w);
      		pnlXY[i].repaint();
      	}
      };
      Content.getComponent("knbAspectRatio").setControlCallback(onknbAspectRatioControl);
      
      
      
      // Update knobs and repaint the panel on control
      inline function onpnlXYControl(component, value)
      {
      	local x = component.data.x;
      	local y = component.data.y;
      	knbX.setValue(x);
      	knbY.setValue(y);
      };
      
      
      
      // Mouse handling
      inline function pnlXYMouseCallback(event)
      {
      	if (!event.drag && !event.clicked){
      		return;
      	}
      
      	// get the mouse position in the right coordnate system	
      	local b = this.getLocalBounds(0);
      	local m = XY_MARGIN+XY_INSET+curRadius;
      	this.data.u = (event.x-m)/(b[2]-2*m);
      	this.data.v = (b[3]-event.y-m)/(b[3]-2*m);
      	
      	// clamp u and v to the bounds
      	if(this.data.shape<=0||this.data.shape>4){//bounds = square
      		this.data.u = Math.range(this.data.u,0,1);
      		this.data.v = Math.range(this.data.v,0,1);
      		// square needs no further calculations so just return
      		this.data.x = this.data.u;
      		this.data.y = this.data.v;
      		if(btnLink.getValue()){ //
      			squareToCircle(this.data.x,this.data.y);
      		}else{
      			this.changed();
      		}
      		return;
      	}// else bounds = circle
      	
      	local uN = this.data.u-.5; //uN is -.5 to .5 if within the circle
      	local vN = this.data.v-.5; //vN is -.5 to .5 if within the circle
      	local dist = Math.sqrt(uN*uN + vN*vN); 
      	if(dist>.5){ 
      		this.data.u = uN *.5 / dist + .5;
      		this.data.v = vN *.5 / dist + .5;
      		dist=.5;	
      	}//dist is now 0 to .5
      	
      	// now convert (u,v) --> (x,y) depending on the transformation
      	if(this.data.shape==1){ // radial stretching (2017 Marc B. Reynolds)
      		//[x,y] = sqrt(u^2 +v^2)/max(|u|,|v|) * [u,v]
      		//we can cheat and use uN, vN, and dist again from above.
      		this.data.x = (uN * dist/Math.max(Math.abs(uN),Math.abs(vN)+.00000001))+.5;
      		this.data.y = (vN * dist/Math.max(Math.abs(uN),Math.abs(vN)+.00000001))+.5;
      		
      	}else if(this.data.shape==2){ // elliptic grid (2005 Philip Nowell)
      		//x = .5*(sqrt(|2+u^2-v^2+sqrt(8)u|)-sqrt(|2+u^2-v^2-sqrt(8)u|))
      		//y = .5*(sqrt(|2-u^2+v^2+sqrt(8)v|)-sqrt(|2-u^2+v^2-sqrt(8)v|))
      		uN = this.data.u*2-1; //uN is now -1 to 1
      		vN = this.data.v*2-1; //vN is now -1 to 1
      		
      		local SQRT8 = Math.sqrt(8);
      		local temp1 = Math.abs(2 + (uN+SQRT8)*uN - vN*vN);
      		local temp2 = Math.abs(2 + (uN-SQRT8)*uN - vN*vN);
      		this.data.x = .25*(Math.sqrt(temp1) - Math.sqrt(temp2))+.5;
      		temp1 = Math.abs(2 - uN*uN + (vN+SQRT8)*vN);
      		temp2 = Math.abs(2 - uN*uN + (vN-SQRT8)*vN);
      		this.data.y = .25*(Math.sqrt(temp1) - Math.sqrt(temp2))+.5;
      		
      	}else if(this.data.shape==3){ //FG-Squircle (2014 Chamberlain Fong)
      		//x = sgn(uv)/(v*sqrt(2)*sqrt(u^2+v^2-sqrt((u^2+v^2)(u^2+v^2-4u^2v^2)))
      		//y = sgn(uv)/(u*sqrt(2)*sqrt(u^2+v^2-sqrt((u^2+v^2)(u^2+v^2-4u^2v^2)))
      		uN = this.data.u*2-1; //uN is now -1 to 1
      		vN = this.data.v*2-1; //vN is now -1 to 1
      		
      		local temp1 = uN*uN + vN*vN;
      		local temp2 = Math.sqrt(temp1*(temp1 - 4*uN*uN*vN*vN));
      		temp2 = Math.sign(uN*vN) * Math.sqrt(temp1 - temp2)/Math.sqrt(2);
      		this.data.x = vN==0 ? this.data.u : .5*temp2/vN + .5;
      		this.data.y = uN==0 ? this.data.v : .5*temp2/uN + .5;
      		
      	}else if(this.data.shape==4){ //Concentric (1997 Peter Shirley and Kenneth Chiu)
      		//x = u^2>v^2 ? sgn(u)sqrt(u^2+v^2) : 4/PI*sqrt(u^2+v^2)atan(u/|v|)
      		//y = u^2>v^2 ? 4/PI*sqrt(u^2+v^2)atan(v/|u|) : sgn(v)sqrt(u^2+v^2)
      		uN = this.data.u*2-1; //uN is now -1 to 1
      		vN = this.data.v*2-1; //vN is now -1 to 1
      		
      		local temp = Math.sqrt(uN*uN + vN*vN);
      		if(uN*uN>vN*vN){
      			this.data.x = .5*temp*Math.sign(uN) + .5;
      			this.data.y = 2/Math.PI*temp*Math.atan(vN/(Math.abs(uN)+.00000001)) + .5;
      		}else{
      			this.data.x = 2/Math.PI*temp*Math.atan(uN/(Math.abs(vN)+.00000001)) + .5;
      			this.data.y = .5*temp*Math.sign(vN) + .5;
      		}
      	}
      	
      	if(btnLink.getValue()){
      		squareToCircle(this.data.x,this.data.y);
      	}else{
      		this.changed();
      	}	
      	return;
      }		
      
      // on paint function for all XY pads
      inline function paintpnlXY(g)
      {	
      	g.fillAll(this.get("bgColour"));
      	
      	// Calculate and store the cursor's XY position 
      	local b = this.getLocalBounds(XY_MARGIN);
      	local u = this.data.u * (b[2]-2*(curRadius+XY_INSET)) + XY_MARGIN + XY_INSET;
      	local v = (1-this.data.v) * (b[3]-2*(curRadius+XY_INSET)) + XY_MARGIN + XY_INSET;
      
      	// draw the xy area outline
      	g.setColour(this.get("itemColour"));
      	local bs = this.get("borderSize");
      	if(this.data.shape==0){
      		g.drawRect(b, bs);
      	}else{
      		b = this.getLocalBounds(XY_MARGIN+bs/2);
      		g.drawEllipse(b, bs);
      	}
      	
      	// draw the XY pad cursor
      	g.setColour(this.get("itemColour2"));
      	g.fillEllipse([u,v,curRadius*2,curRadius*2]);
      }
      
      // update all the XY pads when the knobs are changed
      inline function onknbXYControl(component, value)
      {
      	local x = knbX.getValue();
      	local y = knbY.getValue();
      
      	squareToCircle(x,y);
      }
      
      // helper function to convert (x,y) --> (u,v) for all XY Panels
      inline function squareToCircle(x,y){
      	//square
      	pnlXY[0].data.u = x;
      	pnlXY[0].data.v = y;
      	
      	//radial stretching inverse  (2017 Marc B. Reynolds)
      	local xN = (x*2-1); //xN is -1 to 1
      	local yN = (y*2-1); //yN is -1 to 1
      	local temp = Math.max(Math.abs(xN),Math.abs(yN));
      	local dist = Math.sqrt(xN*xN + yN*yN +.00000001); //dist is (0,sqrt(2)]
      	pnlXY[1].data.u = .5*xN*temp/dist +.5;
      	pnlXY[1].data.v = .5*yN*temp/dist +.5;
      	
      	//elliptic grid inverse  (2005 Philip Nowell)
      	//u = x*sqrt(1-.5*y^2)
      	//v = y*sqrt(1-.5*x^2)
      	//use xN and yN from above
      	pnlXY[2].data.u = .5*(xN * Math.sqrt(1-yN*yN*.5))+.5;
      	pnlXY[2].data.v = .5*(yN * Math.sqrt(1-xN*xN*.5))+.5;
      	
      	//FG-Squircle (2014 Chamberlain Fong)
      	//u = x*sqrt(x^2+y^2-x^2*y^2)/sqrt(x^2+y^2)
      	//v = y*sqrt(x^2+y^2-x^2*y^2)/sqrt(x^2+y^2)
      	//use xN, yN, and dist from above
      	temp = Math.sqrt(xN*xN + yN*yN - xN*xN*yN*yN)/dist;
      	pnlXY[3].data.u = .5*xN*temp + .5;
      	pnlXY[3].data.v = .5*yN*temp + .5;
      	
      	//Concentric (1997 Peter Shirley and Kenneth Chiu)
      	//u = |x|>=|y| ? x*cos(PI/4*y/x) : y*sin(PI/4*x/y)
      	//v = |x|>=|y| ? x*sin(PI/4*y/x) : y*cos(PI/4*x/y)
      	//use xN and yN from above
      	temp = Math.PI/4;
      	if(Math.abs(xN)>=Math.abs(yN)){
      		pnlXY[4].data.u = .5*xN*Math.cos(temp*yN/xN) + .5;
      		pnlXY[4].data.v = .5*xN*Math.sin(temp*yN/xN) + .5;
      	}else{
      		pnlXY[4].data.u = .5*yN*Math.sin(temp*xN/yN) + .5;
      		pnlXY[4].data.v = .5*yN*Math.cos(temp*xN/yN) + .5;
      	}
      	
      	//set x and y as well
      	for(i=0; i<5; i++){
      		pnlXY[i].data.x = x;
      		pnlXY[i].data.y = y;
      		pnlXY[i].changed();
      	}
      }
      
      HiseSnippet 3686.3oc2ZszbabbDdgjfKQ32U4bMdBqTN6h2.DTjxzTlRTR1LVDFVT1EYoh10hcG.rQK1EdeQrQjw9fSk+F4d9Cji9OPNlS4RtjS4R9G3z8L6iYwtfuRbpJ1UhM2Y5tmt+5tmo6Ay.GaMpqqsiToJOKbFUpzqU9fPKuI6NQ0vRZuGhCrqgiluopygGI8fvYpttTcoRkt4GgTTZkaIw9m+0G9.USUKMZ5PRRegsgF8IFSM7RGcvNehgo4iU0oOyXp.081YOMaqcsMs8As4lkaKMSU6Epio8UQxtQYoOV0chTopk06zqynM0Tuylc50USq6laz8tanQUGMhdmNquQuMG0ajpV6tRkdkGoa3Y6bfmpG0Upzsdfsd3ASrOwhu.eggqwPSJ9QGoCfUlO7isM0QSDGUZ2IFl5ChgIWIPJCRAsaxAs2o79F5FIimBduEaBRJGh.XoajU8tYF0qin50VP8JPkJInR2hqRuc4CzbLl4kNCpOuZ48r7nN.7PynJbZktwe5cK2pE49Vj6ir3MkZ4QrGQN3q8UcnDUKcRbv.4viHCT0cq.z+fPxuF7UjO1e1LpiGLDN5GSMmMx2zj7Tpptg03JLIqZF5YnoZR1m5MwV2kLx1gKefDh2DJ4gFtZjggD.EmNj5XBXI4w1b9WYhm2L22uUKUm4FAMscF2Zl9nVcVu8ca19Nq0qGRziLMAiwXDrLdF1VnA7Tplmp0Xlhu2THnxID05qxRrAtDar4FqiDwAjVLUcp5rYft6h579pNZjGzDVuPKHJxMi.mBS1XXCmn4ZN1vah+vlF1vLdSZ0scmMZ0tSq1a1hKdT5Mm3M0jToxt1feyxq4T0WPerC7QheTdyNsqS5tdakspfKmgkgG4Plu5HxKrrG5VAxqb8f+d3gjsIwRZL0aW6oyrsfOjWEmbUPBIjdz4Q5QHoHKMcwor7brM2U0zbHDEHaagybTzvbBO5RQHp9C887.elmMgZoBQ+D+Y5faDhM.1vftYPPG4jITvuZQiFfX3Rzl.NXpdjELzy5IFVuXoFQz7ncTwgNln467THJ02E3XyXX3vi9p8u+S+n85CCttvf60+fG8L9XBPNW0VIhr.HRalk4gHN97i2pBDlKarc6sHFev5v+pVMkWVYEFAO233kplLBVslAnlIDWLTxlMEJyP8919tzDZYyjYnEoe.jO38Tae.1oxyvOXylgLvon1zch5LJn7F4lwGFsctQCJbz4ENZHezyPD923CHJtQwHeKVLMFevc3rsL.uGrcEw032RqXXYBpMRoFO6Gix1kQvAv7QPjrVLHWGbUl9TkJf+PLJfMJnUE53R0UGJCfjQv4rJmsUkklzjpCqprzzgbJJOs3h..U2YvNbDGbCuhQf6yn3oHAmKDXZiaNOA.f8gMkZ5fKgLr+ZUFI0Wuc8NrsZhH7j7DJ2oEWbBDeAfHfFxqNgZLdh2p0mfLrvbmXn6MY05mjcpKO1KX8mC3mGiPzmkh+43tPT99or8ViVaF5OS0hZBvLQiyUAd.wzyyC3wbgjoiROR.6v7SFBSFuQ7WfxRdtBeniRGJDF5rXKgk4SfPGcS7P4EU076NHSCfkioiFiHx+B1mM0cTGSdu2iD8olog1Kn5L2pC0y2wh4SprBrhf2fASSYq7LaWC1JAm4hi5fdcvrrczsPH1Mz0iNckXadHXydSLbQe5SvQdfsuktqrPL3TfjjspqEu+bsjjYfPlDR1XhaQMm2XpRK4gOu6wM5VcpRFxvcpfoV63FbZCincsDZYlllo5zYDeVDQ.lShVzPlFhnkbp.YaU9Aa29zSWXr60S4ksZw4AVTW1Q+.JlUkExwDlnNjfwRIxp3ERbPBwfdyWEhEkBKpkM39c.M2g.vIVcG5ebIt1D19Nb+YlUYdrWgqGYUgvLSFfSBPQzItnejGUpn7RBTo3JqrBWadlMVaoonNOutfTY59YTSWJFjwWunC8k4ykI1CrRjVRBxpwjdkjHK+9YMhFMgslZ0BFFpl.9.cmv+Fh4OAJTKJZMVHbQDjUDAQhH3JHBcC.gibYtesimre+pfJTCjc0f9JaQXwQHU2q45.hkKx.HtJrFs3RpFrd4CHBJjF7isg+bEFZwlx.iFNgzlq3QA43HvNaAPo8DY+5AJjFMtGQdd8PEhNcF0BqtG29CsNOHtyE1teJKHpnjfs2tCyyCmVoa.HfqG3zzlfxPFqANWQzJrX1mCq2wrDDDj9xtjZAeYWEnz44xm5eZ8SCNUgTk7bP+NlQ+I.RqBaIOgp5wxOwMe76Ca4B+e7alAqNFq8eji8Th5P6.Zybg4xH.yHtEyIgKH6OTG5ByoTO4CvcUqYa9+zQA960ymWHG7elzpvy.HEAqc4vJk29iFYrigNBosWmL.ZYzXFou8Ivrb7DsslqWUlgmm1sF.oM.DsF66MU7OUowBS0HcJtHByJhF.c0DDQPpHhmpQ5TnHVLErZ2FcRyAw3tFcvPwN.sKlqESaPAzB+Od10Ae1Se1lYRu1jsUAeV3blYchmEwbHnB820Xrof4gMhyCyvT2BXpQwLkMXpYW.tRUFlB.oSjrC0MM3IuF1fDuCADhDqowKVdcKC4MVf7LglWUc67BEWiEJ93OpAzIKa6NVpcubMbmFJ5N1R1O.NiMnJas5pTMNSOMvI9Kkjg6A+ANfPDYhj7u9R5G8.yXGalc6WRPVp6nJ++.NkdUYbVkGnk246Zfn.aRX+lEDCvO2U1JchtEDsFze6saS9PQff79XFOiaz.yebSHynVju.Q97S467hg5whgfZl0fBvbf8yj6b26tAY.0CJT4fIFNlzP1F4eB0xh5MABtL7SCn.248.+InFr.BEwX.EPc50ZvdYBLTf0FHrEdRRRvTpTVB8AsfSeP4gqRP1U4+UARmW8C7huXCdO9PoUOktsD20TULzQIwIsf2sKOpAPiTd3PQ+VYNKS73qDgsPAbIpvRkpunTCVhTWbqrb1Sff8bF1YxJUVVQoUtJEjlXN4JG8LXEhqF8Lvgg8dg8Ww5ZLocKrmdgK1Je6XI29hLrY4KAYNt4HCSy6aZJG2Vj7pCGyu27UUR5LY2nJ442Zqqmsi3Uk7qbYqXbqXWTyVIcWk1zke13ZXSl3NojSZ7JoWLlmJ81zpkbIZIhi0uUmFBQ+JbQt1UWjL6G5O8DlAOG1jvgpRr88PnEAPV++HdI.gFP.iHHFAHtBHBfyPSpznqvYqhqssMK.ZL1e7I3sNKOrNHkLgJWHJWanaK99wb4vtPaWpfnhbxIFYz0fxctWrI1kai7PoXoikNWOAnq1U7uOVI5l33WGKkEyltvQWHKNPzMj.QawWHagWG0k9xPXWtQZ5Yl6BgcKGhyUYwLWrGkXMeB0bF0IUOvaPKtqFVuLrtZX82HjUN.uam74kErNuDcIwsuyuip1B2F57sVbTLlOLJeMeuPFnpAGMt7lhh.I7TC443gEJ3oEy4MeFeRQDZwHJLgnvhHR7njL8kLWrujv9B4G45dcd+pywrwv9Ug0PXuZbUiawTtc8nZNNNFS5HfTvt2fXPsgyAudyrzEvoKLOcHZlsEHQjrfdgfCiQ2C+r8NMPoxN6FN3EcPBiOOZbrSRvJwMVAiLs4wXkraViA.kL0f0oACcfNxiqkNKaQ1FfzKvFCbEXC0kKUM1YLQvJpAVXC3+xrzVhitncewDyAi5.RHzVsHljqBkrwHMHbyh8kBySlfHqUXTQ7A4YoIaDQLMnFd0KgjiWmN+z6s8ogmBE+Muplsq7f8Z0qZXq4X4d.9XXwGYdqvDXKCOITjvShTh4Y4gRhvFxB+7Fwbx6scljxzaTuWNXiQHt3rxhB6C6RjVOTVlBxxDZCEvTxgYEthgKx779vVNWvJFtnZlkony7fC1fyEX3EQEN2AxguvedgjhLmuUtgCi1DNc3LEwU4Lgys5a6Q+TKY1ITvgJjEmZznBmK5jNSpSgSiOCBmyiQYKeLgV77QjPoR2J66Gn7xe+.hOuAM9ORh.g1V6YY38oynVK6QOHE8KqHAqRjVAj5wdoAuQzKM3Are4VICcoRqTNpvZIlJK9JQjVF6GXZ.0VwX+UJim5mg2uc9e3eb448nL798+ke1e6Rw6aUN6OBz0S6eyxY9c7VTHjcj978dHD5guaiHXEfZ7gSXfdwROjFXnQ4uhiUJ+Pp6K7rmAhM4WzRpzqxW7WO9Mdf0nvV6aWlEF2VZN3nJUAVtvzU9WtC6mQKYfue3N7eyMwQfxdrOI9m9wEsFnUCR5.oEQhOMndcuau6dmM5d20ElnaxLs6rd6tRoUMmpK2dm3dVfwdke3G9g2gM7UvF6f1Xj31gtyOYsytB14ez6mt14Zh14u6mt1YOA6bv28+u1Y4r14STGlXmr+VL+TpmncpuiGctGRH+cNckDqX5v2NpHw9ZkOHoKpqjnEi.2wuHQWobzaKS6JIXQW9NeSQB9MKmTGO9F0tRRecwDmuqXDIsD3hD84dB9x7hFQB+MJydnUQOGvyS74Ogetn3Rk82ONIB4PxmXYO7pH0iVlWTPpGkWp29xWUvRxeSj+qWVj5o7WI6696+me1e9m+W+PnwZwrroF55lzAQWD2BkZjnbqboK1HU3+8uIqtsrUhriqGcFO6ub4NMaGqwwJRFMtWZHU5hJk+4m9Vk22VGu+wruFV7MCGMApDhOAU7AMZAJWn3Z+esmH6kUEe6xCLfsNJVGuQA5HTE2OF5XzCK90K+nQifPoTE7Vke7g+37Jhk3u3uwPSXNFX8i88md.b.fFEVcK7VvvZJuAdJ.+6132HBb.0Rm8AbNwODMYG76RQS1IdRoopZN1eUz6jBe5x2lMBnSVrm48Jk2G+lzYwxlkfvRciuRSKqnxwX2qKiqccYr20kw0utLdmqKiabcYbyKlQ7gteeeOa9C+.HX+AOh0lSoROh8RdYQqR+aPONMfL
      
      posted in Scripting
      hujackusH
      hujackus
    • RE: Circular XY pad

      @mmprod said in Circular XY pad:

      Just tested it, and it works perfectly! Thanks so much. I really appreciate the extra resources too—I still need to wrap my head around the math.

      I've spent the day coding a more polished version of the XY pad for each of the different transformations. I downloaded the destruqtor plugin and determined that it uses the an elliptic transformation, so I'm excited to see how that looks.
      elliptical.png

      posted in Scripting
      hujackusH
      hujackus
    • RE: Circular XY pad

      @hujackus said in Circular XY pad:

      It's the only transformation that I could think of that I knew how to code.

      Is there any interest in trying a different transformation? There are others out there that have different pros and cons.
      Some equations on stack overflow
      Schwarz-Christoffel transformation
      squircular.blogspot.com<- I think this is the transformation I wrote from scratch. Not sure.
      Square/Disc mappings Includes an interactive demo!

      posted in Scripting
      hujackusH
      hujackus
    • RE: Circular XY pad

      @mmprod said in Circular XY pad:

      Conceptually, how is the distance and angle used to calculate the x and y knob values?

      It's the only transformation that I could think of that I knew how to code. Here's a picture comparing a square XY pad to the circular one I made.
      Circular XY Pad.png

      Basically, I calculate the angle the XY cursor pad makes with the center of the circle relative to the x-axis. Then I calculate the distance between that point from the center. The tricky part is that I multiply this distance by a scaling factor so that every point on the boundary of the circle corresponds to a point on the boundary on the square. Doing it this way allows a one-to-one mapping from XY pad to the knobs and vise versa. The angle relative to the center is also preserved with this transformation.

      posted in Scripting
      hujackusH
      hujackus
    • RE: Circular XY pad

      @mmprod I had some fun working on your Circular XY pad (for a few hours🤣). The solution to your problem is that you need to define a transformation from Knobspace (x,y) to Circlespace (angle, distance) and back. The pixel coordinates of the XY cursor can't be transformed into the knob values in a linear way so I used some trigonometry to make it work.

      HiseSnippet 2356.3oc4Y80TiibDWFv2sVIWt6pJOe0D+RjwFijMdWtkkk+SBUB6Qsr2dPQn1LHM1dJj03SRFrtb7X9NkGy2gT4o7ddNeC1z8LRVi.afPkKuDphBOS+ueS28zc6giBEtrnHQnQIy2kLjYT5mW93jf396zmxCLNXWiR+rx646yGFwN4TisSFRihXdFkJM+uAYnTkELj+7u1XapOMvkkukgw6EbW1umOfGmu6Qa963996S8XuiOPi6U17.WQvNBewH.LyW11XH08RZO1anHayU132Ri5aTZwxdNq3zcUW5yW0YkVttsV8Es95W3xnc6xdtSmWrxpcWoK00tkQoOYOOdrH73XZLKxnzBaK7RNtu35.kAdOOhegOCW3XbLXY016K78viHtqwN849dGk4khL.sbTtOadkO6WV9PtGex949tuPRfjKgtCrzbEg27EfmiN7r0f2TfTIMHsfBReY4icC4CiyonhkGDDyBA2Cq.TT7ZL2+7yKui.3HHt4.5kr8CgESjvpiscCRaa6ZqYZt7xjKCt3jDSHnEEq9LYcxYmulYWQHwhCKrWivIuhzB9S850L+SlUjrcF+bfXlc5wh2QLXnH.VXUUxPURcBGLxD1aFgLEDGJ72g56eAjXXIBjTS2F39FyTrbEMjbxoe3sas6Ae6wfkbZYq.7NgLvSCzHCodMHz.Oh6nPv2nI33jinw80vmqTHbSKvH5LtEPAOxcZzoQq113uvoWoflTOuzqMVJNqsFAfv3DBEEaHviNdU3X1lURVWom43zoA9aKvv1mWaM77oThT22V0ofMUQfSeawn.uHKmlxvYN6CC7O4zVyL.oHWEjQ8ooGZTzxiMn2mGviIw8YfeumOS5883fQiEjHw.VbedPuIZ0iFSapXDxiZ1YsJEnHEDhr1XjEU9aYCg6bJ8OjFv7Ih.hqx9l7.ed.izcTfaLG1+V3yxM630.7.9iXxTUegK0mLF8YYjU1drJPR3QDaD7.Hx3N4tbmH4NoH2lUFH7hNyVlXuUbbH+hQwLK3103kcv6WjTNbtKGIJNLytcnTx6QbakIMXx.QLIZTHiv6RRDiHWSAuiBADHGIGKJs3nokjbs3wFxfrDzYhd1KCDWP.fw.qmeNCU9dLO8FUn9PwnHFoODhAGeOsLEIgI4IYADK1Ufdjdc.spUM8Bo8H+3ORTqb84tWx7pYVAXpBlmFRu9DvcqHOdoIW3WKm9o.8I6ujhSU7nKbIBBJQ7dAni.q0AKoignzPAlGMZHnlTMklrcHdsd.OvB7NMjKh99vXKDGKJAScoMwOeZsZYvXRNrztpUfUbgaePYUhKj3b40bva0MTL.xpPLzDjk2Up4e0510vSbkL8HMLjXEfjOcYjmZfkkL+J6MHsaBcG670sddmWZKAwML+HVAUfB9ZahNuK2h7RxR5qkhp7AvMynhWHk+EOPHI73PUWbHWvhulwBHsO5.Pk3U7kvOUTKo9S7O2mNrWRlehxt7xvU0HgOq4vPLSCOr0q1nZcYPtNo5RultN10PBL4wVK10Zha6hHK4GbEQVJVmDmPFaeGFifvsFiYZS920WG8g.Fseobikk6hmH5UBNVb6JtGbbRH+.KTjJc6ToaOUoa+.R2ROMTtQCoXpdKYNR7lZfHb.0m+CLUQVbvrLWIQUESU.VVhBaIoKAMBqZ.UqulADnjnueDxAz6RVZsPvbbFjx8oKJQ1hM6.AjNp7daxqVGRte05pPZt3IYhm6omk3ISD+1oCjpiWuZccLUuZRgcRH0VqhV1rKTapGyyRt6Ml2f0SyqRcDVN6shQwPWi7hT8fBT.2XeVpu6HebTBzGFAivwjNcUy0ecjbBCQDW1rwTldgtIc.tjVa4yZct79FxWRA9RJxW6b9nE3SceTQIr.E4kLSErgJpWKwY1PHvIDaLZVompKNN5skTVnmuUUdLafZypxz+dXM4qKNUCLOnrWDndPERsisBUsY6l1N1iLBBu8HghXIETUxOyrVBzvYSpQ2XxmNu1cPsZrsrI1dPL2RBZjutv22PNHkRzF41CKYe2PQCHKIusws7+MJvbiBTQPKSkj8.OX2CHoSX3yBiRGwBaqiCMZVQ90rPTuG7EWbAruSeQ3nHmp0ZLShvgx7bUO1KXcw7NXHNP4vEbOzCiNhFjg9LJzQINLABFhKQBzXxr5BWaJyGoOZ8CMdzjwP5kM.AF6xGHZx.F5zMqnONGplwKJmlqv9n3Io6aVQwUKaYigzgvBw6wXQObuIyznjSmyjYvYFPehsogtziyZQe2NzIKOV1ad7zZLOoublbIOldx2TzA8zaHmcvKzVQNPy3Eg5mf6KQ9cJdvlJ4pYq6q8opp9Z57u880WdB+SYreUKP5XYKvsjs.2tl5zCkjciGkZ.Dfp.lKSFFsxB70TEWJ1FoJJibLh6XSXDiF+gXfj5bVWtpdpgQckJgdekaL0tP8FQL6aBrjWc.JjaSpa2oRKu9wTIiufR38InUvnAWvB0u3hLZTZghO8P4Y+zC5uLhq5qDpwnH3.3q08Mv2RXVuWhQ52izvnzbonBXMV9HE+hzGo3XeXVmPCtmQomUVVuv1PhX82Wx3wKsSAo+i+ku5uugw2dvtP3DerjT.AfbHKLlim+R6xth6xTOcRkx6xhtLVLDrzju4K3xdXLOdBd2bzlI4f+caZ7ehhbloh7JnnJJE8YYO0CNbVpdT4iZ5w305540adM2Kte9FAa1mw60OVeGnAg35r1DfS5yKukuOIei7dsfTehgwG+HJmVGX41ez3ip286NOQ0WT9PgGNGUwWLCeWwTBPtbgmoBeJp.XtpD87h+q8LZOVH9kkOhG61e5XbtofQL0+m.Ll93ieVY0LB4.bgx6exOQuz3bZ1+SU1+YkUylHMckzENEr+aAypGx9Nsju+5W8m+GarOi4gIUo6sY61+sM1k4SKFnm+QeJbtemnZ19dPejPNbEo7aFM3XHg0kA9v.3RDVQrzbXsK0ZabMBhiYAdxEeD9IknCttTJQmLhFORGUqY4njUs9+AG0+Krw.pan3CouGHlG+L4Nv4NP9eWnR4Cw0Dma21wvX.2i+AW2hp5NB15oJX6mpfq7TErySUvm+TE7EOUAW8gED++qr0nXw.UkXCiCOZOYi9Rk1KfBY4x6UF+a+In0rA
      
      Content.makeFrontInterface(500, 300);
      
      // knbXy
      const knbXy = [];
      for (i = 0; i < 2; i++)
      {
      	knbXy[i] = Content.getComponent("knbXy" + i);
      	knbXy[i].setControlCallback(onknbXyControl);
      }
      
      const var XY_RADIUS = 120;
      
      // Create XY pad, and cursor
      const var xyPath = Content.createPath();
      const var xyArea = [5,5,230,230];
      xyPath.addEllipse(xyArea); // xy area path
      
      const var cursor = Content.createPath();
      cursor.addEllipse([115,115,20,20]);// Cursor path
      const var cursorArea = cursor.getBounds(1.0);
      
      const var pnlXY2 = Content.getComponent("pnlXY2");
      pnlXY2.setControlCallback(onpnlXY2Control);
      
      // init the angle and dist to something;
      pnlXY2.data.angle = 0.5;	
      pnlXY2.data.dist = 100;
      
      
      // Repaint the panel on control
      inline function onpnlXY2Control(component, value)
      {
      	local x = component.data.x; // x is 0 to 100
      	local y = component.data.y; // y is 0 to 100
      	
      	mods[0].setAttribute(0, x/100); 
      	mods[1].setAttribute(0, y/100);
      
      	knbXy[0].setValue(x/100);  //not sure if you want 0 to 1 or 0 to 100
      	knbXy[1].setValue(y/100);  //depends on the knob mode
      
      	component.repaint();
      };
      
      // Mouse handling
      pnlXY2.setMouseCallback(function(event)
      {
      	if (event.drag || event.clicked)
      	{
      		var rawX = event.x-XY_RADIUS;
      		var rawY = XY_RADIUS-event.y; // flip y sign to make y axis point up
      		
      		var dist = Math.min(100,Math.sqrt(rawX*rawX + rawY*rawY));
      		var angle = 0; // angle is counter clockwise from x axis.
      		if(rawX!=0){
      			angle = Math.atan(rawY/rawX) + (rawX<0? 3.14159265:0);
      		}else{
      			angle = rawY>0 ? 3.14159265/2 : -3.14159265/2;
      		}
      		
      		this.data.angle = angle; //this is a value between 3PI/2 and -PI/2	
      		this.data.dist = dist; //this is a value between 0-100
      		
      		//Console.print(rawX+","+rawY + "->a=" + angle);
      		
      		var dist2 = Math.abs(Math.cos(angle));
      		var dist3 = Math.abs(Math.sin(angle));
      		dist2 = dist2==0 ? 1000: dist/dist2; //avoid divide by zero
      		dist3 = dist3==0 ? 1000: dist/dist3; //avoid divide by zero
      		dist2 = Math.min(dist2,dist3); // this is the normalized distance
      		
      		// data.x and data.y are normalized as if it were a square xy panel
      		this.data.x = Math.cos(angle)*dist2*.5 + 50; // 0 <= x <=100
      		this.data.y = Math.sin(angle)*dist2*.5 + 50; // 0 <= y <=100
      		//Console.print( "x="+this.data.x +"y="+this.data.y );	
      		
      		this.changed();	
      	}
      });
      
      pnlXY2.setPaintRoutine(function(g)
      {	
      	// Calculate and store the cursor's XY position 
      	var x = this.data.x - cursorArea[2]/2;
      	var y = this.data.y - cursorArea[3]/2;
      	var a = this.data.angle;
      	var r = this.data.dist;
      	
      	// draw the xy area outline
      	g.setColour(this.get("itemColour"));
      	g.drawEllipse(xyArea, 3);
      
      	// set the location of the pad using rotation
      	g.rotate(-a, [XY_RADIUS,XY_RADIUS]);
      	
      	// draw the XY pad cursor
      	g.setColour(this.get("itemColour2"));
      
      	g.fillPath(cursor,[XY_RADIUS + r - cursorArea[2]/2,
      		XY_RADIUS-cursorArea[3]/2,cursorArea[2],cursorArea[3]]);
      });
      
      
      // MIDI Controllers
      const mods = [
      	Synth.getEffect("Chorus1"),
      	Synth.getEffect("Chorus2")
      ];
      
      // before understanding this, please try looking at pnlXY2.setMouseCallback()
      inline function onknbXyControl(component, value)
      {
      	local x = knbXy[0].getValue();
      	local y = knbXy[1].getValue();
      
      	pnlXY2.data.x = x*100;
      	pnlXY2.data.y = y*100;
      	
      	x = x*200-100; // x range is -100 to 100
      	y = y*200-100; // y range is -100 to 100
      	
      	local angle = 0; // angle is counter clockwise from x axis.
      	if(x!=0){
      		angle = Math.atan(y/x) + (x<0? 3.14159265:0);
      	}else{
      		angle = y>0 ? 3.14159265/2 : -3.14159265/2;
      	}
      	pnlXY2.data.angle = angle; //this is a value between 3PI/2 and -PI/2	
      
      	local dist2 = Math.sqrt(x*x + y*y);// this is the normalized distance
      	local distA = Math.abs(Math.sin(angle))*dist2;
      	local distB = Math.abs(Math.cos(angle))*dist2;
      	pnlXY2.data.dist = Math.max(distA,distB); //the actual distance from center (0 to 100)
      	
      	//Console.print("dist=" + pnlXY2.data.dist + ",\t" +distA +",\t"+distB);
      	
      	pnlXY2.changed();	
      }
      
      

      Feel free to ask for more details about how it works. I know the comments are not completely understandable.

      posted in Scripting
      hujackusH
      hujackus
    • RE: Issue with simply playing a file, and question about introspection

      @thrice801 said in Issue with simply playing a file, and question about introspection:

      it's saying player.loadFile function not found.

      Why is player local? Is this code within a callback or a helper function? My first thought was that it wasn't finding the AudioSampleProcessor at runtime, but that usually throws a different error like "Audio Loop Player1 was not found."

      But I think the main issue is that loadFile() is not a function of AudioSampleProcessor, it is a function of AudioFile. You might want to try AudioSampleProcessor.setFile()

      posted in Scripting
      hujackusH
      hujackus
    • RE: How to use Modulator.exists?

      @d-healey said in How to use Modulator.exists?:

      Did you try it? I get an error.

      That's very interesting. I spent so much time in the C++ i failed to consider if it even compiles in HISE. I assumed it did, but it doesn't in the onInit() callback. It will compile if you call exists() in any of the other callbacks, but will throw an error at runtime.

      Perhaps exists() is not supposed to be visible in the API and was accidentally added into the documentation?

      posted in Scripting
      hujackusH
      hujackus
    • RE: How to use Modulator.exists?

      @d-healey said in How to use Modulator.exists?:

      What I want is to know how to use Modulator.exists().

      So far I've been looking into this file: hi_scripting/scripting/api/ScriptingApiObjects.h

      • AudioSampleProcessor (class ScriptingAudioSampleProcessor)
      • ChildSynth (class ScriptingSynth)
      • Effect (class ScriptingEffect)
      • MidiProcessor (class ScriptingMidiProcessor)
      • Modulator (class ScriptingModulator)
      • TableProcessor (class ScriptingTableProcessor)
      • SlotFX (class ScriptingSlotFX)

      All the above script objects have the exists() function because they inherit it from class ConstScriptingObject (in ScriptingBaseObjects.h) In addition to shared functions, each of these classes have an internal reference ( WeakReference<Processor>) to the actual processor. Because this reference can be null or be deleted at anytime, the script object constantly has to verify that the reference is still there by calling checkValidObject() every time a method is called. (This function never returns false*, it only returns true or throws an error.)

      bool ConstScriptingObject::checkValidObject() const
      {
      	if (!objectExists())
      	{
      		reportScriptError(getObjectName().toString() + " " + getInstanceName() + " does not exist.");
      		RETURN_IF_NO_THROW(false)
      	}
      
      	if (objectDeleted())
      	{
      		reportScriptError(getObjectName().toString() + " " + getInstanceName() + " was deleted");
      		RETURN_IF_NO_THROW(false)
      	}
      
      	return true;
      }
      

      Basically exists() is defined to do exactly the same thing as checkValidObject(). It is literally defined that way.

      /** Checks if the Object exists and prints a error message on the console if not. */
      bool exists() { return checkValidObject(); };
      

      This leads me to believe that Modulator.exists() should only be used in a fail-fast check before calling Modulator API functions. However, all of the standard functions already call checkValidObject() making it basically useless to call exits() at all. Nonetheless, an example of how to use the function is...

      const modulator = Synth.getModulator("myDodgyModulator");
      // I suspect modulator's state is out of sync because reasons
      if(modulator.exists()){
          //call a few functions on modulator that might not already call checkValidObject
      }
      
      posted in Scripting
      hujackusH
      hujackus