CableBox component - for your modulator synth needs :)
-
As a quick distraction from pushing around bits for HLAC I created a CableBox which is a component with sources and destinations and the ability to create connections between them:
It's 100% Javascript (but you need the latest HISE version because I added the path drawing for it). This is the js file:
/** CableBox Component * by Christoph Hart * * A component with source & destination connections and the ability to create cables * by dragging. */ namespace CableBox { /** Adds a new CableBox. */ inline function create(name, x, y) { local widget = Content.addPanel(name, x, y); Content.setPropertiesFromJSON(name, { "width": 180, "height": 180, "allowCallbacks": "Clicks, Hover & Dragging", "saveInPreset": true }); widget.data.connections = []; widget.data.fadeOutAlpha = 1.0; widget.data.fadeOutCable = undefined; widget.setPaintRoutine(function(g) { g.fillAll(Colours.black); for(inputBox in this.data.inputBoxes) { g.setColour(inputBox == this.data.currentDragBox ? 0x44FFFFFF : 0x22FFFFFF); g.fillRoundedRectangle(inputBox, 6.0); g.setColour(inputBox == this.data.currentDragBox ? 0xFFFFFFFF : 0x88FFFFFF); g.drawRoundedRectangle(inputBox, 6.0, 1); } for(outputBox in this.data.outputBoxes) { g.setColour(0x22FFFFFF); g.fillRoundedRectangle(outputBox, 6.0); g.setColour(0x88FFFFFF); g.drawRoundedRectangle(outputBox, 6.0, 1); } if(this.data.currentDragPosition.length) { g.setColour(Colours.white); start = getCenter(this.data.currentDragBox); end = this.data.currentDragPosition; drawCable(g, start, end); } for(connection in this.data.connections) { g.setColour(0x88FFFFFF); drawCable(g, getCenter(this.data.inputBoxes[connection[0]]), getCenter(this.data.outputBoxes[connection[1]]) ); } if(this.data.fadeOutCable) { g.setColour(Colours.withAlpha(Colours.white, this.data.fadeOutAlpha)); g.drawPath(this.data.fadeOutCable, -1, 2.0); } }); widget.setMouseCallback(function(event) { if(event.clicked) { for(inputBox in this.data.inputBoxes) { if(contains([event.x, event.y], inputBox)) { this.data.currentDragBox = inputBox; this.repaint(); return; } } for(outputBox in this.data.outputBoxes) { if(contains([event.x, event.y], outputBox)) { var index = this.data.outputBoxes.indexOf(outputBox); for(connection in this.data.connections) { if(connection[1] == index) { this.data.currentDragBox = this.data.inputBoxes[connection[0]]; this.data.connections.remove(connection); this.repaint(); this.setValue(this.data.connections); this.changed(); return; } } } } return; } if(event.mouseUp) { for(outputBox in this.data.outputBoxes) { if(contains([event.x, event.y], outputBox)) { this.data.currentDragTarget = ouputBox; var start = this.data.inputBoxes.indexOf(this.data.currentDragBox); var end = this.data.outputBoxes.indexOf(outputBox); var connection = [start, end]; this.data.connections.insert(-1, connection); this.setValue(this.data.connections); this.changed(); } } if(this.data.currentDragBox) { this.data.fadeOutCable = CableBox.createCable(CableBox.getCenter(this.data.currentDragBox), [event.x, event.y]); this.data.currentDragBox = undefined; this.data.currentDragPosition = -1; this.data.fadeOutAlpha = 1.0; this.startTimer(30); } this.repaint(); return; } if(event.drag) { if(this.data.currentDragBox) { this.data.currentDragPosition = [event.x, event.y]; this.repaint(); } } }); widget.setTimerCallback(function() { this.data.fadeOutAlpha -= 0.2; if(this.data.fadeOutAlpha <= 0.0) { this.data.fadeOutCable = undefined; this.stopTimer(); } this.repaint(); }); return widget; }; const var INPUT = 1; const var OUTPUT = 0; /** Sets the amount of boxes for the given CableBox. */ inline function setNumBoxes(box, boxAmount, isInput) { local boxes = []; if(isInput) { box.data.numInputs = boxAmount; box.data.inputBoxes = boxes; } else { box.data.numOutputs = boxAmount; box.data.outputBoxes = boxes; } local heightPerBox = (box.getHeight()-20) / boxAmount; for(i = 0; i < boxAmount; i++) { local y = i * heightPerBox; boxes[i] = [(isInput ? 10 : box.getWidth() - 40), 10 + y, 15, 15]; } }; /** Call this function in the onControl callback to update the graphics. */ inline function updateCableBox(box) { box.data.connections = value; box.repaint(); } /** Helper function that checks if the given point is in the rectangle. */ inline function contains(point, area) { return point[0] > area[0] && point[0] < area[0] + area[2] && point[1] > area[1] && point[1] < area[1] + area[3]; } /** Returns the center point of the rectangle. */ inline function getCenter(area) { return [area[0] + 0.5*area[2], area[1] + 0.5*area[3]]; } /** creates a cable with the given points. */ inline function createCable(start, end) { local midY = Math.max(start[1], end[1]) + 30 + 150.0/(end[0]-start[0]); local midX = start[0] + (end[0] - start[0])/2; local p = Content.createPath(); p.startNewSubPath(start[0], start[1]); p.quadraticTo(midX, midY, end[0], end[1]); return p; } /** Draws the cable. */ inline function drawCable(g, start, end) { local p = createCable(start, end); g.drawPath(p, -1, 2.0); g.setColour(0x88FFFFFF); g.fillEllipse([start[0]-2, start[1]-2, 4, 4]); g.fillEllipse([end[0]-2, end[1]-2, 4, 4]); } };
The most convenient way to use it is to copy it in the
%APPDATA%/HISE/scripts
folder and include it viainclude("{GLOBAL_SCRIPT_FOLDER}CableBox.js");`
Example Patch
This is a simple example patch which uses the CableBox with the Global Modulator system to allow dynamic changing of modulation targets - however it's a sine wave so the effect of the filter won't be too drastic :)
HiseSnippet 3931.3oc6bs0baabEFzxHNhNp4Rcyzz1G1QSpGRaJJPcww1JtQxxR1pU2horb5nQSJH3RRLFDfA.TRLYz68s9Z+6zG6acl9Go+CZOmcWr6BRvKRIV1oIpNTD6dNm8remK6tGrp6GF3PihBBMxcyC50gZj68Lq1yOt05src8M15IF49El6XGESCI7ldbuN1QQz5F4xM0SwFxM80MX+7e9hGa6Y66PUMYXbXfqCca21twpV+Kq9mb871ztN8.21ZTuzpa4D3udfWPWPelxzxnisyqraR20FI6ZlFm3ROMxHmk4hKTN7UUp8sqUtb4usVucVXT+21FNcCCo9wGBrajyL2+E9Im4F0ciCBqFaGSAYZ93f58p1J3Te9PenajaMOJ9PEipfNwadKe.JZX6P0Hcy.u5HffTZrdKWu56m.qQFF4dm8Uf7TbP9Vl63V2U1tBr+.VGDEG5vctqkVkudJUtxvTYk5Ykk5kSS8tNW89PypNgtchU8f51GIZcHZGuSiq82+Ty4uycHqaCpxiCNirdP6NA9.5OS96LcsdfaTnaTbPmVjmYGhMhsuFwIgLxotwsHQfOfCkbaRcZTrqucrafOPiuO0A+ZDw1uNItEkXWy0yMtGINf3DRAfg3fibjXzpGZ2roqeyxhA5EQf+zCEOLMHvnXxI1gDmZjGI04xbIUXVmZyVhXA+q3Jj4mmbVIROFeRBinw61sM7MZTAmZkHKWRIjs1c+Wb.mwpzXhe210fnnfFDW+NciiPMd4IWZ68hClHwgR7ksn9zSfd6EzkXWuNYdRHscvI.ZoggkHtwjltmPiXzgfYitddD6vP6dbqfM7nNn65yHCGiFAgsIGcD.NUNtD4nJ.HI98BvugvxiAaHSvN19j5AjSaYGSjZ0o19wkI2Y9YxOSdeH7NBB0oxY6L4+tYxidQqUuNXpI9zSUHAiqoc88b8QM12g6avMYnrJwLTEAh.oL8zdAN1dv7odS.1.ib.DBCCNfK6a6S8zYYkYxSfePtRHCrIf+dGZXrKMZyvf1+wp6sqfGl3mEjbbqYeHox8sJwZnE0sYqX8V.bL3z0gOqAIzhfdlccOW3akHOK.QjaSdhvOcVNCQ1mP2xe+PJL7.4wgcoX6mqqg7YT451w1k0MROhbzwBxRQSCHg6dciWyqSKafnJksFAULzFnpqecZC.nquBNjZCKhKPVq3mGzEhOoERLDEZh.OG4mtY4FPl9077JvypGUtlGf.IyBl7POoBLeXLaAyCyMhqKIsRiXxTHTPpvfyEnhwG8HMFE46QPE66KHVmszRax9g7P3gEVf+PwURjHpmvTAls0eN.j19M8nRgWhbuxVJZuDi9lapM52+98O5PVpSG8nCgYBxOuerCL.YAdxlGA5MwHgTXCEJl3oUZQMj4kaiBYhm6GD4hdYk8n9MiaMzIVh61osbioR2MtrmNJFV3A7sA230o354EFlsKYpPgEaFhENQi5aLvoNKFpPyRD1.Vh.RYX1PU7aZinVbsbtpOLi1BjRIxZ1pBvNRMRGYc7wEKQ3h.GiLXTy4RmyJ.mj9f6yYeNnUUOQy3sivpQrDWosrkHCHOFUES6CtucbqgLxkHygKYI8oOuuzr8krEzrcB5FQSxkqR6Aqr4Gqk5ClqrlJ6fY5o0SMEm7TdIbfxC.5XHkaTgi3RFhf3eoGrhaBiEE7IYb5glX5QRlVIEsgzNXl8BEkMGRi6F5m7H2hl7qKRJnId1H4bvoCtaMWHkxYohH0Fpxrd2qgRqTdjIwMWvnN8wWn6JWdL4OaHkzpQ7nP+IHNbkLEjR8Jy2WmlBUreVFzZJ5.7kOz1qKsP1S79I2oEj+lVufNXpfy98QjtGpunbazyfoy14oibZiQZuny.QNWkdaYZ9NvNjuWxftx3m98uP2zjEZxxPK8RG2ZObQ0+JPi0eWwplWNr0P0ZQGmgVmsSFfav9eKfYJyxQ6B4MMfuTFoT3e5NBrIs8M6T6CdfN9ZgxFmf0+gSzLf+hToGQnc5sMOLZS16.vvbUVQetOc1qqI21tFti1SrNJgEVTtwrLiz3elYNgQDDhGfNUD3kwrj8bdPnM0LSojSq6cnVgt+yivPgAWYVaQ4gfpy8HhU4EVYzaTgS5mijZkBPFp2W+NAB6UPGt4ReGGhwMCii1LkakDmjEa8b7C3epxXvp4.5krRpl4EO.Z2RvAd15pTrpAXITfDs9wXoDpg4SHPNVV6XsA7G24t0qYQMbS8vGqwDHrmjnsv7c8cRb9fHNkJahAvsFoBbEHiip9cauEuDGORI7URSiJuJmHZD2ogAtTuHZ1xcOVFyQIXs7rCJY0bhej+8og7veDIvzKOi0bghysfUQx7oGDjY19.YlEhK4y05m3d26pgE7AoGtiMxcRMXR0E15f6wHpl.kv4NqXAm2TnJuDqRQghj4HKYAo0fttKoG76kw+iG3c9zBeJgCBFJwVxQYsEE.BqRqebXfGwQDtgkepam5X82XtNg1cZ45DMDmFNkIdVHZI8QjHe5RZbBt1xJIDjJDgaIjZ8yndcngpwJFq6jSKpyqhHtMzbr6D.h.7QSlTgIGQcXUXJYKDLFKQrg0TjpsH1j0ErwMxef0M9saeaUqetr06x+1BX+LSHmlJRNqnwYEImUjbt3wh4tXZ+blBvCncXqpIlfAMlnYmZwvrlWGozaqxKeGgtWRSojMu3wJMSna7UewB4wpMKu1h8YHhFYc83qbqcN5zoTZ6V+OCNI6.myqba6y3DdDVXRfV32EAEbQziuxxP164KfsZc7bbxrDqnKE0WAhJoKfGA0Pjij94WPlTlyUGsBKx0X1YNKJBzEg6c3qVuK8zpcqwHHQhhZDfppTxcJ+McsgkeiccNHn.pWkXST9jxRM45eAhNpnBF7CK6dpvw.gwg.zCqhEoQZbhNDShTMzNzcmzmul26vKYAu5Sa3441IhV3nDzYtET3C98kf+cblbHLrKjfMoolGsLSddNtYxmXwZa+J5lgvCx2tSg6YYUBbYXpc5ZTCNYgtmwWQhUmZs0Y2dy8RVjU03F6d3Fau29aL3xx6r2Sd4y1XisgdVXk7mm03HVgp+A5oqs0tCNR6u0Aq+rAGlM2Z6C134ZCB++oH3rrd2GmMKX2PTXYFHj4Ko.VtewAeiGSFwIuPiYxqoIdMB11tF0Kcc5YMUX1jNAE6AfjVd4hqje94IGgUjWx4w4Gck60kBqXZyFSOCqw9rfwCq9Nzhrh9VKwaPVQ+EVl2PCXLv2JIx2dm0qI0eVUGUc+VriJ2Sqo3ddLhebfWcAo1dtM8aCZJ1dHa.3cztqWrKFbBcXAdqho478MOUnF0+DpGLSGNzkhBA9Uw595.XJRFKJ1u.SCkGB843F26GA3YeSaEn1Nn9KaQodCGTSQQBnduEzA0TjLVPseAlFT2In9oXu+H.T6aZqk2B1.UlXI1ALiW79vpEKeOcHD6YrHmf8u6MEx3QaLQ.Cexnkw1M1oUl.BqGDQ9rGfgpOPGRX8MVLIQBu0CJhoi1BVtd39WyBV3cIwk6UQGW3cNVfQJi25QFwDJ8p0PvUWO1EhfWGR1YoOhcqcvC5sCua3jkrnBbOIyBG3an8KyUOJhj4dJdbIYEdIDRlCK2odDiKmfwMvbptPirvwYDCsfhwM1BxzFb7PMx8JG3uaPLcO+BEy+c4mN+4CzSiFY0k3PydXweFrWQUgFJaE3W4iR7yBynysgnQ7cPnNCMVVgXguAX7FvgQqxBHoP+ry.q0YRssftvnnj64SA7hH.dnXYqRptRx.l9kov0w9qfQavUc.souWfXluAD1G.NDE.meoSHd1+1E05pcJsrgsWDUzcdlpdNfnF4lJ88m5lS18mxgmMQiv.+s7ci2qCU9L2cHoEKCoafdSJyudqLydFjoZZzWfKCQ1NCib2PvJPZL6hbMSxE4BunKFtLYblAy1Xj6iMwbLGgWYG1U3wBu5NGykWVBgkAlIj7lI6BMQVpK72Dv96alZSWWRYjZOFWJY7NlrKv3kg0aXxxNco38cM4YWxf4AuJdefoLqj9sDDU7cjARotGd3YX8ifba52LyKvUGzJyqNXV2rwIUc+PNXks9dsLzWvU90s9JtHlyXtQiFPxFkxdcyM+pK6st7xoJuKWU9MlO0KnlsmB.40ajxu8k+NQ2DY+DEAC+R49u9g+R41eZzK70PMyaI60eCbKY+g2U+WNfUJ5JH3Ly606T6Ovc61zD1YDSOee7aJkb753lgzuoK02QqwasJ5srkxYa0+1puz9DJdyP4imh8soMgwQukCns6D.a8xQ2wrZ6ff3Vt9MS6CdqUWuaTbP6Doaj62atvRkS+yI6Aez3t3Wev5rmM9degoyzS8ZSru.hwRzDQ62xSTy0Xoo9sDM9FbMNuYxl1Y55sjOdQbieQD8.al1nb51B1LRXLxjpsmPcbg0qAISG0xRSMYNTid9Mszh.I0T6QTrzIKSmVq+fMEUxbW1QHzkAONLcPn6pOg1vFNs5g8uskWKnxkdCES8SyMTvuG1M4u0.HUOXTqx9an.zD37Td3ehK4tFZ24OagOyx4R8qak7WEinyJ3y4DcVIoS8o6ufOcuoYUXCHrSPylr+J1yDLQM4oTXqICDV9Ze6I64DCi9Ag19QcBhRI3pz1tGD3iftpQHdAy38bzQJc7gcXlcAKFBywL4opcb2PlGI+83mxCbpK0evQo2oulaxOI1O0afS5XMNz7FI5aU21c7naHNKqHyjHIor0wpvqEGa67J8M67bpG0V2y8SWcaviyNL8xQWn45EX+M4lPayu1jq5DLhj7V0oQElnjyLgJ3g1gt19pZ7wlB4MSJQ53NRp95pP7D9kmXGaOo6DccYMsLxcmQbRtGlda4uVLvWFf58MSUF3qPzpznPq92bzUEd8aEJEakpp3MSHS3Rtg0qN3Z9QAWYri4W6H1aa6iarmUdRCItoo78b7yIOFIR8AloeUN+b1iQm8HAuxJ8wT+eV5Cq2DGq5R9WGunPsej49Ad85zJv20QTIedwSTMKdwsi3fOFFCVQs+5+d0uT2p1e0G9xt1dJCO4S9j+4+XzG81ZxO58DWUqO1LU8gdcrmuJudSb+dlpWS7UXn0OFyb+gl88hv+4T2iN0sDv9ovV+99UBujCT7F9TiWE0M6pXLZa6DF70N7PBL036xZAl29r+eOmoM2AelTI40NiXSaHL5qcbvUSmCPmr4XgKLGKdg4XoKLGKeg43dWXN9rKLG2eDbf4rVqabPat+tgw+CXmLfLC
-
Is This Broken?
Hitting COmpile Will remove All The Paths :| -
@Natan on line 58 & 59 oninit cb, put an "var" in front of start & end
var start = getCenter(this.data.currentDragBox); var end = this.data.currentDragPosition;
-
@ulrik Thanks Ulrik, I Already did That,
But the issue is when You Hit Compile, All Connections Gets Disappeared :| -
@Natan Ok, then I don't why it's not saving the state
-
@Natan Is there a control in there that has saveInPreset enabled that holds the state?
-
@d-healey Hello Sir David, No Just the Code Posted above.
I Didn't add anything to The Snippet -
-
@Christoph-Hart any plans to add saveInPreset for this??
-
@hisefilo You can already do it with existing components, I use a sliderpack when I need to store a lot of related values.
-
@d-healey Thanks Master Jedi