What are the most important parts of C++ for coding plug-ins?
-
- KVRian
- 1194 posts since 28 May, 2010 from Finland
-
- KVRer
- 11 posts since 29 Apr, 2022
"My tip is very simple: Learn it by doing."
This is the way
This is the way
- KVRAF
- 14123 posts since 20 Nov, 2003 from Lost and Spaced
I got ChatGPT to code a 2 oscillator 1 filter, 1 LFO, & Chorus VST synth in C++. It didn't put any values in for the internals, but it was a great bare bones structure to learn from.
-
- KVRian
- 798 posts since 5 Oct, 2020
I'd be interested to know what you told chatgpt to get thisosiris wrote: Sun Feb 05, 2023 4:48 pm I got ChatGPT to code a 2 oscillator 1 filter, 1 LFO, & Chorus VST synth in C++. It didn't put any values in for the internals, but it was a great bare bones structure to learn from.
also what do you mean it didnt put any values in for the internals? like an lfo with no frequency value?
-
- KVRAF
- 4340 posts since 8 Mar, 2005
Be aware of ‘realtime safe’ code in realtime threads. Look up lock-free programming.
Avoid locks, malloc, logging, anything of that sort in a realtime thread. Use atomics wherever appropriate. The principles are the same across the programming languages, the execution and syntax is different.
Cpp specific: lookup RAII, be aware of rule of zero, rule of seven. Get comfortable with templates and debugging using gdb, run tools like asan, tsan. Stick with modern cpp (avoid c++11). Go for c++17 at the oldest.
Avoid locks, malloc, logging, anything of that sort in a realtime thread. Use atomics wherever appropriate. The principles are the same across the programming languages, the execution and syntax is different.
Cpp specific: lookup RAII, be aware of rule of zero, rule of seven. Get comfortable with templates and debugging using gdb, run tools like asan, tsan. Stick with modern cpp (avoid c++11). Go for c++17 at the oldest.
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
Locks are fine as long as you never wait on a lock that might be held by a lower priority thread. Two audio threads using locks to synchronize each other is fine if there's no sensible wait-free alternative. An audio thread waiting for a lock that could be held by a GUI thread on the other hand is a priority inversion and not realtime safe (though sometimes you can get away with this using trywait() primitives in audio thread, if you don't care if it always succeeds and just move along with your audio processing if it doesn't).keyman_sam wrote: Thu Sep 21, 2023 3:37 am Avoid locks, malloc, logging, anything of that sort in a realtime thread. Use atomics wherever appropriate. The principles are the same across the programming languages, the execution and syntax is different.
- KVRAF
- 14123 posts since 20 Nov, 2003 from Lost and Spaced
I think what it thinks it's trying to do is teach me to code. It says it wants Steinberg SDK, which I don't have so I don't know if it would make any difference. I just asked it to code a basic one oscillator multi wave synth. Midi in, pitch and Unison. The envelopes for amp, filter and a LFO. It did the basic frame. The envelopes were all done but no values for Attack Decay, etc.j wazza wrote: Wed Sep 20, 2023 10:22 pmI'd be interested to know what you told chatgpt to get thisosiris wrote: Sun Feb 05, 2023 4:48 pm I got ChatGPT to code a 2 oscillator 1 filter, 1 LFO, & Chorus VST synth in C++. It didn't put any values in for the internals, but it was a great bare bones structure to learn from.
also what do you mean it didnt put any values in for the internals? like an lfo with no frequency value?
-
- KVRer
- 8 posts since 14 Apr, 2024
This is interesting. I've watched several videos on realtime-safe coding and none of them mentioned this. Do you have an example of why you would want multiple audio threads? Also, how do you ensure they're the same priority?mystran wrote: Thu Sep 21, 2023 10:11 am Locks are fine as long as you never wait on a lock that might be held by a lower priority thread. Two audio threads using locks to synchronize each other is fine if there's no sensible wait-free alternative.
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
Watching videos is not a very good way to learn anything except absolute basics... or perhaps get an overview of what to actually study... but even then it's like the most inefficient possible way to spend your time.rou58 wrote: Fri Apr 26, 2024 2:44 pmThis is interesting. I've watched several videos on realtime-safe coding and none of them mentioned this. Do you have an example of why you would want multiple audio threads? Also, how do you ensure they're the same priority?mystran wrote: Thu Sep 21, 2023 10:11 am Locks are fine as long as you never wait on a lock that might be held by a lower priority thread. Two audio threads using locks to synchronize each other is fine if there's no sensible wait-free alternative.
For the most part, the question of what is or is not "real-time safe" becomes completely obvious when one truly understands what real-time actually means in the context of computing: a real-time program is one where missing a dead-line is a failure. Sometimes the term "hard RT" is used to describe situations where missing a dead-line is equivalent to a total system failure (think say some safety critical system) where as something might be called "soft RT" if missing a dead-line is bad, but not end of the world.. but it's a spectrum, and audio is actually "pretty hard RT" in the sense that while missing a deadline won't kill anyone, there will still be an obvious "glitch" (where as say a video might be able to get away with a few framedrops).. but still "soft" in the sense that we obviously don't usually prove that our code is guaranteed to meet a deadline on a certain CPU (though you could perhaps do this if you were making a hardware DSP product).
The fundamentally important part to understand is that "real-time" as a concept is concerned with dead-lines and dead-lines only. This means that when you're looking at realtime code, you need to evaluate performance in a different way from how you would evaluate it for general purpose code: in "normal" code, you are typically concerned about average efficiency, but in real-time code you must meet every dead-line separately, so you are concerned about worst-case efficiency first, and average efficiency only second. This is fundamental: if you are not thinking about the worst-case efficiency, you are not doing real-time programming.
Now.. if we have a thread that's trying to work towards a real-time deadline and then we have another thread (say a UI thread) that's not.. and the UI thread is holding a lock and we try to grab it from the audio thread, then what we have is what is known as a "priority inversion" where now the realtime thread is waiting for a non-realtime task to make progress so that it can free the lock. In a strict real-time system we can actually construct scenarios where this sort of situation leads to a dead-lock, but even if that's not really a concern on desktop systems, we still risk missing a deadline due to something that has nothing to do with any real-time processing.
That gives us the two rules that allow us to figure out what is or is not realtime safe: does the operation have an acceptable worst-case performance and does it guarantee that we'll never need to wait for a non-realtime thread? Once you understand these two ideas, you don't need to watch any videos about realtime safety anymore.
So finally why multiple threads? Well, we have a bunch of stuff to process and we need to get it processed before a dead-line expires. Modern CPUs have a bunch of cores, so if we can put work on all of these then we can expect to be able to process more stuff without missing dead-lines compared to trying to compute it all on a single core, right? Now, basically all modern DAWs try to process multiple plugins in parallel, so for most plugins you don't really need to do multi-threading directly, but sometimes when you have something like a particularly expensive synth or something, it could bottleneck the whole processing graph for long enough that you'll miss the dead-line.. unless we run the synth itself on multiple cores (most commonly different voices on different cores). This then frees up dependencies in the graph, allowing other plugins to be processed earlier, and hopefully allows the whole thing to meet the dead-line. There is a cost, so it only makes sense if a single plugin takes long enough to compute, but .. this happens.
So how do you make sure your audio threads are on the same priority? You put at the system designated audio priority and hope that the DAW (and all other plugins) are doing the same thing like they should.
-
- KVRer
- 5 posts since 4 Dec, 2006
I'm sure everything under the sun has already been said, but I'll add my two cents. You don't need to use all of the latest fancy features of the language, nor do you need to know everything.
- KVRer
- 15 posts since 19 Nov, 2023 from Austin, TX USA
Coming from other coding languages and writing c++ here and there over the years, I've foudn ChatGPT can be helpful but understanding fundamentals so you realize when LLMs are giving you inaccurate answers is invaluable.
One greatly overlooked resource is Udemy that most counties/cities have free access through your local library. Its a cheat code for getting access to free knowledge in well formed courses online. Don't sleep on it!
One greatly overlooked resource is Udemy that most counties/cities have free access through your local library. Its a cheat code for getting access to free knowledge in well formed courses online. Don't sleep on it!
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
No. These are geared towards video games which do just about every just about backwards with regards to how regular desktop applications are supposed to work.muzicxs wrote: Sun Sep 07, 2025 4:34 pm Would you guys recommend SDL3 or Raylib for the GUI? Development format would be CLAP in my case.
-
- KVRist
- 386 posts since 21 Jun, 2019
I see. I wondered, because some plugins have rich animations and I thought that could maybe be related to using a framework like SDL3.mystran wrote: Sun Sep 07, 2025 8:32 pmNo. These are geared towards video games which do just about every just about backwards with regards to how regular desktop applications are supposed to work.muzicxs wrote: Sun Sep 07, 2025 4:34 pm Would you guys recommend SDL3 or Raylib for the GUI? Development format would be CLAP in my case.
What would you recommend? Would something like https://www.gtk.org/docs/ work? I'm in a phase where I'm learning C, so I'd prefer plain C for now. In the future I'd like to look at Zig to see how that would improve the code base.
- KVRAF
- 8476 posts since 12 Feb, 2006 from Helsinki, Finland
Let me try to explain different GUI architectures instead, so you'll gain some understanding of what might or might not be a problem.muzicxs wrote: Mon Sep 08, 2025 3:57 amI see. I wondered, because some plugins have rich animations and I thought that could maybe be related to using a framework like SDL3.mystran wrote: Sun Sep 07, 2025 8:32 pmNo. These are geared towards video games which do just about every just about backwards with regards to how regular desktop applications are supposed to work.muzicxs wrote: Sun Sep 07, 2025 4:34 pm Would you guys recommend SDL3 or Raylib for the GUI? Development format would be CLAP in my case.
What would you recommend? Would something like https://www.gtk.org/docs/ work? I'm in a phase where I'm learning C, so I'd prefer plain C for now. In the future I'd like to look at Zig to see how that would improve the code base.
GUI applications in general are event-driven, which means the OS (or windowing system) sends some sort of "events" (eg. mouse moved, this key was pressed, window needs to be painted, etc) into an event queue (sometimes they are called messages and we call this a message queue, but it's the same thing), from which the application "main loop" or "event loop" will dispatch the events to the relevant window and widget and whatever.
Now, the first fundamental difference between a "normal" GUI application and a typical game engine is that the structure of the "main loop" is quite different. In a typical GUI application (eg. your plugin host) the "main loop" does exactly one thing: it drains the message queue and dispatches those events for processing. I'll get back to this.
In a typical game engine, the main loop is a lot more than an event pump, rather it's sometimes called the "game loop" because every game frame (at least in the traditional approach) is one iteration through the main loop. On a modern desktop system the game loop does "pump events" because it has to, but that's sort of more comparable to say a console game polling the controller keys once per frame. Many game libraries also tend to be geared towards the idea that there is one window.
Now, plugins (on Windows/macOS at least) don't have an event loop at all! Rather what they do is rely on the host application having a "standard" event loop. This works fine because a "standard" event loop will simply dispatch any event to whatever code is responsible for the window/widget/whatever. However, this means that when you pick a toolkit for plugin development, you need one that (1) can function on top of a "standard" event loop, (2) does not insist on actually running that event loop (it's fine for a toolkit to provide support for one, but in plugin context it needs to run on top of the host application loop) and (3) it must not make any assumptions about what other code might or might not be running in the same process (eg. mutable global state and such will cause issues with multiple plugins or even multiple instances of the same plugin).
There are some other things where one has to be careful in a plugin context (eg. say OpenGL "current context" management is a classic landmine), but the event dispatch in general is the big one: you need a toolkit that can work purely based on standard events, dispatched by a standard event loop that is not part of the plugin itself... and it must not step on the toes of anything else in the process.
So ... the basic rule of thumb: if a given toolkit does not specifically state that it can be used in plugin context and/or it's documentation does not go into any specifics of how it would be used in a plugin context, you probably want to just stay away from it. There's a reason iPlug and JUCE are so popular for plugin development and that's because they are built from ground up to function in a plugin context gracefully.
