Just wanted to wish everyone a happy, productive and prosperous new year!
Just wanted to wish everyone a happy, productive and prosperous new year!
Until you spend hours debugging an inaudible filter node because Claude set the smoothing to 20 seconds instead of 20ms! 
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!
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.
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.
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?
I like using overlay images to ensure my Figma design is translated properly to HISE. Currently, the only way I know to toggle the image visibility is to select/unselect the image, or quickly slide the alpha slider, which is difficult because of the 'invert' half of the slider.
This PR adds a toggle button between the image dropdown and the alpha slider. It uses an existing image icon for the button and respects the alpha slider value.
This allows me to toggle the image without taking my eyes off the interface, making it easier to spot changes.
PR here: https://github.com/christophhart/HISE/pull/825

@David-Healey I just had a go at fixing this. Is that what you mean?

HiseSnippet 1112.3ocsVs2aaaCDmJIJKwacqEne.H7e4roYH+pIcACMO8pwxCi4rhMDDTPKcxhKRjFRTMwXneH12z8MH6ndXKO6klZfI.av6Eue2wi2w9QRGHNVFQLpb0jw.w3qLGLQn7O1mwEjdmPL9ZyyYwJHhlw5nIiYwwfKwvX8eRyvX6MHoe+8aNhEvDNvLVDx6jbG3LdHWMia+C9YdPPWlKbEOrj1sOnmiTbrLPlf3YcSaxXlysrQvELsZqYRdKK1mX7sl1scX60zqSqVu9061wcH330.FtqCytCyqCC41l0tSi1DiMO0kqjQCTLEDia5QR2IC7k2Ixbv63w7gAflnAY.54L1ji84At8KRNwDhwF8mkpVOKU8Ryy4t7o7mkxddp.5LKJmzLV6wfTiOCHYTBRajAoWXNvIhOVMShFOeoYOAdB5wvylxPISWxZ+05lGKQMDp5gragtQHwTKp0z11hh+sy9UpfmOwJZ.yi9izBSbh.LRNS5vBNSJu8PgaW.BpoUGUrdDLhqqe5lHbTbonVU2H1c8kiSFeNHRNBOhGEISDtUsndE5LxhJG9G6T4OqPwuQ0iAUVcQsp12am+UEcQlXOrd5W.GUsqssrsz.F+cCJ9iOQTzSAg+29+CrHJCiXjUcFFs3dVvdLy8PjCJ7Z1012P+NZSKJ65FSW07F52SaqW0Jc0M6uPHo2Vd7a4i7CveJvk9FZln35ih.PP+gozCCRf4CacpCb0QOSLJ.pkiHK5d6TBmJ3dUAPy0HCt6YUDCHnmsNE1Md0LFstYIHu.U24yUyfEJuKVaTq5IfGKIPgI1FsqaOUtNyeHFpBv8JDVowuFeVSQoEsZ.3opVbBlU1crLbn7H48MJU7MRikvwRAnc3TMzVNkPCnEJOwhhc1u37lJEWHUvkhZ5i7sq7wJz+sHOukJSiiHYP.DsTw5FbQOlg0DIgCgHK7PRexVnHdgd9tDa9z5R3jkVJonTzSvUWNFxo6JCb0290qWrmBIOup6tjiPTUUZukmm2aoHuR3t5VKSSyjzPnbyexu16DlhUrY39h9ZLDo35Px3D3C3vgrFWaadBDeqRNF6yO8.kXrUlqeVQaMl.BR86VloqaPturCmTl.KICKFlr8lDxCOLO2lkYeG2U4OyZ9A9f9tXYNjR35KdhoDDclFMyPlowKwEgrTdqunO+8CzXCSLei4kBnxU2IqbkOd8GGXtPedbBizMIfoleridfbt.rJatd8594hXtZR4A1eFyhrezYQOUH9By9bki+xw3ZKAiXsy+GXLeB9yLO0yC6bNCfaX182V0w0eB2icpUbwnyYpHttF3hjvAXYnCfdWf0xw55h0z2Ayns0z5Lv.P3lR7.9kKrgl1HWXiBgX0kSj78NY2b0uQXqTNHlDougZa7wbHMcIWVCwmr7dGm42pELr4pZXqU0v1qpgcVUCe0pZ3tqpg68oMT+hxCSTxvrqMDx48OMs4pgwoBFVAlVsR9GztgJYG
Content.makeFrontInterface(200, 200);
const laf = Content.createLocalLookAndFeel();
laf.registerFunction("drawPopupMenuBackground", function(g, obj)
{
g.setColour("0x00000000"); // any transparent colour
g.fillRect([0,0,200,200]);
});
laf.registerFunction("drawPopupMenuItem", function(g, obj)
{
var a = obj.area;
var padArea = [a[0] + 2, a[1] + 2, a[2] - 4, a[3] - 4];
g.setColour(obj.isHighlighted ? Colours.green : Colours.blue);
g.fillRoundedRectangle(padArea, 8);
var textArea = [padArea[0] + 8, padArea[1], padArea[2] - 16, padArea[3]];
g.setColour(Colours.white);
g.setFont("Default", 14.0);
g.drawAlignedText(obj.text, textArea, "left");
});
const ComboBox1 = Content.getComponent("ComboBox1");
ComboBox1.setLocalLookAndFeel(laf);
The drawPopupMenuBackground object should probably include an area, and the popup menu items still have a subtle drop shadow. But they're both fixes for another day.
PR here, if it's useful: https://github.com/christophhart/HISE/pull/805
@bendurso Today I learned that right-clicking a module in edit mode shows a different context menu to right-clicking not in edit mode. 
Posting this in case it helps anyone else. I just banged my head against a brick wall for too long before I realised how simple this was! 
When using a Floating Tile with content type Waveform (to display the waveform of Sine Wave Generator or Waveform Generator, for example) the default waveform path is a filled shape.
You can override this with LAF function drawAnalyserPath and draw a line path instead of a filled path:
laf.registerFunction("drawAnalyserPath", function(g, obj)
{
g.setColour(Colours.white);
g.drawPath(obj.path, obj.area, 5);
});
However, this means that the path is clipped at the bounds of the floating tile, especially at wider line thicknesses:

