A GUI is a fantastic idea… But what should it be - SDL, wxWidgets, or Qt?
Choosing a GUI framework for a C++ audio project is a "fork in the road" moment. Each of these options pulls the project in a completely different architectural direction.
Since your course currently uses SDL, it’s the natural frontrunner, but here is how they stack up for a synth-building context:
SDL (Simple DirectMedia Layer) - The "Low-Level" Choice Since you already introduced SDL in Tutorial 02, staying here is the path of least resistance.
Pros: It doesn’t "take over" your main() function as aggressively as the others. It’s perfect for custom-drawn knobs and sliders using simple shapes or bitmaps.
The "Audio" Fit: It’s great for creating visualizers (oscilloscopes or spectrum analyzers) because you have direct access to the pixel buffer or hardware-accelerated rendering.
Cons: It has no built-in "widgets" (buttons, text inputs). You have to build your own UI system from scratch or use a library like Dear ImGui.
Qt - The "Professional/Industrial" Choice
Qt is the heavyweight champion. If you want your synth to look like a modern DAW (Digital Audio Workstation) or a commercial plugin, this is it.
Pros: Incredible documentation and a "What You See Is What You Get" (WYSIWYG) editor. It handles high-DPI scaling and complex layouts beautifully.
The "Audio" Fit: It’s overkill for a simple tutorial but excellent for teaching Signals and Slots, a C++ mechanism that perfectly mimics how patch cables work in a modular synth.
Cons: Huge binary size and a steep learning curve. It also requires the moc (Meta-Object Compiler), which adds a layer of "magic" that might hide the raw C++ logic you are trying to teach.
wxWidgets - The "Native" Choice
wxWidgets uses the host operating system’s native controls (it looks like a Windows app on Windows, and a GTK app on Linux).
Pros: No "magic" pre-processors like Qt. It’s "pure" C++ in a very traditional sense.
Cons: It feels a bit dated. Styling custom, "cool-looking" synth knobs is significantly harder in wxWidgets than in SDL or Qt because it strives to look like a standard spreadsheet or file explorer.
Feature | SDL | Qt | wxWidgets |
Learning Curve | Easy (if you know SDL) | Steep | Moderate |
Look & Feel | Custom/Game-like | Modern/Slick | Native/Standard |
Best For… | Visualizers & Prototyping | Commercial Software | Traditional Desktop Apps |
C++ Style | Procedural/Simple OOP | Heavy OOP & Macros | Traditional OOP |
So, we choose Qt - let’s install the dependencies and the Qt Creator IDE
We start by simply installing Qt 5 plus dependencies (roughly 500 MB)…
1
sudo apt install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtcreator
The QTCreator


The QTCreator allows us - for example to create our own UI ….
We start with the simple *.pro(ject) file which is to be generated when creating a new project…
synth.pro
| |
The meta-object compiler (moc)
The Meta-Object Compiler, or moc, is the tooling that makes Qt more than just a standard C library. While C is powerful, it historically lacks introspection—the ability for a program to examine its own structure (like classes, methods, or properties) at runtime.
The moc handles this by generating additional C code that bridges the gap between standard C and Qt’s advanced features.
How It Works
The moc isn’t a replacement for your compiler (like GCC or Clang); it’s a pre-processor. Here is the typical workflow:
Scanning: The moc reads your C++ header files.
Detection: It looks for the Q_OBJECT macro. If it finds it, it knows this class needs "meta-powers."
Generation: It creates a new C++ file (usually named moc_filename.cpp) containing the meta-object code.
Compilation: Your standard compiler compiles both your original code and the generated moc code, linking them together into the final binary.
Key Features Enabled by moc Without the Meta-Object Compiler, the following core Qt features wouldn’t exist:
Signals and Slots This is Qt’s signature way of letting objects communicate. Because standard C++ doesn’t have a built-in "signal" keyword, the moc generates the "glue code" required to look up functions by name and execute them when a signal is emitted.
Introspection (Run-Time Type Information) You can ask a QObject about its class name, what signals it has, or what methods are available at runtime using metaObject(). This is much more descriptive than the standard C++ typeid.
Properties The moc enables the Q_PROPERTY system, allowing you to treat class members like properties in languages like Python or C#. You can get/set values by string names, which is vital for Qt Quick (QML).
==
main.cpp
| |
mainwindow.h
| |
mainwindow.cpp
| |
| |
From linear to logarithmic
Human perception of pitch and loudness is logarithmic, so the slider must be mapped using an exponential function.
The standard approach:
\large \[f = f_{min} * (f_{max} / f_{min} )^{(slider/maxSlider)}\]
This is the valid approach for both, volume and frequency.
So next we show the both adapted files mainwindow.h and mainwindow.cpp
mainwindow.h
| |
mainwindow.cpp
| |