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.

    alt text

    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
    

  • administrators

    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 to var. Now this might seem illogical considering the fact that I always recommend using reg 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 using reg is considered harmful. First of all, we're in GUI land and here performance is not as important that you need the reg variable type (this is more useful in the MIDI callbacks, where every microsecond counts). Also, using var 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 variable distance twice. By using reg for that you loose this tight encapsulation and you might get weird side effects because the controls are accessing the same variable slot distance. In this example this is rather unlikely, but nevertheless it's good practice to resort to var 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?


  • administrators

    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 and AFTERTOUCH? Then the scripter won't have to worry about what numbers are being used behind the scenes.


  • administrators

    Yes good idea, will do.


Log in to reply
 

2
Online

315
Users

919
Topics

6.0k
Posts

Looks like your connection to Forum was lost, please wait while we try to reconnect.