To prevent the clipping, I fudged around with it for longer than I want to admit before I realised the answer is to simply reduce the area that the path is drawn in, by half the thickness of the path:
laf.registerFunction("drawAnalyserPath", function(g, obj)
{
g.setColour(Colours.white);
g.drawPath(obj.path, obj.area.reduced(2.5), 5);
});
Voila! No more clipped paths!
Top row is using obj.area, bottom row is using area reduced by half line thickness:

You might want the left/right of the path to bleed out of bounds, in which case change the reduction from all-round to y-only:
obj.area.reduced(5) π all-round
obj.area.reduced(0, 5) π y-only
Note: you might need to compile with HISE_USE_SCRIPT_RECTANGLE_OBJECT=1 for the reduced and other Rectangle helper functions, as per the docs: https://docs.hise.dev/scripting/scripting-api/rectangle/index.html. Not sure if it's still the same, or if it's built-in to all new builds.
@Chazrox said in MEDIA BROWSER PLUGIN [NOT A HISE PLUGIN - but may be useful]:
The forum has definitely been less active since everyone has found their agentic work flows.
I noticed that too. Bit sad really. Maybe we should all start sharing more wins we have with AI?
I just went down the Windows installer and code signing rabbit hole for my synth plugin and came out the other side with a decision I didn't expect: no installer at all.
TLDR: if your plugin is one file going to one folder, a ZIP with clear instructions gives your users a smoother, less alarming experience than an unsigned installer, and costs you nothing.
Sharing the findings here in case it saves someone else a day of research.
My plugin is a single VST3 on Windows. Bundled presets/images/fonts/audio assets (for simple Audio Loop Players). That means one file, one destination folder. So the installer would exist mostly for polish, not necessity.
Here's why I dropped it.
The problem: an installer is an .exe, and an unsigned .exe looks scary
If you ship an unsigned installer, SmartScreen will greet your users with the "Windows protected your PC" screen, and they have to click "More info" then "Run anyway" to proceed. I'm sure most Windows users, especially music producers, are used to this, but for a paid product from a developer they've never heard of, that's bad optics. I'd argue worse than no installer at all.
Option 1: Azure Trusted Signing. Blocked for me.
This is the modern route everyone recommends, and it's cheap. But it's only available to individuals in the US and Canada. In the UK you need a registered (Limited) company. I'm still a sole trader with no Ltd, and I'm not registering a company and wading through Azure bureaucracy just to unblock a release. Registering is on the roadmap but not worth bumping it up for this.
Option 2: An individual code signing cert. Possible, but underwhelming.
There is a middle path: Individual Validation (IV) certs. SSL.com and Certum both sell these to individuals with no company required, verified via passport and a face scan, turnaround in days not weeks. Certum even has a "Cloud CODE Signing for Individual Developer" product that a company literally cannot buy.
But here's the catch that killed it for me: signing removes the "Unknown publisher" label, but SmartScreen reputation still builds up gradually per certificate. A fresh cert with no reputation can still trigger warnings. So you pay, you do the ID verification dance, and your users may still see scary screens for a while. And from March 2026 the CA/B Forum caps code signing cert validity at 458 days, so this becomes a recurring chore, not a one-off.
The realisation: no .exe, no problem
SmartScreen cares about executables. A ZIP containing a .vst3 and a text file doesn't trigger any of this.
So the Windows release is:
That's the whole install. VST3 has one canonical system folder, so there's no per-DAW path confusion like the old VST2 days. I shipped earlier plugins as VST2/VST3 and had some support tickets, but those were usually because of the VST2 confusion. Oh, and I'm clearly not doing AAX either - another axis of complexity avoided.
The installer isn't dead, just deferred
When I register as a company, I'll 100% ship an Azure cloud-signed installer. Shipping an unsigned one in the meantime would be a downgrade from the ZIP.
One extra risk: the ever-annoying Anti-Virus checks on Windows, and two practical mitigations. [1] Submit the ZIP and the .vst3 to Microsoft's file-submission portal once the release build is final (it whitelists the hash and hugely reduces the block-at-first-sight risk), and [2] run the final binary through VirusTotal before release so I know which of the ~70 engines flag it, if any. Both are free and take minutes.
Very open to having my mind changed here, but given the fact that I've been distributing my previous (non-HISE) plugins for 3 years on Windows via the ZIP > extract > copy to folder method, I think this is a no-brainer approach for my first couple of self-contained HISE plugins.
@David-Healey In a conversation with ChatGPT today, it said to me
Your mockup surprised meβI expected to dislike it. I don't.
AI is getting cheekier! 
@ustk As per @Christoph-Hart 's suggestion, updated the PR to use a noise burst instead of sine burst.
Re-ran tests and it all checks out.
I noticed my 'centred' knob labels were shifted 1-2px to the left and it turns out that letter spacing adds extra space after the last character, which shifts the whole text left.
Wider letter spacing = further shift to the left.
Claude says it expected JUCE behaviour. Expected, maybe, but not cool. 
Notice how the first row (zero spacing) is centred, then the text shifts progressively further left as the spacing increases. The last 2 rows show 2 different fixes that Claude suggested. No idea how robust the fixes are. They're in the snippet at the bottom.
During this, Claude found 2 HISE bugs. I'm still unpacking so I can submit bug fixes. Links to PR fixes in next post.

