Forum
    • Categories
    • Register
    • Login
    1. Home
    2. dannytaurus
    3. Posts
    • Profile
    • Following 3
    • Followers 1
    • Topics 79
    • Posts 683
    • Groups 0

    Posts

    Recent Best Controversial
    • Code feedback on this custom envelope panel

      Looking for some feedback on the code for this minimal envelope panel I made.

      I needed a tiny (130x42px!) envelope control for my synth and wanted to take the opportunity to try making a custom one. ChatGPT helped me a lot with the geometry and value conversions!

      I kept it deliberately super minimal - not curve controls, no hold section. Just A/D/S/rR drag handles with fixed pixel ranges and abstracted value ranges from 0-50.

      How does the code look? Never made a custom panel like this before. Am I on the right track?

      Snippet and script below.

      HISE-CustomMinimalEnvelopePanel.gif

      HiseSnippet 3916.3oc2arsaabbcos2TKkqNns4B5CiIJLHsoj4RcwVxIwjRjxRMRxJbocrgQfxxcGQtPK2kY2kRjwvn4Kn.8s9Veq8SnOU.CTz2yOPQ5mP.5GP64Lyr6NK4R5KMtQoBVhblyYl4b+blK9.eOSZPfmuRt4aMpOUI2anpOxMr6lcMrcU1otRt2SstuQmNFscnMbOg530m1hFDprwn9FAATKkb4N+cPjyM2ETX+782dCCGCWSZRWJJ22y1jtqcO6vjdOn5mZ63rkgEskcOIrWt5Nldta543M.HryqVVoug4wFcn6afncNUksMB5pj6pplVKatr4psWVyv3nan0dUZ6apcCM5MMWwZMSSCyUZapszRFJ4dsFV1gd95gFgz.kbWXCOqQ5c8N0ku.22NvF3PrglhNrx7t2xywBYQrWkM6Z6XcPjDKPQIm5AIxuyyke+b08rsri6OQN9NL.jjQHK.yctzj24SQdZxjWYIxKCRJmDIcANIcIUcSe69gIPP540U2wMj5ejAnmjIENtJm6u+qT2zCvvMbwdFGS2xGZDOhBKWtbIRkxkKdq4ivJfFdu.511c51jF34LHz1ycKO+CLboNAEB8GPAjmGTrAgj9tNfwD4iIQCtCMbSud88bgFExyAmu3sHW+5jsrGRsHA1eMknsT4gKWQLGT1DvrVwgumm0.GCPFVHOL1Z85KFdssqq2jzCgRmed9LizZg7FNNdmtI721f0UP9Rj7a5XCeqDYauSn9jqPXV91tcxiTNLWMoCBPGAReivtji77IV9FmBHPB6RQBh4djPeGfnkvjl9TP8hcV.lPNVAg9dGSAjdLoUWX0cAMz5DsEKSdBeM20nMH+DX6z1o1TkZHv7wSLzp9rPsdJT0mEp5oPs4rPsYJTObuZO.vdkxKVlyLbkgQXnuc6Afkt.0cp+fCQ9BDY3TVKB9NtVzgExCsAMTxLinWe5nWmZZLJM15SGa8AAgfOZZ7aNc7aRcnFAzHSBLxEw2vsCMfYPvo0RDFQThHvVL06sy9GtGRKZn.QzWsGv6C7lhkSBhh.+yZCAh52SuUMXBpuwgv7.CXAM9.lDLSpGOYbGn9vecHldd9VQh8CpseicO7yQ5YIoYh281P2KWIo2F6e+CePYnyajtuGlQeOPCmyJKMFlXuKsRDYssgqE3J0y1858LFRNwvYPrAAXNzpUsM+TAmJM8IPXLoLcCFEM1r1COTGXfo.hOnUSAQH3f9WKU+MaraiZ5MDjvTfwlOsJbYMG5F01cWznG5hjvl9FV1CBjP4vJ.RLbuJohLlAe0.CepEJitLY6F6dPil5yO+QCbMwHpDSGid8KLrDwnDocQHrg8QjBCIeDwnHwmFNv2kXPfHFTAfOAwR.nMGfn0vaQdBSSrumeOCGL.aeLXsvHgTn7hKpUjYUiwrl210w1kRhoD2gEFhDPzzQtdjEENwSf8nBijvdTL1ayHiwQuuO3XcOW6vM7F3ZETnew4e77y0eQSvexGCeBeG7Q7C2mdp9f1rfpfVnDZ1mMTMDpFCZVqGfxtPO0ZCqUIxPsRjQvuCq.eVQr1iOin.PqXIFqoUjup3r1xiAph.Tkh7kDClCPM7IgXPidF86ioNlQTiwIxdAs7PkEjVERMcZgdALJCUz8BHezGKBvDquYlkyIZvMbPDWHFuqSJHh+D2GSBNCAkKr9s71K.nAVJWZA2XhvEoATADQ.74LgFDA.ulfXbkVLvMXBZIRroeL8THDlrDKJBYgEzp.wHgbJPjDqE56Y6FVbBhNfic81s7dXAq1LB1wyzvgXAdgbhwpcowhwVZrfpXHeFeZQ9DL7KDcr37yIlHWVH2U.dC.eMBCHHewOAVCf.RAz6K0..TWXrEkoTXycFfDSTr7TDVcARg3uwiIin5lo9aTKO8HoA3QlHIFMJVT.lf7oQ7oFZaKQ0wK1nQLxc7EORN4hxIfhQojfh4b10PXKv.AiGEaWkIoRjQBzGKoGabWmOtqNUwjvr4xj6z3t60nUyGNoT.RreeCnrTF+KVK3ayUa8Ix6WfUcRwR.z5SAZcFT8o.UmAs4Tf1DDNOISMkITYEf0AnIsfR45.rt2XF.k07tMvPC.nwiRbxh0RzeFrHMXVqT4XulXzfPMUF1ERglzhI7ndHLQobtNYQcIrrlJIUOgjrvfd6YL7Aw1eQD40RkSuTDwWRNe9XyCNIIC2JhoRViEh.KQl9SkLalL897fxbQmbwAWSLdlrStxfERiXQIGWzVikNYcHk3v0EUWA4ZVOxm9Ik3liLvwLdD7xb30Ev4rNCbrh4IBaRFBwk4jANME3DwfSPETWKYxTKEBQVurpU1oEoUC8V6r+clzb1xNHrRACrxEH9Ra3y1xgerFhZtgfPq8vDUJFSxXD14njrHVCuJfMncGcUqQY55z0NjWMEKWNPuRKTaJTA1GSxm+Vx8TOoZL7iXXGSGE.fdTd87kxWC9sN7ay7eApKw7PENFKRGwB7iebbvcbae8ezw.ZyIkngKBP5oDo6hCw+LBMvDIUfjmLRACWhS0bQDl0shZAMNFafh8X4ABHVGrasMZrqdVE3XUQjpV3AyDBfXbOnVlE8wxr.3IR4BAK5Pc6f6fEJwsH41jB4Ki3GTj.lPYJ2QGn6Y+rqKIc5jmUIIiWCiDAmYcDhcdhkxTJtQlzqUaF89+QUDLgDx8ERfLnukQHkelCEhUhgcsCVD.XrnkuQmEM.bOgVjjXtOVFIn61N03mxRHcXHd1J0VGscXVgBqDLuTwHrqmF65Yfc8Dr0SisdB1BMJlFJF6lowtYFycSN1OguAoGmMGzpU9oQtM1L+zns6omeZDRicYfdRju6Aflsk7gTc.DkNro2fPPIUHRIUnCSw.0EiIoH3oW0goqIPHORaXuaT+4mqyhGY63Tywgq85fKb6N7CUMOiY6fq.uCIbPhKMV3Yb0DmepUSpYngaGHt5iJWpbIskJWZ4JeQIxxkHUX9BQDUzYgw1W07ycBrom9neU5RZvcLM197DmZFCjzVxDcWhH1EFF7L5qivuVi2SMd.0oLzDjvOpyaUelCIAI7CcdK8YNjDjvOZxa0blCIAI7CHeKuM9kQSWUYGR6Mophs0z34NB6cQ+TgLtLDHfetiozYcYYLC.W9wiRBP2v.rjfzbQoSwDTD3GL7.zMliXrnDm101raQNV3OOe7.hIOn3y63pvGHe.bq9FNN18C.iTrbBLcNPxweie3KQe9EbGPX3wbIlleBKpDn0yOowSBT87SZmj.sY9ILIdB+fDuLYu6dO8FxN+64MHfFc9zId+Tl2+T8n3QroKZhmkM0RTURV5FBL7TEJQQ5hJJIIyX9XBpLmpKi0RvEkQD.BkbkqPxN4AmrPt3TR1lNHqvlpSQiKPoDWVDNpgwYoYTs7tTJk5PBYLCaHrzqCGeKMXx0Yukm4vJfYZjw1SXoLOLjhh5ylK9P33LP8zLvj65gYxMwddDFhisimLEBBTim4LXcFJLdVdGQ7dmNmV+EiS0S3zLmN8RoOEBzjaZyUS9bM2T06RavpT5SlMSMu79w3p9YuisowCMmoHA9S5Joh8n7o8wb5ER6qzCc0uW+rcVic8NBJuhdqY3My1Syy2JGG1Ym82AJ4X7wHhBEuFrKnhSHqyHiRD1ptNrCBX+ewoJ7b22KjdWWdsiPcMjwAczQYBCuQIeOGGpelfwqYweVCrf6fdso9k32iPLhJ4tP5aVUc52rp7E+ZxufKID8b2ApR4t8otS65fUD2JF7s6sScPxgWGqnO.u9T+PajDxUmdhsIke4ryoVmFbbnWeFthqRSI2aDxf9lQWcKdt7J1VJ4tnJ66ZJCiuu7u4QUGkb446T8TaqvtIcXWsK0tSWo6c+gU4EIpa+0otidduMY2TQp96HeW7IYdwWKvxUtoVYs0ztwZR.pLFjjZJ4SQNUIV8slNqxsBkY0Zxr5xiwpU+xIX0FUSeKuJ49P0ocKuR7Ii5KeyadiUVaoIY3UWc4kVa0aNNCWob4kWa4JqrVEkrjue+syV99NUkEO7UtxZqr7Jqpz2vGDQRxpXsuhTmymV.xbhYBvWSE2DyTEe2ksvfxPER2oLlUS0pGAVto4fBfvztiaO1pBSN8nPEJ3cYD+zD9gffqKQvO8frIXHW3YGBVWhfAeqLIXXWfmcH3lxR3uLaBFxB9Jmfm7op7NpwOiC4WNC99hD.ff9odtJ3SRwMvNbjri1OXOmlmWR7RpGXGZ1MaZ7bYPiPpgWEzn3QH8lpMN5HXq5ID3ET25AuZdwQxK+GvW9WW8yMNgxdYNrE+WvZeDdF42g5R8QYm1Ld.Ye6y6CHS449AjcWyPfDZ4a3Fz2KfpIMGOUm1ytEXbFH263inRliPtWk5zvAtolZQWovBEEPEi8jv6hUi5rhrUL3ljZxf1olo8rGJ2rgK5zoSAN25tAlffAkyolvAPgaeN5TKMu+SotqH281F9VfNzTdMzwCb4ftFokfRcmh.yc9Y8n6zdIezcu1YtGc2OABjk5cANWDMpa2qexy5jQiuqnSRTuocT2yy0qeWOW6TlEMovVi5zglxZKSFh+PGROV1sNkTD2erJ+UR.xI5KorP6E9MRlo958U4jK+Qd8S2DPm+UaBnTxyKEkBXKG5P1y8iQe+RVaw6+KSSqy8BXZsgceOGC+ojaMKqrsgXJoCLaZDMju4O8g+lphSiPN.3DVl+1piaSxWnco.+LY2aNv+jHre5+5e7c2lsnx8pz5u8cQKSp9wk+GL68ejKPHqPOuq5AdNi3Z6srcBo72j7bp7Fyp3.Eks7oe0.pqYj9i7691+b0OSV9mVM89U+rAPUpos9ElP+25Y7LhzbgmS2Wv8HhoH+3me3s4T5OSMw+8hp7GU8qfjASX3OoaB9SJe5p+0A+gpY57MaWcV5kzt5O8WuyUdZZWcxk9K+9pML8d0kAR84zt3Mky.cFLsyaEQebsvYOB7MTYp+ypxu2VM5cLdVU.9VpBeiyphvKwJp9rc0YefpHcCACye1lVeK0O6rMAh6oa3YaR78TgMfWgvJIm7iRM4J7GMRm8LfjwCgDN6Onmt2.eSJPkt3+irf9xcN7RK3swCkOGau7TWKVi+M7i.nF1Nm.nVDv+mrF8LL88NzjeIOXpyKx5A3aW1+Y.mScOrMQSgcwOxBydvV+OzzL8TMw.q7xNvkdYG3xurCbkW1At5K6.uwK6.u4ydf3IyTaPnWOtughxdGzfcqY4xwOJKlahx+AkFwJS.
      

      Full script:

      Content.makeFrontInterface(400, 200);
      Content.setUseHighResolutionForPanels(true);
      
      const pnlEnv = Content.getComponent("pnlEnv"); // Fixed size 130x42
      const env = Synth.getModulator("EnvAmp"); // AHDSR module
      
      pnlEnv.set("allowCallbacks", "Clicks, Hover & Dragging");
      
      // Reusable path for drawing the envelope
      const envPath = Content.createPath();
      const stroke = { Thickness: 1.0 };
      
      // Labels
      const lblA = Content.getComponent("lblA");
      const lblD = Content.getComponent("lblD");
      const lblS = Content.getComponent("lblS");
      const lblR = Content.getComponent("lblR");
      const lbl_MAX = 50.0;
      
      // AHDSR attributes
      const IDX_A = env.getAttributeIndex("Attack");
      const IDX_D = env.getAttributeIndex("Decay");
      const IDX_S = env.getAttributeIndex("Sustain");
      const IDX_R = env.getAttributeIndex("Release");
      
      // Time ranges for Attack, Decay, Release
      const MIN_MS = 1.0;
      const MAX_MS = 2000.0;
      
      // Sustain in dB
      const SUSTAIN_DB_MIN = -100.0;
      const SUSTAIN_DB_MAX = 0.0;
      
      // Fixed pixel coords
      const PANEL_W = 130.0;
      const PANEL_H = 42.0;
      const ENV_X0 = 7.0;
      const ENV_Y0 = 7.0;
      const ENV_X1 = 123.0;
      const ENV_Y1 = 35.0;
      
      // Handle min/max values
      const X_ATTACK_MIN = 7.0;
      const X_ATTACK_MAX = 30.0;
      const X_DECAY_SPAN = 30.0;
      const X_DECAY_MAX = 60.0;
      const X_SUSTAIN = 90.0;
      const X_RELEASE_MIN = 90.0;
      const X_RELEASE_MAX = 120.0;
      
      const BALL = 5.0; // Handle radius
      const BALL_2 = BALL * 2; // Handle doubled
      
      //! HELPERS
      
      function clamp(x, a, b) { if (x < a) return a else if (x > b) return b else return x; }
      
      // Normalize panel coords (0..1) for Path
      inline function nx(x) { return x / PANEL_W; }
      inline function ny(y) { return y / PANEL_H; }
      
      inline function primeUnitBounds(p)
      {
      	p.clear();
      	p.startNewSubPath(0.0, 0.0);
      	p.startNewSubPath(1.0, 1.0);
      }
      
      inline function pathLineAbs(p, x1, y1, x2, y2)
      {
      	p.startNewSubPath(nx(x1), ny(y1));
      	p.lineTo(nx(x2), ny(y2));
      }
      
      // Linear time mapping for Attack, Decay, Release
      inline function msToNormForDraw(ms)
      {
      	if (ms <= MIN_MS) return 0.0;
      	return clamp((ms - MIN_MS) / (MAX_MS - MIN_MS), 0.0, 1.0);
      }
      
      inline function normToMsForModule(n)
      {
      	if (n <= 0.0) return MIN_MS;
      	return MIN_MS + clamp(n, 0.0, 1.0) * (MAX_MS - MIN_MS);
      }
      
      // Skewed mapping for Sustain (-12 dB at mid-point)
      inline function sustainDbToY(db)
      {
      	local d = clamp(db, SUSTAIN_DB_MIN, SUSTAIN_DB_MAX);
      
      	if (d >= -12.0)
      		local n = 0.5 + (d + 12.0) / 12.0 * 0.5;
      	else
      		local n = (d - SUSTAIN_DB_MIN) / (-12.0 - SUSTAIN_DB_MIN) * 0.5;
      
      	return ENV_Y1 - (ENV_Y1 - ENV_Y0) * n;
      }
      
      inline function yToSustainDb(y)
      {
      	local yy = clamp(y, ENV_Y0, ENV_Y1);
      	local n = (ENV_Y1 - yy) / (ENV_Y1 - ENV_Y0);
      
      	if (n >= 0.5)
      		return -12.0 + (n - 0.5) / 0.5 * 12.0;
      	else
      		return SUSTAIN_DB_MIN + (n / 0.5) * (-12.0 - SUSTAIN_DB_MIN);
      }
      
      //! GEOMETRY
      
      inline function getVals()
      {
      	return {
      		A: env.getAttribute(IDX_A),
      		D: env.getAttribute(IDX_D),
      		S: env.getAttribute(IDX_S),
      		R: env.getAttribute(IDX_R)
      	};
      }
      
      inline function computePoints()
      {
      	local v = getVals();
      
      	local aNorm = msToNormForDraw(v.A);
      	local attackX = X_ATTACK_MIN + aNorm * (X_ATTACK_MAX - X_ATTACK_MIN);
      
      	local sustainY = sustainDbToY(v.S);
      
      	local dNorm = msToNormForDraw(v.D);
      	local decayMaxX = clamp(attackX + X_DECAY_SPAN, attackX, X_DECAY_MAX);
      	local decayX = attackX + dNorm * (decayMaxX - attackX);
      
      	local rNorm = msToNormForDraw(v.R);
      	local releaseX = X_RELEASE_MIN + rNorm * (X_RELEASE_MAX - X_RELEASE_MIN);
      
      	return {
      		start: { x: ENV_X0, y: ENV_Y1 },
      		A: { x: attackX, y: ENV_Y0 },
      		D: { x: decayX, y: sustainY },
      		S: { x: X_SUSTAIN, y: sustainY },
      		R: { x: releaseX, y: ENV_Y1 },
      		end: { x: ENV_X1, y: ENV_Y1 }
      	};
      }
      
      //! HIT TESTING
      
      inline function dist2(ax, ay, bx, by)
      {
      	local dx = ax - bx;
      	local dy = ay - by;
      	return dx*dx + dy*dy;
      }
      
      inline function hitHandle(p, x, y)
      {
      	local best = "";
      	local bestD = BALL * BALL;
      	local keys = ["S","A","D","R"];
      
      	for (k in keys)
      	{
      		local h = p[k];
      		local d = dist2(x, y, h.x, h.y);
      		if (d <= bestD)
      		{
      			bestD = d;
      			best = k;
      		}
      	}
      	return best;
      }
      
      //! LABELS
      
      inline function pad2(n)
      {
      	local s = "" + Math.round(n);
      	return (s.length == 1) ? ("0" + s) : s;
      }
      
      inline function msToUi(ms)
      {
      	if (ms <= MIN_MS) return 0;
      	local n = (ms - MIN_MS) / (MAX_MS - MIN_MS);
      	return clamp(Math.round(clamp(n, 0.0, 1.0) * lbl_MAX), 0, lbl_MAX);
      }
      
      inline function dbToUi(db)
      {
      	local d = clamp(db, SUSTAIN_DB_MIN, SUSTAIN_DB_MAX);
      
      	if (d >= -12.0)
      		local n = 0.5 + (d + 12.0) / 12.0 * 0.5;
      	else
      		local n = (d - SUSTAIN_DB_MIN) / (-12.0 - SUSTAIN_DB_MIN) * 0.5;
      
      	return clamp(Math.round(n * lbl_MAX), 0, lbl_MAX);
      }
      
      inline function updateLabels()
      {
      	if (this.data.drag.active) {
      		local v = getVals();
      		lblA.set("text", "A:" + pad2(msToUi(v.A)));
      		lblD.set("text", "D:" + pad2(msToUi(v.D)));
      		lblS.set("text", "S:" + pad2(dbToUi(v.S)));
      		lblR.set("text", "R:" + pad2(msToUi(v.R)));
      	} else {
      		lblA.set("text", "ATT");
      		lblD.set("text", "DEC");
      		lblS.set("text", "SUS");
      		lblR.set("text", "REL");
      	}
      }
      
      //! PAINT
      
      pnlEnv.setPaintRoutine(function(g)
      {
      	// Draw background and border
      	g.fillAll(this.get("bgColour"));
      	g.setColour(this.get("textColour"));
      	g.drawRoundedRectangle([0,0,130,42], 4, 2);
      
      	// Draw envelope path
      	var p = computePoints();
      	primeUnitBounds(envPath);
      	pathLineAbs(envPath, p.start.x, p.start.y, p.A.x, p.A.y);
      	pathLineAbs(envPath, p.A.x, p.A.y, p.D.x, p.D.y);
      	pathLineAbs(envPath, p.D.x, p.D.y, p.S.x, p.S.y);
      	pathLineAbs(envPath, p.S.x, p.S.y, p.R.x, p.R.y);
      	pathLineAbs(envPath, p.R.x, p.R.y, p.end.x, p.end.y);
      	g.setColour(this.get("itemColour"));
      	g.drawPath(envPath, this.getLocalBounds(0), stroke);
      
      	// Draw handles
      	inline function drawBall(key, x, y)
      	{
      	    if (key == this.data.drag.which)
      	        g.setColour(this.get("itemColour"));
      	    else
      	        g.setColour(this.get("itemColour2"));
      	
      	    g.fillEllipse([x - BALL, y - BALL, BALL_2, BALL_2]);
      	}
      	
      	drawBall("A", p.A.x, p.A.y);
      	drawBall("D", p.D.x, p.D.y);
      	drawBall("S", p.S.x, p.S.y);
      	drawBall("R", p.R.x, p.R.y);
      });
      
      //! MOUSE
      
      pnlEnv.setMouseCallback(function(e)
      {
      	var p = computePoints();
      
      	if (e.clicked)
      	{
      		this.data.drag.which  = hitHandle(p, e.x, e.y);
      		this.data.drag.active = (this.data.drag.which != "");
      	}
      
      	if (e.drag && this.data.drag.active)
      	{
      		var w = this.data.drag.which;
      
      		if (w == "A")
      		{
      			var x = clamp(e.x, X_ATTACK_MIN, X_ATTACK_MAX);
      			var n = (x - X_ATTACK_MIN) / (X_ATTACK_MAX - X_ATTACK_MIN);
      			env.setAttribute(IDX_A, normToMsForModule(n));
      		}
      		else if (w == "D")
      		{
      			var decayMaxX = clamp(p.A.x + X_DECAY_SPAN, p.A.x, X_DECAY_MAX);
      			var x = clamp(e.x, p.A.x, decayMaxX);
      			var n = (x - p.A.x) / (decayMaxX - p.A.x);
      			env.setAttribute(IDX_D, normToMsForModule(n));
      		}
      		else if (w == "S")
      		{
      			env.setAttribute(IDX_S, yToSustainDb(e.y));
      		}
      		else if (w == "R")
      		{	
      			var x = clamp(e.x, X_RELEASE_MIN, X_RELEASE_MAX);
      			var n = (x - X_RELEASE_MIN) / (X_RELEASE_MAX - X_RELEASE_MIN);
      			env.setAttribute(IDX_R, normToMsForModule(n));
      		}
      
      		updateLabels();
      		this.repaint();
      	}
      
      	if (e.mouseUp)
      	{
      		this.data.drag.active = false;
      		this.data.drag.which  = "";
      		updateLabels();
      		this.repaint();
      	}
      });
      
      //! INIT
      
      updateLabels();
      pnlEnv.data.drag = { active:false, which:"" };
      
      
      posted in Scripting
      dannytaurusD
      dannytaurus
    • RE: MIDI device reselect bug?

      @Chazrox Could you try the PR please? Do you see the same as me, or the same as @David-Healey?

      posted in Bug Reports
      dannytaurusD
      dannytaurus
    • RE: MIDI device reselect bug?

      @David-Healey Interesting. USB MIDI keyboard? Or USB MIDI interface with 5-pin MIDI keyboard attached?

      posted in Bug Reports
      dannytaurusD
      dannytaurus
    • RE: MIDI device reselect bug?

      @David-Healey Ok, I'll look at the channel issue when I get back home. I'm working in Starbu7cks right now and it's too nerdy, even for me, to carry a MIDI controller around with me.

      Or is it? 🤔 😂

      Anyway, the issue I had was, if my MIDI controller was checked in settings then I relaunch HISE, it would still be checked in settings but not responsive until I manually toggled the check box.

      The PR fixes this issue for me. Can you confirm that? Or are you seeing different behaviour?

      posted in Bug Reports
      dannytaurusD
      dannytaurus
    • RE: Goals for 2026? 🚀

      @David-Healey Yeah, a few people commented on that. I used Screenflow to do that video. Easy to do that effect.

      I use Motion for demo videos now, so I can get a bit more into audio-reactivity. Screenflow doesn't have that at all.

      To be clear - the audio waveform animation in the background was created with VideoBolt, not in Screenflow itself. That's why I'm moving to Motion, because it can do those sorts of audio animations natively.

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Goals for 2026? 🚀

      @David-Healey Example ad video here: https://wmd.d.pr/v/qVq1KN

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Goals for 2026? 🚀

      @David-Healey I just made square videos for all my launch videos. My launch videos are all simple animations of the plugin sliding in and out with different presets playing audio in the background.

      No human face, no talking, no sales, no discounts, no sensationalism. Just basic product demos.

      Some are way too long (4 minutes) and I don't think Meta pushes those ones very much, but the others seem to do well. And when folks land on my site they tend to buy extra related products too.

      To be honest I haven't looked at my Meta ads dashboard for about 4 months. I really should do that! But I know the ads are showing because Meta charges me every other day, and the uptick in revenue is consistent.

      Some people would live in that dashboard, tweaking ads and launching more campaigns, but my goal is to just put my plugins in front of the right people and let them discover the rest for themselves.

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: MIDI device reselect bug?

      @David-Healey Here you go: https://github.com/christophhart/HISE/pull/842

      I don't know about the channel resetting bug. Is that the same thing, or tangential?

      posted in Bug Reports
      dannytaurusD
      dannytaurus
    • RE: Goals for 2026? 🚀

      @David-Healey @ustk Building an email list was key for me. I don't post my new products on social media anymore. Just send out to my 35k email list. I built my list with free products and a lot of social media interaction. I don't do any of that anymore either.

      Also started Instagram ads. The latent revenue from 'old' products went up 5-10x, even with the daily ad spend accounted for.

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Goals for 2026? 🚀

      @David-Healey More course - yeah! 🙌

      Moonrise does look interesting, but I'm not using any protection on my plugins for now so I don't think it would be worth it for me. Plus, some of my products are only $5 so the 1€ per sale would hit me pretty hard

      I've been reading your Rhapsody codebase to get some general code organisation tips. Very cool stuff! Looking forward to seeing what you do with it.

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: MIDI device reselect bug?

      @David-Healey @Chazrox Okay, excellent. I just made a fix so I'll create a PR 👍

      posted in Bug Reports
      dannytaurusD
      dannytaurus
    • MIDI device reselect bug?

      Does this happen to everyone, or is it particular to my setup?

      • I have a USB MIDI controller (Arturia MicroLab) connected to my laptop
      • It's checked in the HISE settings, under MIDI settings
      • But every time I launch HISE, I have to go to settings and uncheck/recheck for it to work

      Curious to know if it's just me or it happens to everyone before I go on a bug hunt! 😜

      posted in Bug Reports
      dannytaurusD
      dannytaurus
    • RE: Goals for 2026? 🚀

      Oh, and bonus goal for me is to move away from Gumroad to my own custom e-commerce site!

      posted in General Questions
      dannytaurusD
      dannytaurus
    • Goals for 2026? 🚀

      Anyone care to share their overall plans and goals for the coming year? 🚀

      My main goal is to start releasing HISE plugins. I've been learning HISE for a while and it's time to start exporting my efforts!

      1. A series of 4 free synth plugins, first one Sublime posted here for design feedback, and another 3, each based around one simple preset concept. Sublime is all about bass.

      2. Then I have 2 collaborations I want to work on, both with UK house music producers. One is a multi-output drum plugin based on a series of expansions, the other is a chord synth with some interesting features.

      3. I also have a lot of vintage reverb impulses recorded and processed, which I'd like to turn into a suite of free reverbs.

      My user base is mostly house music producers & related genres - rave, techno, classic house, etc. I've built a decent brand and I think my customers will love the move from Maize-based ROMpler plugins to way more fully-featured HISE-based plugins.

      What are your goals?

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Errors when saving and loading XML

      @JC Not putting HISE projects in cloud-synced folders is a good tip!

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Sending Midi Out from Sliders (Instrument Plugin)

      @bendurso That makes sense too. Reaper is way more configurable than a lot of other DAWs.

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Design feedback - velocity indicators

      @David-Healey Cheers. Yeah, tooltip on the V button for sure. A different one for each button too, to describe what it's doing.

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Design feedback - velocity indicators

      @Bolle Thanks! 🙌

      posted in General Questions
      dannytaurusD
      dannytaurus
    • Design feedback - velocity indicators

      This is (or at least it started as) a simple, free bass synth called Sublime.

      As feature-creep always dictates, I've added more stuff than I intended, and afraid it's getting too busy for the small size.

      The thing I'm working on now are the velocity switches and arc indicators around the relevant knobs.

      Here, all velocity switches are active for the 5 available knobs:

      Sublime-Velocity-Active@2x.png

      And here's the same with all velocity switches inactive:

      Sublime-Velocity-Inactive@2x.png

      Does it make sense? The velocity arcs are drawn inside the main value arc, and are scaled within the arc value. So, if the knob is at 50% and the current velocity is 64, the velocity arc will be 25% of the full arc.

      Does it all make the UI look too busy?

      posted in General Questions
      dannytaurusD
      dannytaurus
    • RE: Is GitHub a good solution to distribute free products?

      @Christoph-Hart Agreed. Sorry, I kinda cut myself off short there. Edited for clarity.

      posted in General Questions
      dannytaurusD
      dannytaurus