HISE Logo Forum
    • Categories
    • Register
    • Login

    VSL Velocity Histogram

    Scheduled Pinned Locked Moved Presets / Scripts / Ideas
    9 Posts 3 Posters 571 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • It_UsedI
      It_Used
      last edited by It_Used

      Hello, i created velocity histogram looks like VSL, maybe it will be useful to someone.
      This is a not ideal version based on 128 sliders (i know that need uses sliderpack for more effiency). I want update this in the future.
      Feedback on the quality of the code, suggestions for improvements, and reviews are most important to me. ❤️

      Screenshot:

      e952b42f-cf14-4b2a-9211-b2c273508403-image.png

      Snippet:

      HiseSnippet 3779.3oc6ctscaabEFFzxzITI1wIMM8bJpZZBUrBMAHAOj3DaKIKa0HYqZ43C00McD4PRDCAvB.JaEW2ld3p9lzWm9hzz66Z0tGfM3AQJGq8t9lnQQNKxYlMlM9mu4vOEzRaEFzRFEEDZja9aseeoQtWM+166G2akdBWei0W0H2YxuoHJVFZlVzx62WDEIaajK2bWUUPtBmzH4qu9hKK7D9sjiJxv31Atsja3tqa7nR25Repqm2Zh1xa4t6Xst5kVuUf+JAdACf7Yt7kM5KZ8PQW40Eplch7FWSD0yH26mW1tS8xsrDssKKqWGdSMKmNxcpVUZUuS8c1oovtZCQCKibm5JsciCB2NVDKiLxcxkCZu+18BdjeZGba2H2c7jp2XYrMzyoEuVfWa0snpTiU5450dqLgJx.tJaMR1lKU1dy7a511cX4ijuylTg4nHFW.ychISu4lH8rFO8JOV5MiTJ2XozISSoWO+1sBc6GOpFU9jOeTqIShzVYbh+0Yye9yattuabo48AEOBTeo4skdWyMJNX9mL+7Ef5WU1xSDJM6oJrqX24K.iYQwl6IBM666AMOnka79IwzMTrq4GatRferzOtjnc6sD9RuhKLqFtvRlkguW7iluvrptTjLt3BOxscbOnkV1MLOmoEzZSHmNmiYmvfcM8jchM2IHrsLbogEF51sWVokdVW6dRUKgKdkjjXh61HOWH7n4KntM2ChGtst+CR5bkf4J7b+Roob29w6aJBCE6WJsoQwhv39AQ2EZuSRy2VUhITDDUf+cMK5z+wKdfVeuCo02ahVeGnUVIs5NJUwrn0n5tFTmc4jJuVxs0vZ6DDZVzEpFp007BJkDdw4N2hlic6pjW7VFB4IyWnf5d99tOXxQyO0OXmhKnpZAXzvcowtcm3s2SomYWhIGHuyzUMbb3ZSWWT79dRnpEtsLL1skvagoaytt9KffzApP7XE5zXVWVY+sgQPUbkJW1ZFs.lTdK4iiWNPcM5H7hjynQsBC77tSOoz6vajzW.SoUKJrgTD5+LtZR+12V3MPdC+UCEceFMDxsjFtUP+A8Upy0ClktDLHRtszWwR6A3uRKJCeMcK2KcYmCqGS5qhIw8T07jChTNi.pMEOTN9zRyvfA9vRqSRUiO7nlW6Z99pK34gACmEmtarrqLC1MoqFex92beY0v7CLU+Ctref5pMryd57yCWxsfEwgYep0rFeIwjEwRpy0uKrtX5RE3TUrXnSyV4rzgsjSxk3lACf1KK1YfeK0b7hcWLMeguGaFIrZMDpvOYgVWEAolYlLWekfPeXhpheSV2.KV.uIFVktTWY7FAvTkkUxQTQmEyZw18DsCdTeAr1wno0sBkvdQaAEVLogiZjZF+MSkzaJaA4RWOYQwRi2+IQfIdn3QlQIAmjocKsirqq+Fh8kgEGgUcK0FZ3pgA8S6n0fkrS57Q86RlIch5TAQkdjabuK60umnX4GWN4K0TVamEWxzdIy6qd2CvKrneeu8gyt7vCdshCGj04vTrzL5fYd2cRSZXXJsqKNqLXkqn9ujLn7h3krCb1linLsGRGl9C1cGnMlB+1ld.UDUBtzOG4wDJAlGPDqAioEW3lhuncOguqZx0XZtZ0rhKTFJ89NvTg5KYBe23Aika1Uew121US5bXBuMlAVkGlBGhPNr4pVCeW6AKkrJwnr1o1K1r1oVVV6T6Hk0plenYciluXy5FMyx5FMORYsp4GZVaU9EbZCcPVdCuDSb6mqDOo8Sm4OM4rcv56iVOWM8ac+1vwIfihugnyvkzWIYsPSOQGyfc9B3xWZ7S6pVSGZ8TqclrX6FAAO7x9sWCNJPxZKXiKEBKBpbSsV1x8KntY2.lqKB2N4DWpccGtWvRpNF2P3nszzHM24Yuzz8gdnDrEi39kAUp3v2U4AvFv1Kp1cTU1dpM8yJAtnIYVZKsg3r.EeXyf2Obyu6.wXMtzO0wEF1T03PIOoe23doaqO0F2SIsnrlts8DCpY1KCGNZlsUZrpzIFIyZKjSWwG1jRhijIweijQ9hSYInCDznUtcy3mgCdPO35qVDeXII8yPPqHd6kHG6AWfjKFTXRoEb6.kp16N8zVKZdAPvT0lVcg8JoRfUB1sefOvdoaoBaB5jddNUCl7nZETGroPAIzLyot3exAt1CCchVoF3KaWVc5rIJGlrs3nt3o340FdlnLAe3PRorWo5mjRVQ34sCX1ezwfRUmTrWUapdm7+loVW3.haFuMqNUkUIkUzVIMoG16pxXS+f3Qiokl+fievs70gVjcXNHGgTzSwjlJddSvksnqLQYF1D0AKgzHChmbPScRDXtiJOSFRvFM9.CLpa9tuq4Lp5BiWX5QZWb5oL3v3zgeNyJ3ocUHQZbgx3Ag9oSl9n4OvWCkg.ekJbC0XzSvEJUCPcOn.N9vyTRmR1O3UrSmTIEpxbr5TKupLVoNl1LpNcj7YDXwziUsjYxhSCanQtSN4m9R9C+SeY7ObnVoq1OVCC7UeH.2nuz+v9HiLvsHLLx8UXVAMMN4yo4L3mSS5x+FtsMx8R4UZXYijD1HWgSk8woY7bGrEmfs4DbENAWkSvNbBtFmfqyI3FbBtIsfe4THoLqnsXEsMqnqvJ5prh1gUz0XEccVQ2fUzrXMaVrlMKVylEqYyh0rYwZ1rXMaVrlMKVylEqYyh0pvh0pvh0pvh0pvh0pvh0pvh0pvh0pvh0pvh0pvh0pxh0pxh0pxh0pxh0pxh0pxh0pxh0pxh0pxh0pxh0bXwZNrXMGVrlCKVygEq4vh0bXwZNrXMGVrlCKVqFKVqFKVqFKVqFKVqFKVqFKVqFKVqFKVqFKVqFKVqNKVqNKVqNKVqNKVqNKVqNKVqNKVqNKVqNKVqNKVqAKVqAKVqAKVqAKVqAKVqAKVqAKVqAKVqAKVqAKVqIKVqIKVqIKVqIKVqIKVqIKVqIKVqIKVqIKVqIQVq.9Y4VlW3V7B2lW3U3EdUdg6vK7Z7BuNuvavKbdTmEOpyhG0Ywi5r3QcV7nNKdTmEOpyhG0Ywi5r3Qc17nNadTmMOpylG0Yyi5r4Qc17ntY9yT3yVeUQrP8aw.9iIeqvf9pGva0OU9bqJ2yskL82ogB4WUF8v3f9IsEeLJLxcpzt8zY+FOnd.cS502J+rd3aMdrQt74T879YuH44QWkT+cLmReJzUk71XIpex8C6wy9M9ytOoOxm0GpWj7vqaja97YO75FYO24peGX9O+i+8+byc15h6Jd7nekXLuzvDK2TI1ahkL1yld1syXOI5YEcfm67gsbxmx7rhO3CKtp+N66k1e8EgfFLlXbHp7dYO+DoWRiif7YkJemho78NGSkO6T46kXJekOlJeURkuWlo78gGSkupoxWAlx2pGSkOmT4adpx2odCTaNdJe0RkuWQKejju5ox2qpkORxWiT46zZ4ij70LU9NiV9Nhx2vmmyj6kWSqezzOz2wY05GM8CMd75Z8il9gNOdCs9QS+PqGeGs9QS+PuGuoV+noen4iu62F0uCnKOux4QR+P2Gukl+nwen8iumV+noen+iuuV+Hoe1n+iefV+noen+iend+CR6eXi9O9QZ9iF+g9O9wZ9iF+g9O9IZ9iF+g9Odas9QS+P+G+T87WZyeQ+GlZ9iF+g9O9YZ9iF+g9OVPyej3uJn+ietl+HweUP+Guil+nwen+iegV+noen+i2UqezzOz+w6o0OZ5G5+nnd+CZ6ef9OVTyez3Oz+w6q0OZ5G5+3bZ8il9g9OVRqejzupn+iOPqezzOz+QIs9QS+P+GmWqezzOz+QYs9QS+P+GVZ8il9g9Or05GM8C8eTQ6eij+spn+ipZ9iF+g9Obz5GM8C8eTSqejzOGz+Qcs9QS+P+GMz6ePZ+CGz+QSM+Qi+P+Genl+nwen+iORyez3Oz+wEz5GM8C8e7w54uzl+h9O9DM+Qi+P+GWTyez3Oz+wkz7GI9qF5+3xZ9iD+UC8errl+nwen+iUz5GM8C8erpV+noen+iqn0OZ5G5+XMs9QS+P+GWUqezzOz+w0z5GM8C8ertV+noen+ieo97yjN+bcz+wmp4OR7Wcz+wFZ8il9g9O1TqezzOz+w005GM8C8ebC89Gz1+.8erkl+nwen+iekl+nwen+iap4OZ7G5+Xas9QS+P+G2RO+kz72Fn+iOSyej3uFn+iaq4OZ7G5+3NZ9iF+g9Otql+nwen+i6o4OZ7G5+3Wq0OZ5G5+3954uzl+h9O9MZ9iF+g9Odfl+nwen+ieql+HweMQ+GetV+noen+iemV+noen+CgV+noen+icz6ePZ+iln+iVZ9iF+g9OZq0OZ5G5+Pp0OZ5G5+niV+noen+itZ8il9g9O5o2+8Ht+K9m28xnADWM.dDAvLADcf7EZAjn.hVPdnV.IJfnGDOs.RT.QSH6p2Dg3lHnKDeMARj.QaHAZBjHAh9P5qIPhDHZD42qEPhBH5DITOEl1T3r+TnGoIPZDX1eKzi0DHQBDchLPSfDIPzIxdZBjHAhNQdjl.IRfnSjGqEPhBH5DYe8TXhSgQmHeol.IRfnSjmnIPhDH5D4OnIPZDX1eTzepV.IJfnSj+nV.IJfnSj+jV.IJfnSjuhr.9ZGyEPzIxelr.dli4BH5D4uPV.O8wbADch7WIKfu5wbADch72HKfux29NH8VgAsjQQAgF4N4sRDvyleyf1C7DwAgqzS35ar9ppBuJ7RrB2.eik2uuHJRBpat4V2ONIoTIzISSmu9h4NwUZ6BWisiEwxHibysbP682FTE3tbt7VF2NKgmKeYisC7BRekwJ8b8ZOLqTe32Omo3qmeK23V8lcNdhYjiFFuPxw4RywSm+Jc5HaEOJAOY90t6D51++59aFLH10u6lh3PWEuc8A6tcvfvVRn288kdQJt3Dp4KouubFm.zT6j27eguvJsTuOGVoUVkF6J.98yaE3GCXLzo4d4jRfbxWrqZ1R9MUu2zxXOE5NtNuK.3edqVSdolJPapAVgZfUoFnC0.qQMv5TCrw2bfp0et7f3fcSm1XXr4VWYUQr.Xzqjr.UBsZ7+.J9soE
      

      Code:

      // Init.
      namespace VelHisto
      {
      
      	// Declare histogam
      	const var pnlVelocityHistogram = Content.addPanel("pnlVelocityHistogram", 0, 0);
      	pnlVelocityHistogram.set("width", 128 + 10); // +5 from left border, +5 from right border.
      	pnlVelocityHistogram.set("height", 30);
      	
      	// Declare sliders
      	var velo = []; // Initialize empty array.
      	var startposX = 5; // Start positionX (5px).
      	var startposY = 5; // Start positionY (5px).
      	var W = 1; // Width (1px).
      	var H = 20; // Height (1px).
      	for (i = 0; i < 128; i++) // Declare 128 sliders.
      	{
      		velo[i] = Content.addKnob("velo" + i, startposX + i, startposY);
      		velo[i].set("width", W);
      		velo[i].set("height", H);
      		velo[i].set("style", "Vertical");
      		velo[i].set("min", 0);
      		velo[i].set("max", 18);
      		velo[i].set("stepSize", 0.001);
      		velo[i].set("showTextBox", false);
      		velo[i].set("scrollWheel", false);
      		velo[i].set("enableMidiLearn", false);
      		velo[i].set("sendValueOnDrag", false);
      		velo[i].set("showValuePopup", "No");
      		velo[i].set("mouseSensitivity", 10000);
      		velo[i].set("visible", false);
      		velo[i].setValue(0);
      	}
      	
      	for (i = 0; i < 5; i++) // Make left border rounded.
      	{
      		velo[i].set("max", 8 + i * (i / 0.5));
      	}
      	
      	for (i = 123; i < 128; i++) // Make right border rounded.
      	{
      		velo[i].set("max", 18 - 8 - (i - 128));
      	}
      	
      }
      
      // Paint panel.
      namespace PanelPainting
      {
      	
      	// Start painting.
      	VelHisto.pnlVelocityHistogram.setPaintRoutine(function(g)
      	{
      		
      		// Declare assistant variables.
      		var CornersSize = 5;
      		var a = this.getLocalBounds(5);
      		var Shadowpath = Content.createPath();
      		Shadowpath.addRoundedRectangle(a, CornersSize);
      		
      		// Draw shadows.
      		g.beginLayer(false);
      		g.drawDropShadowFromPath(Shadowpath, a, Colours.withAlpha(0x000000, 0.25), 2, [0, 0]);
      		g.applyMask(Shadowpath, a, true);
      		g.endLayer();
      		
      		// Draw gb.
      		g.setColour(Colours.withAlpha(0xCECECE, 0.20));
      		g.fillRoundedRectangle(a, CornersSize);
      		
      		// Draw velocity numbers and lines. 0.
      		g.setColour(Colours.withAlpha(0x000000, 0.25));
      		g.setFont("Rajdhani", 8);
      		g.drawText("0", [5, 17, 7, 8]);
      		
      		// 24.
      		g.setColour(Colours.withAlpha(0x000000, 0.25));
      		g.setFont("Rajdhani", 8);
      		g.drawText("24", [5 + 25, 17, 10, 8]);
      		g.fillRoundedRectangle([5 + 25, 7, 1, 16], 0.5);
      		
      		// 56.
      		g.setColour(Colours.withAlpha(0x000000, 0.25));
      		g.setFont("Rajdhani", 8);
      		g.drawText("56", [5 + 56, 17, 10, 8]);
      		g.fillRoundedRectangle([5 + 56, 7, 1, 16], 0.5);
      		
      		// 89.
      		g.setColour(Colours.withAlpha(0x000000, 0.25));
      		g.setFont("Rajdhani", 8);
      		g.drawText("89", [5 + 89, 17, 10, 8]);
      		g.fillRoundedRectangle([5 + 89, 7, 1, 16], 0.5);
      		
      		// 109.
      		g.setColour(Colours.withAlpha(0x000000, 0.25));
      		g.setFont("Rajdhani", 8);
      		g.drawText("109", [5 + 109, 17, 12, 8]);
      		g.fillRoundedRectangle([5 + 109, 7, 1, 16], 0.5);
      	});
      	
      }
      
      namespace veloIndicatorLaf
      {
      	
      	// Create laf object.
      	const var VeloLaf = Content.createLocalLookAndFeel();
      	VeloLaf.registerFunction("drawLinearSlider", function(g, obj)
      	{
      		// Draw gb.
      		g.setColour(Colours.withAlpha(0x000000, 0.50));
      		g.fillRoundedRectangle([obj.area[0], (obj.area[3] / 2) - (obj.value / 2) - 0.5, obj.area[2], 1 + obj.value], VelHisto.W / 1.5);
      	});
      	
      	for (i = 0; i < VelHisto.velo.length; i++)
      	{
      		velo[i].setLocalLookAndFeel(VeloLaf);
      	}
      }
      
      namespace FadeTimer
      {
      	
      	// Declare timer.
      	const var FadeTime = Engine.createTimerObject();
      	
      	// Declare fade velocity indicator function.
      	inline function FadeIndicator()
      	{
      		for (v in velo)
      		{
      			if (v.getValue() <= 0)
      			{
      				v.fadeComponent(false, 250);
      				v.setValue(0);
      			}
      			else if (v.getValue() > 0)
      			{
      				v.setValue(v.getValue() - 0.020 * (v.getValue() + 1));
      			}
      		}
      	}
      	
      	// Start timer.
      	FadeTimer.FadeTime.setTimerCallback(function()
      	{
      	
      		// Call fade fade indicator function.
      		FadeIndicator();
      	});
      	FadeTimer.FadeTime.startTimer(20);
      }
      
      // Get note velocity.
      inline function getNoteVelocity()
      {
      	local i = Message.getVelocity() - 1;
      	velo[i].fadeComponent(true, 1);
      	if (velo[i].getValue() >= 0 && velo[i].getValue() < velo[i].get("max"))
      	{
      		velo[i].setValue(velo[i].getValue() + 3);
      	}
      	else
      	{
      		return;
      	}
      };
      
      
      function onNoteOn()
      {	
      	// Call get note velocity function.
      	getNoteVelocity();
      }
      function onNoteOff()
      {
      	
      }
       function onController()
      {
      	
      }
       function onTimer()
      {
      	
      }
       function onControl(number, value)
      {
      	
      }
      
      Christoph HartC 1 Reply Last reply Reply Quote 5
      • Christoph HartC
        Christoph Hart @It_Used
        last edited by Christoph Hart

        @It_Used nice idea and from a coding style perspective it looks good, however I would suggest a few optimizations on the concept level as this is unnecessary heavyweight:

        • you don't need 128 sliders (as you have noticed yourself already), but you also don't need a sliderpack. If the histogram is read only I would make it a single panel and draw the histogram as an array of Rectangle objects.
        • the most efficient data structure for this kind of stuff is a ring buffer (you can read up on that concept, there's lot's of resources available), because it won't require to shuffle all values when a new value is added, instead it just moves the read / write pointer.
        It_UsedI 1 Reply Last reply Reply Quote 1
        • It_UsedI
          It_Used @Christoph Hart
          last edited by It_Used

          @Christoph-Hart I'll take that into consideration. My programming experience is about 1 - 1.5 months, so so far I don't know a lot of things (about the ring buffer), I think I would make it as simple as possible on sliderpack, well, for a beginner, and so that it is less resource-intensive than using 128 sliders. I am currently faced with the problem that the sliderpack does not display all sliders if there are 128 or more of them. as I understand it, in order to customize them, the drawLinearSlider function is needed, I use it, but I draw either 1 slider at the very end, or 1 slider in the middle, or 4 sliders with some kind of random padding. Maybe there are some pseudo-states that are not specified in the documentation...
          Thanks for advice! ❤️

          Christoph HartC 1 Reply Last reply Reply Quote 0
          • Christoph HartC
            Christoph Hart @It_Used
            last edited by

            @It_Used I don't want to discourage you from learning stuff from the ground up, that's always a good mindset and vibe coding is the death of software development. That being said, this is a prime use case to hammer into a LLM to get something that almost works. With a little bit of correction, I got this:

            HiseSnippet 1216.3ocsV8+ShbDEeV08xIsWSuj9GvjKoIKmBBHhZnWJmndRZ0iHW8ZiwXF1cV1ItLCY1APZiI8m5e.8un92R+Kn+Gz9lcVXWPimGIkDH799m48dy6MskBWZTjPhrx8gICnHquztyDtJnY.gwQsNDY8U1mRhTTI1v5fICHQQTOjk0puSyvZ80Pwe9mu+.RHg6RSYgPWHXtzej0moR41twOvBCOl3Q+.qeFsq1nkqf2TDJFB3YU6RnAD2aH8nmQzpshM5DRT.x5016TYa2pd65UoxN6WykTituOw2u71dUqVau8Ku89jp6UiVZGj0yNxioDxNJhhFAN8.g2jNAhwbS.tfEw5FR0DkQcfHaXiZFvB8ZOM4DgPVq0NMUspIU8M1mx7Xy3mlx95XA3TKxlzrV4wfT4OCHYkARqYfzKs63JYCToRz34KrawgJnOApMYghQWzJ+hscSAnAWUrO4F5wRfXlEN0JUZSL7S954haMJ5Q8oxljvvtP4IxQIGRAY4fZWjBOhHwsIbZH9M3oNsGU0TzeffCDNuJVZ4WoMYqsvEJT.eNi2C2cnO3VMcFOYX1g8qTvckqrW8LxFQCEtL0jCLF9F7kWUOmj1COVxTzVbO5s.yRPX7ERrCKl.yveWFuBzarQ9bX3y7tq3fgQAN5ybNFOjwoX+gbWESvwZIWjnryHRHb5y8aOfKtLEGWAwNVy5w5MG.cxPsAtbd72lEe4t69..Rmyhuv2OhplB.fIIDy7VzuEvkguFcgfj5+Eil1IRpZnju3gAb5UwnYZQqMzsqvRwPkFb5x1h3zSRFeBKRI5II8c5MOHGCPLtSP2c7QlmJvIe8LxCxJ+DJqWfZdE5RjwlA5MFu08NEw+zqnOLo4sggNloJQE6FB8rI9oWwHcioVvL4iCfjltpqU3I02XNTo3ZDne1JTlVXSYfkuNFxghPOJzIGR8U3+9O9SLmNVSK0mzEbIbTMY.cYcDbXKWY2hkxieMNHAoo5pK8LPxzzS8EjOAjG.nXlOy3AS55bpqx4xa2DOYyzjbAbkMSs4JyQnPk3TTDLlFtAG6l6xcG3PSgCxtwMIma5QblqeHe8Y8IB9YBE88bGcGx5yc85TXHFr.nX1DZ9jxmIHR5.cLbLHRAoudvv.IUGLncEuXT78MgYAY5QURQXHU9fh0KpjOlgN7g86RkahmMPHVQXv77S6e1SaZuqYxYFEE7Vbl58CnIzGq6e7L++96FPIidg+8SsNjnH50EI7.8FPkJlFNVGRGAKnMKOV29PZzMJwfXcSlWCPVEK8ESWsnS6HFD5maaFkitMcG96ZLIk35Fi0MOyXz92aDD2+Liye0sA59awf8mBuggD07KU0O2HQ.j6maSldaEOB5Nx9bjOiMskdzMsOUH9R61LkavCiwUd.LBUk+OvXx6Sdg8QvnGWUJ.Wy93edYeLxmH7lK48Nk.WAg9A6yF1uCLQ0kBQmCcIfyssVQ2YZnKoo0YfNTtWLw+BeRDVVSakHr7Tgn9DWo3ZWyMN8KfddLG.S73WHtN7TUfFWFEeKLadtO7frqccm2U2yvJKqgaurFVcYMbmk0vZKqg6trFt2m1P86ke6Pknu4ZCBcZ6ihGaYYcDm.cfwcqn+Cjopn3.
            

            That's more or less how I would implement it. And if you don't understand what happens here you can always ask the LLM to explain it to you, at this level it's pretty good.

            It_UsedI 2 Replies Last reply Reply Quote 2
            • It_UsedI
              It_Used @Christoph Hart
              last edited by

              @Christoph-Hart no, no, no, I do everything myself, I never use an AI assistant, now it's a nonsense generator that will waste more of my time and won't give me the desired result. I like to do everything on my own, it's very interesting to me)

              1 Reply Last reply Reply Quote 0
              • It_UsedI
                It_Used @Christoph Hart
                last edited by It_Used

                @Christoph-Hart said in VSL Velocity Histogram:

                @It_Used I don't want to discourage you from learning stuff from the ground up, that's always a good mindset and vibe coding is the death of software development. That being said, this is a prime use case to hammer into a LLM to get something that almost works. With a little bit of correction, I got this:

                HiseSnippet 1216.3ocsV8+ShbDEeV08xIsWSuj9GvjKoIKmBBHhZnWJmndRZ0iHW8ZiwXF1cV1ItLCY1APZiI8m5e.8un92R+Kn+Gz9lcVXWPimGIkDH799m48dy6MskBWZTjPhrx8gICnHquztyDtJnY.gwQsNDY8U1mRhTTI1v5fICHQQTOjk0puSyvZ80Pwe9mu+.RHg6RSYgPWHXtzej0moR41twOvBCOl3Q+.qeFsq1nkqf2TDJFB3YU6RnAD2aH8nmQzpshM5DRT.x5016TYa2pd65UoxN6WykTituOw2u71dUqVau8Ku89jp6UiVZGj0yNxioDxNJhhFAN8.g2jNAhwbS.tfEw5FR0DkQcfHaXiZFvB8ZOM4DgPVq0NMUspIU8M1mx7Xy3mlx95XA3TKxlzrV4wfT4OCHYkARqYfzKs63JYCToRz34KrawgJnOApMYghQWzJ+hscSAnAWUrO4F5wRfXlEN0JUZSL7S954haMJ5Q8oxljvvtP4IxQIGRAY4fZWjBOhHwsIbZH9M3oNsGU0TzeffCDNuJVZ4WoMYqsvEJT.eNi2C2cnO3VMcFOYX1g8qTvckqrW8LxFQCEtL0jCLF9F7kWUOmj1COVxTzVbO5s.yRPX7ERrCKl.yveWFuBzarQ9bX3y7tq3fgQAN5ybNFOjwoX+gbWESvwZIWjnryHRHb5y8aOfKtLEGWAwNVy5w5MG.cxPsAtbd72lEe4t69..Rmyhuv2OhplB.fIIDy7VzuEvkguFcgfj5+Eil1IRpZnju3gAb5UwnYZQqMzsqvRwPkFb5x1h3zSRFeBKRI5II8c5MOHGCPLtSP2c7QlmJvIe8LxCxJ+DJqWfZdE5RjwlA5MFu08NEw+zqnOLo4sggNloJQE6FB8rI9oWwHcioVvL4iCfjltpqU3I02XNTo3ZDne1JTlVXSYfkuNFxghPOJzIGR8U3+9O9SLmNVSK0mzEbIbTMY.cYcDbXKWY2hkxieMNHAoo5pK8LPxzzS8EjOAjG.nXlOy3AS55bpqx4xa2DOYyzjbAbkMSs4JyQnPk3TTDLlFtAG6l6xcG3PSgCxtwMIma5QblqeHe8Y8IB9YBE88bGcGx5yc85TXHFr.nX1DZ9jxmIHR5.cLbLHRAoudvv.IUGLncEuXT78MgYAY5QURQXHU9fh0KpjOlgN7g86RkahmMPHVQXv77S6e1SaZuqYxYFEE7Vbl58CnIzGq6e7L++96FPIidg+8SsNjnH50EI7.8FPkJlFNVGRGAKnMKOV29PZzMJwfXcSlWCPVEK8ESWsnS6HFD5maaFkitMcG96ZLIk35Fi0MOyXz92aDD2+Liye0sA59awf8mBuggD07KU0O2HQ.j6maSldaEOB5Nx9bjOiMskdzMsOUH9R61LkavCiwUd.LBUk+OvXx6Sdg8QvnGWUJ.Wy93edYeLxmH7lK48Nk.WAg9A6yF1uCLQ0kBQmCcIfyssVQ2YZnKoo0YfNTtWLw+BeRDVVSakHr7Tgn9DWo3ZWyMN8KfddLG.S73WHtN7TUfFWFEeKLadtO7frqccm2U2yvJKqgaurFVcYMbmk0vZKqg6trFt2m1P86ke6Pknu4ZCBcZ6ihGaYYcDm.cfwcqn+Cjopn3.
                

                That's more or less how I would implement it. And if you don't understand what happens here you can always ask the LLM to explain it to you, at this level it's pretty good.

                I looked at the snippet. Thanks for this unique experience, I'll probably release an updated version tomorrow. ❤️
                I think, here we have main throuble, if note with const velocity pressed double - we summon a geometry overlap, for example this geometryes colours are blended both itself, but we have non ideal solution - simply delete pervious geometry object instance before new was created. Anyway here i need a deep think, for create ideal (for me) solution... Thanks advance!

                1 Reply Last reply Reply Quote 0
                • It_UsedI
                  It_Used
                  last edited by It_Used

                  Update: Histogram based on a ring buffer now!

                  Works same as pervious version, but maybe lightly different in FadeOut anim. (Thanks @Christoph-Hart for advice). 💕
                  Updated 15:08 26/09/25: Added opacity fade.
                  Updated 17:02 26/09/25: Some refactor.

                  Screenshot:

                  6446796b-ab89-4eb0-b0f3-90f026bc54a6-image.png

                  Script:

                  // Init.
                  namespace VelHisto
                  {
                      // Declare histogram panel.
                      const var pnlVelocityHistogram = Content.addPanel("pnlVelocityHistogram", 0, 0);
                      pnlVelocityHistogram.set("width", 128 + 10);
                      pnlVelocityHistogram.set("height", 30);
                      
                      // Ring buffer for contain velocity values.
                      const velocityBuffer = [];
                      const bufferSize = 128;
                      
                      // Max value for each velocity.
                      const maxValues = [];
                      
                      // Init max values buffer.
                      for (i = 0; i < bufferSize; i++) 
                      {
                  	
                          velocityBuffer[i] = 0;
                          
                          // Make start end bars same background shape.
                          if (i < 5)
                          {
                              maxValues[i] = 8 + i * (i / 2);
                          }
                          else if (i >= 123)
                          {
                              maxValues[i] = 18 - 8 - (i - 128);
                          }
                          else
                          {
                              maxValues[i] = 18;
                          }
                          
                      }
                      
                      // Add velocity into buffer function.
                      inline function addVelocity(velocity)
                      {
                          local index = velocity - 1;
                          index = Math.max(0, Math.min(127, index));
                          
                          velocityBuffer[index] = Math.min(maxValues[index], velocityBuffer[index] + 5);
                          pnlVelocityHistogram.repaint();
                      }
                      
                      // Fade function.
                      inline function fadeValues()
                      {
                          local needsRepaint = false;
                          
                          for (i = 0; i < bufferSize; i++) 
                          {
                              if (velocityBuffer[i] > 0) 
                              {
                                  velocityBuffer[i] = Math.max(0, velocityBuffer[i] - 0.010 * (velocityBuffer[i] + 1));
                                  needsRepaint = true;
                              }
                          }
                          
                          if (needsRepaint)
                          {
                              pnlVelocityHistogram.repaint();
                          }
                      }
                      
                      inline function getVelocityData()
                      {
                          return velocityBuffer;
                      }
                  }
                  
                  namespace PanelPainting
                  {
                      VelHisto.pnlVelocityHistogram.setPaintRoutine(function(g)
                      {
                  	
                  		// Declare assistant variables.
                          var velocityData = VelHisto.getVelocityData();
                          var CornersSize = 5;
                          var a = this.getLocalBounds(5);
                          var Shadowpath = Content.createPath();
                          Shadowpath.addRoundedRectangle(a, CornersSize);
                          
                          // Draw shadows.
                          g.beginLayer(false);
                          g.drawDropShadowFromPath(Shadowpath, a, Colours.withAlpha(0x000000, 0.25), 2, [0, 0]);
                          g.applyMask(Shadowpath, a, true);
                          g.endLayer();
                          
                          // Draw background.
                          g.setColour(Colours.withAlpha(0xCECECE, 0.20));
                          g.fillRoundedRectangle(a, CornersSize);
                          
                          // Draw velocity bars.
                          var barWidth = 1;
                          var areaHeight = a[3]; // Full height.
                          
                          for (i = 0; i < velocityData.length; i++) 
                          {
                              if (velocityData[i] > 0) 
                              {
                                  // Calculare bar height.
                                  var barHeight = 1 + velocityData[i];
                                  
                                  // PosY: mid position - half height (bipolar view).
                                  var centerY = this.getLocalBounds(0)[3] / 2; // Do not reduce getted value (0). Because dividing by 2 will not give a ideal middle position value.
                                  var y = centerY - (barHeight / 2);
                                  
                                 	g.setColour(Colours.withAlpha(0x000000, Math.range(velocityData[i] / 5, 0.00, 0.50))); // divide by 5 is a fade opacity speed.
                                  
                                  g.fillRoundedRectangle([a[0] + i, y, barWidth, barHeight], barWidth / 1.5);
                              }
                          }
                          
                          // Draw velocity numbers and lines.
                          g.setColour(Colours.withAlpha(0x000000, 0.25));
                          g.setFont("Rajdhani", 8);
                          
                          // 0
                          g.drawText("0", [5, 17, 7, 8]);
                          
                          // 24
                          g.drawText("24", [5 + 25, 17, 10, 8]);
                          g.fillRoundedRectangle([5 + 25, 7, 1, 16], 0.50);
                          
                          // 56
                          g.drawText("56", [5 + 56, 17, 10, 8]);
                          g.fillRoundedRectangle([5 + 56, 7, 1, 16], 0.50);
                          
                          // 89
                          g.drawText("89", [5 + 89, 17, 10, 8]);
                          g.fillRoundedRectangle([5 + 89, 7, 1, 16], 0.50);
                          
                          // 109
                          g.drawText("109", [5 + 109, 17, 12, 8]);
                          g.fillRoundedRectangle([5 + 109, 7, 1, 16], 0.50);
                      });
                  }
                  
                  namespace FadeTimer
                  {
                      const var FadeTime = Engine.createTimerObject();
                      
                      FadeTime.setTimerCallback(function()
                      {
                          VelHisto.fadeValues();
                      });
                      FadeTime.startTimer(11);
                  }
                  
                  // Get velocity data.
                  inline function getData()
                  {
                  	local velocity = Message.getVelocity();
                  	VelHisto.addVelocity(velocity);
                  }
                  
                  
                  // Callbacks...
                  function onNoteOn()
                  {   
                  	
                  	// Send velocity data.
                  	getData();
                  	
                  }
                  
                  function onNoteOff()
                  {
                  	
                  }
                  function onController()
                  {
                  	
                  }
                  function onTimer()
                  {
                  	
                  }
                  function onControl(number, value)
                  {
                  	
                  }
                  

                  Snippet:

                  HiseSnippet 2071.3ocsY01baabDFPVzSEmlNIsc5G6bi+DXLML.snDcURZrdKVSsr4H531LZzj4HvQhKBDGFfiRh0i+Czes8eP6t2gWIAiXTafkFAb29xyt2d6t24gIBOVZpHwvr86WDyLL+ssFsHRFbT.kGYb1wFl+tVmSSkrDhdnCWDSSSY9FllO56vAL2YaC0y+9udHMjF4wJGxv3CBtG6M7YbY4nC+1+FOL7TpO687YUnd2u8LOQzQhPwb.OOpkiQL06Z5T1aoHYa0x30zz.CyurEyex9NdtT+dNr82G9XO29SXi2cWl69S1e73WR6s6.5.WCyGehOWJRFIoRVpg41GJ7WLJPbajVAefmxGGxvObMFAZVO7ohPezDwQMNJfG5OL2QkZ.RYXoa6QZ21er04bedw3ktuOWMAojipNPyspCuGUCdtUgmSE30.jLq.os0P5KZMxKgGKKmAwyeHazRD4VCR5YM1Z2eeqm+bxYQboc6Hv+mBqELxGXgulmJEs+XaB7.TbLyKjlvHA3vSSnyHwzHVnsZdX4LURtglPhiBAdEdb4hWWP4WSNRDIYQRapu+PjMqmzDgOoKwA9oyAJg1DE1oLo0Stk6KC.hc6Mf7Th68yP.iOMPBb7hbZyMqK3QSIimOYBD3OQjfVhDVRI2jIHvnBmyRqYlYScnlqulb4UGTYZsvFw+mLXJ.g0024z6zhToMF0KnPdU0wL5cePo3JhOWD3ZERPFzxTnlaTnVbfImCHbxWUALv2O8oczB4is2Q8W7ot0bI+JEyESW7hB6WyHoRZhjvh7IioIojTHjAdy65oIh4vfoAzXlcAW7IHb9JR+NEC8wh2vmBCUqYb8jS9RjomS50oDGep3MVXJKSteC5fewFJZ2AjmQveAFeFtvrVouoxqI9aW9Y950q78KCm3QRQQ717HOIWDocW7nPdDqXPBrUIOZ1Jm8NsqCKXTZHvoO6N.QEJALuRrkO64TYfMXCVvVL867HK2d62USQmNMrnubvAR3UExB3uhOQMW20vxSgHfR423F0DVLrwSZkQWceHVD4d7WS.RzXwpY2TDi4mdgVKfMLgBK0MXya1VnUCOvPxU2L8MP5LRM5py051BVc0Z04eFww1w0A2nr5jPFwpKl4OKY9xj4r5D8o0ENmacUkv51zsIKskpnxh7xKmSYxbAcLURWYMMgImmDsjuIOz4SsqTKSUvYHB.HWeVAs75a1qqlgh9KDyAdXV4fxZZmh7m6rSkhhPUUfYZjpFHmBkxSKyAhkEuoho.N+B0uhUdPM1NRjDwRRyJlzu9jnfjP4XTHuAivODy.mZ0eIgLJf5KtMFBnpTH1KgAshLDFrpNKIEqTeAJOl+ELOvzlFxrncqhnNMWk33D5sXY.PPUbBSsGylxidCcAKwRs0qB6Ss8AlNNQDqAvoIhYJnUhmtDkxwVFSsukKCdUXb.0x4NG0Cz0fcu9c5R50kbI90U0DOMNNbAzd60KKQbWPMJgBaZL9yYck06pZfPTiFfVMgyiNA+mBmNcpoxIPSx+O3pKx5i0iqG0Ai72wVkvpUKE6.K+uV0TDLG8xWb0AprryCCI5dkru+DiUiosCYQSkAadFRjoMM+HfringdyUa0.aZEHtjMWXXtPtvkT3p4EaRcCEo+vegLi6ShEobU9nmQBngSxTMwZLOVDhar4ra6zLR7f8YrjeXM6Rc5.dcrIGkm+XAIRHgjZ9ygLV.oRleVeh.k1jCYdz4PeO97afSYfsrtfzibKD4n3aJ+FHIDg6yf5b.r8CYkHWIllg3B.b4vDZLpz2Uu4q04p149B5y2bpplk.Q1rUB.dNoOtoPuEtOr0nixgnLTFZl8I7Tv1vx6DAjPGC0SigRQ12+R4Z1bcI8RGrNIuKYQ2hcIcKictpbT.ft1867KnT4JaLilOaLrQlPg9iwhboadViZY2pk0.36THWt0Stf9S9AzHNb5lAqIOgyRYZeO6NfQGfiKAmuKzBH7yfqVC281sQ16sqhevM1KSHtNKIk049yYB4A9YuqxV6aV+82qQ82eub82euGf9Ql1L8O3kMp+AuLW+Cd4CP+HSal9ccZF.v34H.dMCB89E.AEWMigOA+sVST42hSRVCTkm3OeFHUxIQPIdVVuEJpe23eBzoU0CcmSOFAqnAxsGhUTKayZ4d8JZWpZO9k.stTwympjqkqq1J.e32wJO2NwGKX0tgFNyZzDZuSehgBNf9wYoozorpMrgPXmBn03w0Tpust9kxFSsssaWnRQzaER16PC9in6A5pDncDd35k.6NEnCzIJzkkwjIZfCyQpLG1tWhHLDanogo09oeFFsz4t5pKhTPng410uPqVq+Bspdead5tOqPnHBuNi2EyhV2svYj0xJ712eF5CvaAKaLftXVhjiPv7X1MbOl9Nw1o0wrzqkhXEsyhEQnDLerTM6mkeiY3ICL39Fl+oVMcP.i6.KyDuxxE4unt5IP9O9ekcwm5FBvQ9y42E5pWQ2m25bgOz+hr9MFh2qZ1DfWu10ycFZePA7EUu20+ucMhaJD+hVC4Ruflw3VMfQXs4WCLlc4qeVqSfS44IKA31sN8e7qyMsZnO72Tn0kDNFG714yFA0m8Xf1if3FLp2bKL9T+sSdHBt+U8w+AdxlzE+1LaR27IMlQ8RD+nmduFd8t+F0H.lhTWE9NsNG+l3Zn1+U0OCc4w+QOu5hZEF68PY7EOTF28gxX+GJi68PYb+GJiCteFw+y.d0boXldaigw4COQk7xz7jH7BBTQqF+W.sdb86C
                  
                  d.healeyD 1 Reply Last reply Reply Quote 1
                  • d.healeyD
                    d.healey @It_Used
                    last edited by

                    @It_Used said in VSL Velocity Histogram:

                    reg velocityBuffer = [];
                    reg bufferSize = 128;
                    
                    // Max value for each velocity.
                    reg maxValues = [];
                    

                    Arrays should generally use const. And if that bufferSize is fixed it should also be a const

                    @It_Used said in VSL Velocity Histogram:

                    var velocity = Message.getVelocity();
                    

                    This one can be a local

                    Free HISE Bootcamp Full Course for beginners.
                    YouTube Channel - Public HISE tutorials
                    My Patreon - HISE tutorials

                    It_UsedI 1 Reply Last reply Reply Quote 1
                    • It_UsedI
                      It_Used @d.healey
                      last edited by It_Used

                      @d-healey said in VSL Velocity Histogram:

                      Arrays should generally use const. And if that bufferSize is fixed it should also be a const

                      it is my typical stupid moment... Sometimes i forget primitives.

                      @d-healey said in VSL Velocity Histogram:

                      This one can be a local

                      Yeah, after publish move it part to init callback, into inline function, to avoid cluttering up the onNote callback. Now i update post!
                      Thanks a lot for the advice. 💕

                      Edit: Post are updated!

                      1 Reply Last reply Reply Quote 1
                      • First post
                        Last post

                      12

                      Online

                      2.0k

                      Users

                      12.7k

                      Topics

                      109.8k

                      Posts