1. Centred text with
setFontWithSpacingdrifts left (JUCE behaviour)
setFontWithSpacingmaps toFont::setExtraKerningFactor, and JUCE addsspacing Γ heightafter every glyph, including the last one.drawAlignedText(..., "centred")centres the advance box, which therefore has an invisible trailing gap, so the visible glyphs end upspacing Γ height / 2px left of centre. Small at typical values (0.075 Γ 15 px β 0.6 px) but visible on all-caps labels under a knob. Fine, that's how JUCE works, but the obvious fixes both fell over because of 2 and 3.2.
"Default"ignores the font size
g.setFont("Default", 30)andg.setFontWithSpacing("Default", 30, x)do not draw at 30 px.MainController::getFontFromStringreturnsglobalFontunchanged for"Default"(hi_core/hi_core/MainController.cpp~line 2035), so the size argument is dropped and you get the global font at its own height (~14 px). No error, no warning. Every other font name goes throughFont(typeface).withHeight(fontSize). I'd expectglobalFont.withHeight(fontSize)here.3.
g.getStringWidthdoesn't measure the font that was set
getStringWidthdoesn't ask the currentFontfor its width; it looks up a per-character normalised width table (CustomTypeFace::getStringWidthFloat,MainController.h~line 2318) for the current font name, and if the name isn't aloadFontAsfont it falls back todefaultFont's table β then multiplies by the requested size. So with"Default"you get a different typeface's widths at a size that isn't being drawn. In my test the returned width was ~2.5Γ the rendered width. Combined with 2, both "shift by half the gap" and "measure and left-align" corrections came out wrong until I switched to aloadFontAsfont.Suggestion:
getStringWidthcould just usecurrentFont.getStringWidthFloat(text)(theFontobject is right there insetFontWithSpacing), which would honour size, kerning and the real typeface.Repro β snippet below. Six rows: a centred white bar with
MMMMM"centred" beneath it at increasing spacing, then the last two rows apply the two corrections. SwapFONTto"Default"to see 2 and 3 (text renders ~14 px regardless ofSIZE,+measurerow lands far off).
HiseSnippet 2430.3ocsX8taaibDmJI5ZsZu16.5CvT8kRYSq+cxWbsqQtDG4F2KN1vxWR6EDDrhbo3VSsKA4RKqdHE8MnEnen.8S8wnnesuI2KP6av0Y1kThx1W9iAJMLf3ryL672e6v8jTkOOKSk5TqwYyS3N09w0GMWpi1OhIjNG9XmZ+j5Gwxz7TvR5QySXYY7.mZ0t6ulHTas64Xd9uO3QrXlzmujjiyyUBe9SESE5kTS9huTDGe.KfelXZEtG7EG5qj6qhU4n8b25ccRX9mylveFiX6N0cdBKKxo15060se.eK+A7PVP+9a6u01C3C5ELX6s51cPX+t9L1u79r6O1o1GMLPnUoizLMOCU5iTAyGEolIsavyEYhwwb5kdNivc1R1Y+HQbvIkAmLGmZ26jkgp6ZCU+r5GIBDKnuLj8IlEfkRTMnU6NuMSp2GfIUqhIcOqI8o0G4mJRzKWgrmeT8CkXFLjg4lplhkWm67u9o06zANkmjp1AlzNHkM6gwhIRdvY7K0tsa21CZ5yk5TdPyVPPpHTmAOc3AmAyh3RPGwgPkTCQrrFnlPgRYPLWia5lYXRTHm.tYb8AHSuPniFUPqCPT1YGbogjLeIOUhzOf4iAnVsQcQp6Dp9CDRsBTxCkBMnBAFDlxyhfmb3ng.Z3+dtu9WjQbYcTHy3b.SF.9poIhXNoO3XIGRXRdrGDJtfCopYYsggL+H5m6f5MSEKBfTTeL4jXNT33npMNZgvndI007H5oI5cymNkqSE9vj34IQdnZfLQ.eywbVJ4qrBNlChLXpPJlxhoXIalznnx3a49jgE8vLQfNBBDj0DOGFykblNpMbpZFzkB2PY3saoEkEoxiCfXA5n4I6ZzkIiASHeEUIpwRo91+zeEc67IQnxKnsdl3Ov6zGRtzDuNCEOFS.fdlxDrvHSBZDF8hlGGWpTaFUyvvcJYuBkDXIIwBL1spskIYIvXr2FxkAHxBopEw6cHFAL4bIzTlGLg2DLloFqpLbgZA8FToohIQZX70rbWTVbYUXHVW0ph5lxYY4onBI8Mo8DtdjlxMufhxtsnrRdlwZvZQQL4RSXId1jDVOGp2zpsq9vrcKPQXgp2xIK7RvkeIFA7wZVS9EUowf9ZkZpg0k0qt6qSi6r+z.XCXpJOiS8VbrDAK6KLbfMAgXxLaBokEwLrvOhkF.bLbksKPUqT9GqyXomW3P4kUxlVhwJLUYXuciF6iMg3RsmxNmePJ9xB3B2Ac65AeV2ts1sQCDbF26KXoPhLF1CJEiEDbB0T31DoaPQZ5AnXjPHk1XVvsooRFoOn6Jji3TRrY4drf93I1yAHMc4AGzuK8GYDna+s+8+w+4e9mgixQqYLmPBHrmXEdfR.bgfY9IAr7vLO3YGeFz7w3AE4w5lH5lEDB8xo1buMNpySk1L+jX0XVrUk4RphJ.eIcoNvVcjHfIbEFmM84jbmagtH0g0LTOdYWw+9uA+wdC7.oRWk1nC+5gsL3HWqTrLemALReIHJpOleQTQrYwBInY3YDVbv0CDgg7TLSrNDXMRi42FdDkjW1MZvliUpyQWZFllKZXW5YjexujYfZzQpLpqjkgB1tRHEX997DD+mYvsXiQ7RrXGwE0VTODAcNBXO0FCw.QHAEQ5tDyt.ttcigxI3ZsWpb2lcFYDtySEiSYoy6Pzy5LJGAR3SQejE24goBVbasNDKNZZp2HlZhUGKqPO33mclo0buprTkCJ9WvQ+t6Vdz.0gLmh31SCJyWHlL5PtHdq8zSpo75mm0ZwwByhD3AJknHaVTbTEYDU.ANNGba1DMAoRxwC7VZdmd7KFgzeYi09lRqXGnaarsx.lsCfhU77Fuqxz82x6cxT+2GMs0GHSk.1uUlV.C+lFupZF4oO7QCeZQNydrZ0UOc39m85WXVsWuAHRPAVwIHjn9TUtFqjbCyklvqKBy9MMVijaFJfNRjQ8XE.86ZWAyvOoxhOw.EgGCzwD7aGykSzQ3FsFU65JPV6tKHfe0JKChM1nE5qMVyny4HWBXcit2sfVYQzdFAeo3UsKnTx.c3zxEw2nEvpneyWs+P.QWyV4DNfER3.Ce9vS+ckCaHj9w4AzlnKNutDXxpoxYXFqtzL0.ShhbgcRyUNrifTptYsKLQZo8V3Iqa5dnPCo7QECLY.g7qbTt2Bzjh8mz1DJoYA2cInc6CkSvkBwOL3TTb2WNCSC8gMKS63KdXvcC3y8JH4Aa+pVkl.Mm50GgJLON1NulE0zqXjA6TGB8By4J8wtD5gmwG8J84BC7p1996aN2Zs0Dgl4Nf81aYANVWXJLHKb3UmC.TxhI.NeSABJZw0cYAWPeCUwqKmHAS.sH60jMzTQ80Ffwz+zBiYHujIs10Gk2vhGrH5pmsLxRmQMyy1UrI91qPzUZlmlF+6M3+73LdEWpnaeG6.Y1IeJpyLyosX9rHVbXoSzlPRvwryPmdg+XUvdKifVM2BdfovirUDC4c3SFk786JK99Eq2TT5VTPeAKNGKWI20z3XFzkgyJgC3J0hPAcb6JkKE0H85eiEFaadJV5pFbyx1nlnoV96MrN+OeOJ97.bIXCZYhFA9hGs7xAVmCSW8Fz06pYHxkLeEGNOQNZ1ES.5VoIvNrUqcpNMnGjDmmYRQapHaQO2nGqzQ4SlPVmYbwkeRTwfi2P+P2t19gapU1bH.Y3dWCy8UVYppss69101RfAJE+NT7UEeiUvUnmueweC9e44JXS6yTZ9wRWy4KMdSC3pKEFdiqQCKmphi4o23xzMgj91DzUlOcLO0yVptfQ7K+W85D9n2uqSv2N6dEFseZ8wI7h2OPEGPWS.86qe4CNEC+i+5qN7wLMitOhBZHe3.TZAYN0dL+BgO2d6DqU+w7ry0pDCuSSvYdPMT6GnMq9wk2cAUq5HvstQ8xOnv4RmZ0qQWRz7xeX.HQc9Q+kZ1qOxVcST7JnT9QDDMLE+cFhW+RS9j5GoBxiY5UuCG51sJV.yDqbwIz2Ggeafdd0a+5C3hc59VuXm2WS7SqehP6Gcy13ctAaDyQ++vFKtNrOt9P76P70KMv6U+fe6s8tudGaucfuIGwvy+nZimkOcDlo843tKw5mLpL4NTcp88tkkMi3x.yKeG9TrXO58ZEK1qbQmoL+T0q8s8ezEt8CMTPaRZtPx0peD8NzywzSVMNOUDHdsu+pp5ZB1+1J3mcaEbvsUvstsB942VAu+sUvse2BRWO6Cy0po11FGmiNYnADqVsgR5ndS0py+CyHjtw
This image shows the font set to "Default" which exposes the HISE bugs. The font size is ignored (point 2) and the width measurement is way off because it's measuring a different font size (bug 2).

