Pitch and Mod wheel display
-
I've made this little pitch and mod-wheel snippet that I think some of you will find useful. It also has mouse callbacks set up. The only thing it's missing is moving the pitch slider with the mouse doesn't currently output data to pitch wheel modulators (Christoph, can you help with this?).
You can change the size and colour of the sliders using the panel's properties. bgColour sets the background colour, itemColour sets the slider fill, itemColour2 sets the line colour. The borderSize property is used to set the line thickness.
HiseSnippet 2136.3oc6Z01baabDFPRHiEcYqyLoS6zOcUSegrQhuHqj5LptVRTVtr0TRinjxKcx3dB3H4MBDGJvQon3QyzeG8+Q+d9Gz9Sn+DxW6mR28N.hChPzj9kF2LAefVXua28Y2a28tagOLR3xhiEQV1283qBYV1+.mtWEHGzZ.kGX0dWK663bXDKlIs14pPZbLyyx1dwmfiZu7RVpmu9Q6P8oAtrLRVVmJ3trmxGxkYTC25Ow882i5wNlOzX1arUaWQPKguXDfjEcZXERcOm1msOEm1BNVWvYWFaY2v49qWK57lm8kaWCe1oV5yS28y5ugO87K2qVs6+G6ridbK2QQQr.4o.6V1N1eC7X67XOtTD0URkLPlKsiv6ptCDWFnU8o7X9Y9L7klVcALoIumv2CMdjpUqAbeuCScdwVfrOLyUtn1U9dNc3d7wzybo2SM.IiCSWq8BSCdMewvqQQvy1.dKog265z0MhGJyFAw1ccZGHYQ8nvpoIrzy0ZgCtmS85GN5LetKYWwPvjJWpboVBfo.YsgzyY6EAuLVHU9vFMVk7AMZTcSbhvxbrjbAMhDF3eHW5Nf7PRJ28YxVhggh.3kJqjNgUptIod8mDQOiDpX3xALlOIjFv7ug.6H7ll3fgMD1PXx4DU4RfkAFjjbjXjjGvhKWp2n.WIWDnU8GiSWMkjYToe0xkdd4RD3Ih0m3Cz5x+RFfB4.dLBgJqblHxiEgjWAcB3b0+VudKpuq+HXgFlNiDJh4JkIEDuH5kJhnHImQgkABNBNMDt+5Xvn8GwHULcJJRUSk9nXFoCUNnVDMnOCkJ00ULBLvdhHknFv38GHIhdYppRpMTMuYcnHFrpLwUIy.0RYkpqUo.h0yHMj9EqTsJ42L12bJB2JUqt5XGW80WkTffyFNuGresdPAks88MT7Y80ER.UkL2zmT+xtnuU6873wg9zqRkVLFxfLaHOtjM7lRT+KuGoxMLExum7flez5UAsrCKviLJTO0mOloLXeDyUV4O2X0T2qokeI2SBQ9E4LpuNYsTV97T.cs9eX9vRdQv52kGVdP4jDfcqnpHMWHDSvxZEwvMA3DKCHyyl2e8L2e+ZX5wSwDvFSCR23OTQ0apgv0X993ranVvsjaOuwZyesf2BSvlLQYdSPdkhv+byD22dhVpWui.Ko5R88OCNeRwaOnlSqjoTgcAr4S1dDXpohTMWXCzyYdUmHKrdcRL8B8FB5ZT8hDCUuNTqdjyr4qrGOpjVSM7tPlsZU2HrKIJXxRESnbLVLfc4zE.IWsrLSB7x8qlMvyyW7EEMTsUhmSj.x1foOAJnk81mhAvaz.2mlf6ONxOc+wXV.tA4Eb4UlQkoOF.+lYQE4ed+wvwLnXHOHePoNmxvzud5dAkVNI71cDFvDqIu4KVvi43mOwRBVQ+3wQJCnwD2AnY6cqpWIf3TAjJ5atUoZVQrPrdXkBGLQOvf2tAb8sTl86yQd0yQpSt++Ojh7cyH5z6lfpM2YFJ9ZBn5LYIe7+sr2gdiX80VlPOEcfkDsjL875nvLupaNNyTDruPxNHnR0ROuzxkttzMGoWuhFBupUjv2mEoGEWa6.WlDt5t95WoCu+ngmgSh7vGRZt9CvE4Cyt2xD4XlNK8xZgRMMjYyB3Lao1Lit7rhQDgcRugXQ3KwMO2nC46lXKuSE6MRzT71UBT.c0ja6k520TQvm5CJpvYW73+5bK39f56NBAGXED3NgqQFHtDtc.oM9ClU7nBudQNcAVzjZR0EIvAE3YDizLEyY1sk8R462w6La86vUeIeiIJBZGvkGDxRde5MrwJoKAXuQRPHLUopyHkS6LBdQaKNHiRNo9TKkAj05puZKqSZuKT6LUPfLA8Dxhjbzbr2kcA2koa4xxN6xhOWJBsrWXbqIrru2Ln1uHSks25JyWTGiMivmtk9XzX6t5aaYAEmSG7u8M+ysxt.RFK+hDpGQ83ihMahWnHbT3AAGgBrEtmJ1JnAfiscbdZoWDBX9c1e+CNAYN6v3HUKq+yeGoB0dDWlVABT1OyQID3P2+AwEPL0uh.mzueedPeCArNJAr4cnDvs9aGjzURa6ErLbk+nayUdGGcjpoijOiNxDJ+6QaY3Ls9pm8cAmo0jMF7dNcRKHX1yRrmuIC.kix0bPrae34NtxrmvyQiLaLy8YcVg665nRaJFuKT.dgz22z3MosvkcdbudvEiy.6RN68Iur8.9kCJ+PMTtqSW7htXoZEP9wp2IeLd15mvBXQnScJM9+e85uw+G3JAseLbvz3PQbNA2kMjeLjmmKo5jX1dQr+5Q3hrI8VBZTgC80OZOvFKjmtT4nHUzx1Cw1jlK5Xw7KINy11T4SZLl+K3yIrz2BeNgW+YguQKZLGe8iELv6xo3sKeXnO6wAWv7gsqSpZrKqGcjubLUS.2QDHBGHB3tlAFGwjQ798YQllQg111RIEKvmR4815HlOiFmayCrMUzHvkwllaYwYysLaeHnBW59oNZ3RvDVxaU08GuBhg8YmtLYETkKXP8EhWnBxwTEfxVTaCq+QRjIyJJ4unfoL5NTHjCxWaiuURvzo4Ow3j6z7RuZ9ZY2vEeU2M7k7yPdmzO37giu+qBr+DMAhhBYr0LUH+WN4j+QAKjXh3jKjEuXoTp51dJgnNRu8uzY8Mpk+4hCfe5893e9QsTu+lY87a6SKnapP+NTn7FbnWGHnuKrKsKCPR.bpZbOP3r2Hqp2afuq2lNvqQ5GaOYvl361IC1Lcv+mnigT2Hwyb0IuXL3cTT.6NP8etfkc5fuSZldyNz2LDJh7LWWzYuVSKqh4X84li6O2brwbywGL2b7gyMG+14liGLENvJ1aORJFpKMYY8ew5mlHY
-
This is excellent and pretty useful. I've made a few changes and added the missing pieces (actually I needed to add support for sending pitch wheel messages in HISE via scripting, I've never used this before). These are the modifications:
-
added
Synth.sendController()
in the mouse event callback. The pitchwheel CC number is 129, this is stolen from another well known sampler from Native Instruments. -
deferred the MIDI callbacks using
Synth.deferCallbacks(true);
. The only thing that this script does is updating the GUI so there's no need to run those in the high priority audio thread. -
encapsulated the factory methods in a namespace. This is more convenient - I recommend this paradigm for all custom GUI elements. Actually I would even go further and extract the namespace into a separate .js file with the same name, but for the sake of a self-containing example, I'll skip that. If you do it like this, you just have to include the file and call one method
ModPitchWheel.makeModWheel("modWheelName")
. -
I changed all
reg
variable definitions tovar
. Now this might seem illogical considering the fact that I always recommend usingreg
instead of var in 99% of all cases, but funnily, this is the exact 1% (and actually the only case that I can think of) where usingreg
is considered harmful. First of all, we're in GUI land and here performance is not as important that you need thereg
variable type (this is more useful in the MIDI callbacks, where every microsecond counts). Also, usingvar
definitions inside a standard function (not the inline function) limits their scope to the function, which is a good thing because you have used the variabledistance
twice. By usingreg
for that you loose this tight encapsulation and you might get weird side effects because the controls are accessing the same variable slotdistance
. In this example this is rather unlikely, but nevertheless it's good practice to resort tovar
whenever you define normal functions which only makes sense for mouse callbacks / paint routines of the ScriptPanel.
This is the updated version:
HiseSnippet 2307.3oc6ZstbabaEdWIsoVzUsNy3NsS+EpldgLVh2rSpcUcstY4vIQWFQIEmoSFWncAIwnkK1tKVJK6Qyzmi9dz+m2f1Gg9Hj+1ekdNX2kKVxUTjJ1MwMgdrFBfyA3Cm6.fGDHrYggh.CyaezE9LCyerU6K7j81pGk6YzZaCyaYcP.KjIM17BeZXHywvzb9mgiZt3BFpOe0S1j5R8rYYcYXbhfay9TdetLqW+0+Dtq6NTG1Q79ZT+f0aYK71R3Jh.jLuUcCep8Yztr8nHYyYYLfyNOzvrt08aVM3rFm9pMpNxm12aypU6zE5uyq5ic7b3+F1QAALO4I.6FlVleM7wz5oNboHnsjJYvbtvlBmKZ2SbtW7ReBOjepKCazvnMfo3t2Q35fadrWis5wccNHU3EZ.y8AYhx4iEk20ZWtCeX+Yhz6nFfjwgtn0btIAuFWO7pWD7L0f2Bwv68sZaGv8kYifX61Vs7jrfNTPapCqXZMl6iuqUsZGDcpK2lrsnOrkVpzRk1R.L4Iq1mdFam.nwvIo7GUu9JjOrd8JqgDVqFoUeeQfj5I+Cji5wHfhWFHbcYADapq6ofhmD1SD45P7DRxoLB6kL6HIygH7HpYPBrEvntDIXEAsfu6.DZSiBYDtDny8BBsSGlsLTQ7yNtU0kJoLrq5v5vB1JYkBKKChXwPyCr0BA6NFYWgyAbocuOqGi4tToWuTIB7g64x8XjNQd1RN.EbuBTpHpLxbkX5RHG+3JfsDw2yEni7XRpTpKStk.jBdPiXNWKimruEyWUv26.PLKOTDIA.TNE.k6VIi1WmmU7S2pc.msMbcKK6wCwEs7xm1M1Ia4JoKYddFPCH3trM+UL.vZLJBbXAX2KqCVcdNPDBrrKEjwATutLsksGi2smb4JqVtfNqk0Ue5KAjQ9fgK7IT2HV4JUVYHpp0bERASb1vwJSc.Vq11AzyAbBy0nhnPTUfRDMfwkr9iJlxKTODrrJ+mquR59VGRmycj8VtRQn7KJVOqgQb9lMH1rHL5.y0mh1J0KDYCQctufhuJqkGZWdcVl6J.etTuoLSS1.vzV27LOB4cHwjT0FhibFyoR9wGg7XADIjNfobmUZRRm.QeUy9HFHpYZb9TaeGpjVUQ11PbTkQkl0chQ1HRwKy2j4FxtVPhtBdryu9EXbVyDIfxqakwInfkKcIc3gRL8KAVSsI44jUIYs97JjZj6uFJHA8kcjKjdQI9BYdgbIe.WdQQ9Hoez1Wi5iWj38dCQktIXetWdWiXO90FeIub7tJVnMDW+pwD3vNt1QCsW5QCI18PT6L0RW0DFlNgoKUQ3cH0ALeLZc4IRTBNtRhhSUAZFmsFldrbiUHYHXRBrQLj08lUe+xbw9KJuVV5uqKylhxImaCzBOKfdJwWQ543rR7odXp0wQLTbAJ9HIY6ByEzQsXSYBwadhsQiLitKtQotK9BzaAjSRAAiyp5TIAOkFFWjhhLbC96BSr8Jqu2UcUYzUAigk4XgyN01VDAhhNh.0TFmFgH5jsjkGF39674juoEnLw7kwRWHRiuK8haZt8wyMMxVk7mHOrwiZhgS1DbIIQ9ijInvfSeiJUnVSH3cBKewTjZpPX+GyCaGH370lBaDTWDxlTMEqVDCSZC7tbYP5Qs1MtHjzyUTbXqenZo2gpV5CHOn96hkKMIokZUO1e5EXZaCLVxZy9B+8n5yZ9n2bUnU5R04XycUDUGozrkSisnJcYbRGd6DKGefskiOaL9ugU6I71SHY66UtRoWWZwRWN1Hc5TzPZaa0nnldWVXHsKKtDvzg2Kp+oHQjG+XRilODU4GjUKzX0UpGsLVoV3rlZ.sVAblofKoI0WZZwXEUvbmqFeIm7clQGx2nXKuPEuTzfIHsK6o.5JIUPlJ2i6EAepLX750qUqMVBPrmFTaYb8n8ENXfMn9xUI8DmCUHPZg+A8AdhtzaXIF4VKXGM9JcUGcYflWAtuMLWH+Ec9dS2EcZGePCMBEds73x88YIsm7UgZjbRE7RQSPHPpTcknKkdknXw6FbXNJYkJSMTafr6r9KW233VaCgxSmHXNg0wmEH431wba1.tMK9tVWzZaV3YRgug4bCOdjg4clhk8kYKYq0uPugpPlrN970iq3Bum6tlFFPthzA+ae8+b8rC5jwxuNo2CoN7nP8au2W3G4uu2g3DtEVq.dGv8.Aaqv78kVvNv76s2d6eLxbVYYXuFF+m+N1KT1i37gW7pg4uzRMIPYWerX.XS8aIPsec6x85pMAMwY.u0dbFvRZZ4k7bDllyYnIJ+oWkn7VVwVp5BR9TJHS54eGstlvz3Kew+OHLMF+EAti0toADzerB7wdRF.BGk6UAvq4GKG5B8GCZFdAi5S8CrLsv88sTtMEi24J.uf66aa7l7dPKY8T0aRjA1Er1442zG+4lAkeRLTtsUa7nNXnZEP9Yp1jOCOyvyXdr.TnNgW76e8l+E+12VBq9QPcxg9hvbSbaVe9QfedNmpiCY6Dv9qGhJY892RPCJbnu5I6.6wB4oMUFEnrV1nOdkK4rNlOuJwZ5RSk2oQi9q4g5V3ag2Q7MuW3a0fFyvydNuFdWLEus488cYO0a.yERWmD0XaVGZjqbXu5.dWgmvumviaqaXbHSFv61kEnuMJbusgTRw.7o8b20Oj4xng4RdfWTAM.DYrIIVle5DKS2K.Wnp6WXECWB5vR9NUb+gZPzrOq5xDMnxWPq2qEuPDjinJ.koTaA5+.IxjdDk7GTPeNZ2WHj8xGaiudhwzI4qXb7LM2XsotT4Gk9C2H6zeIJx3CZo5gLTS27Mmfo3M+akM4MNk+7eSS4eC+QVbqqPq7yKVqLQH+WN93+QAJELZyzpTTKp5HspIQctEyeiUyGLxuhlA6C+oy8vu9nsTse6Xz9scIQwucT2coPLbnxdKvytMTJhMCPhGbzALQOb.CjUU65X63ZQ7bpm9SIJYvFXayjAajN3+SVi9T6.wKR9Mzf1f2R0Cru8T+zoVzZWrMoQ5wWQYSeHR4KrsQg8pMLLJlilyLG2el43AyLGe3LywGMyb76mYNd3D3.SKsQjTzONzjgw+EvQ+T12
And here is the Javascript code that could go into a dedicated file:
namespace ModPitchWheel { inline function makeModWheel(name) { local pnlMod = Content.getComponent(name); pnlMod.setPaintRoutine(function(g) { g.fillAll(this.get("bgColour")); var lineSize = this.get("borderSize"); var linePos = Math.range(this.get("height")-((this.get("height")/this.get("max")) * this.getValue()), lineSize/2, this.get("height")-lineSize/2); //Draw value g.setColour(this.get("itemColour")); g.fillRect([0, linePos, this.get("width"), this.get("height")]); //Draw line g.setColour(this.get("itemColour2")); g.drawLine(0, this.get("width"), linePos, linePos, lineSize); }); pnlMod.setMouseCallback(function(event) { if (event.clicked) { // save the value from the mouse click this.data.mouseDownValue = this.getValue(); } else { var newValue = this.getValue(); if (event.drag) { var distance = (event.dragX - event.dragY) / 3; // Calculate the sensitivity value newValue = Math.range(this.data.mouseDownValue + distance, this.get("min"), this.get("max")); } if (newValue != this.getValue()) //The value has changed { this.setValue(newValue); this.repaint(); this.changed(); Synth.sendController(1, newValue); } } }); }; inline function makePitchWheel(name) { local pnlPitch = Content.getComponent(name); //Grab pitch wheel panel //Paint Routines pnlPitch.setPaintRoutine(function(g) { var lineSize = this.get("borderSize"); //Calcluate the position to draw the line based on the panel's value (pitch wheel value) //use Math.range to account for the height of the line (lineSize) var linePos = Math.range(this.get("height")-((this.get("height")/this.get("max")) * this.getValue()), lineSize/2, this.get("height")-lineSize/2); g.fillAll(this.get("bgColour")); //Draw value display g.setColour(this.get("itemColour")); if (this.getValue() > 8192) //Bend up { g.fillRect([0, linePos, this.get("width"), this.get("height")/2 - linePos]); } else if (this.getValue() < 8192) //Bend down { g.fillRect([0, this.get("height")/2, this.get("width"), linePos-this.get("height")/2]); } //Draw line g.setColour(this.get("itemColour2")); g.drawLine(0, this.get("width"), linePos, linePos, lineSize); }); //Mouse callbacks pnlPitch.setMouseCallback(function(event) { if (event.clicked) { // save the value from the mouse click this.data.mouseDownValue = this.getValue(); } else { var newValue = this.getValue(); if (event.drag) { var distance = (event.dragX - event.dragY) * 40; // Calculate the sensitivity value newValue = Math.range(this.data.mouseDownValue + distance, this.get("min"), this.get("max")); } if (event.mouseUp) { newValue = 8192; } if (newValue != this.getValue()) //The value has changed { this.setValue(newValue); this.repaint(); this.changed(); Synth.sendController(129, newValue); } } }); }; };
-
-
Thanks Christoph for adding the update for pitch messages. In the controller callback I'm detecting the pitch wheel as number 128 should this be changed to 129 for consistency?
-
Aargh, I've explicitly looked up the numbers in the Control Modulator's code and there it's the other way round - now I know why I always confuse these two (128 & 129 are Pitchwheel and Aftertouch or the other way around).
I need to check if this breaks anything, but then I'll fix it obviously.
-
@christoph-hart How about creating two built in constants like in KSP -
PITCH_BEND
andAFTERTOUCH
? Then the scripter won't have to worry about what numbers are being used behind the scenes. -
Yes good idea, will do.