@ustk It's a bug to do with 1/0 versus Yes/No.
Here's a PR fix: https://github.com/christophhart/HISE/pull/1023
@David-Healey said in HISE with Claude:
I'm not sure there is any security advantage to use a desktop app rather than a web one
I think he means if you run Claude on a dedicated machine there will be far less personal info on that machine to get leaked either way.
Deprecations in Xcode 27 Beta
The following items have been deprecated or removed:
The minimum supported deployment target on macOS for the C++ standard library has been increased to 11.0.
@David-Healey Claude says:
the libc++ minimum deployment target was raised to 11.0, which is a hard toolchain fact β a C++ codebase like HISE cannot target 10.14 or 10.15 from Xcode 27 regardless of distribution channel
So 10.13 to 10.15 etc are completely out for Xcode 27, but can it build for 11 (even if 12 is the minimum for App Store) is still an open question.
@David-Healey said in Why is macOS minimum 11.0? (And beware of Xcode 27!):
Where do you see this?
Xcode 27 Release Notes https://developer.apple.com/documentation/xcode-release-notes/xcode-27-release-notes
The relevant line is under the "Intel Deprecation" section (issue ID 162138432):
"Xcode 27 will only install and run on Apple silicon Macs. The macOS 27 SDK supports back deploying Universal (Intel and Apple Silicon) apps to macOS 12 and later. Intel development is still possible with macOS versions that support Rosetta like macOS 27."