NB: A preview release of Klang Studio (v0.7pre) for Windows and Mac is now available from https://nash.audio/klang/studio.
klang is a language for the design and development of realtime audio processes in C++.
As a dialect of modern C++, klang enables synthesisers and effects to be written in clearer, more concise language, using the concept of streams and OOP to combine the performance of native C++ and clarity of visual/data-flow languages, such as block diagrams or patch-based tools like Max or PureData, and is designed to facilitate rapid prototyping of audio processing, as well as experimentation, knowledge sharing, and learning.
Designed for both professional and academic use, klang hopes to facilitate the sharing of DSP knowledge with the community-led development of an open library of reference examples.
- Concise, accessible, and extensible language for audio processing.
- Performance of native C++, with single sample or buffer-based processing.
- Primitives for all common DSP components (oscillators, filters, etc.).
- Natively compatible and compilable in all modern C++ compilers and IDEs.
- A single header file, easily integrated with any new or existing C++ project.
- Designed for knowledge sharing; supporting a growing repository of DSP examples.
- Permissive open-source (attribution) licence.
NOTE: The klang language is under active development, so syntax may change between pre-release versions.
To use klang, simply include the klang.h header file in your C++ project.
#include <klang.h>
using namespace klang::optimised; // optional
Audio objects are then accessible using the klang
namespace (e.g. Effect, Sine). klang tries to use plain language to describe objects, so the namespace is used to avoid conflict with similar terms in other APIs or code. If this is not needed, add the using namespace
directive as shown above.
The core data type in klang is signal
, an extension of the basic C type float
with additional audio and streaming functionality. In many cases, signals can be used interoperably with floats, facilitating integration of klang with other C++ code, while enabling signal-flow expressions, such as in the following wah-wah effect ...
// signal in, out;
// Sine lfo;
// LPF lpf;
signal mod = lfo(3) * 0.5 + 0.5;
in >> lpf(mod) >> out;
... where lpf
is a low-pass filter, in
is the input signal, out
the output signal, and mod
is a signal used to modulate the filter's parameter (~cutoff frequency), based on a low-frequency (3Hz) sine oscillator (lfo
).
DSP components, like oscillators or filters, are declared as objects (using struct or class) as either a Generator
(output only) or Modifier
(input / output), supplying functions to handle parameter setting (set()
) and signal processing (process()
) ...
struct LPF : Modifier {
param a, b;
void set(param coeff) {
a = coeff;
b = 1 - a;
}
void process() {
(a * in) + (b * out) >> out;
}
};
Here, the Modifier
parent class adapts the LPF code so it can be used as before. Parameters have type param
, which is derived from signal
, allowing constants, floats, or signals to be used interchangeably with or as parameters. Code may use either signal (<<, >>) or mathematical (=) operators interchangeable, to allow you to express the audio process in a manner best suited to the context or other reference material. Filters are often described in mathematical terms, so you could also write: out = (a * in) + (b * out);
.
More complex audio processes are created by combining klang objects, as in this simple subtractive synthesiser:
struct Subtractive : Note {
Saw osc;
LPF lpf;
Sine lfo;
event on(Pitch pitch, Amplitude velocity) {
const Frequency frequency(pitch -> Frequency);
osc.set(frequency);
}
void process() {
signal mod = lfo(3) * 0.5 + 0.5;
osc >> lpf(mod) >> out;
}
};
This class supplies the Note
definition to be used as part of a synthesiser (Synth
- see the Examples linked below). It processes audio, but also handles events such as a note on, where the supplied pitch is converted to a frequency (in Hz) for use in the oscillator. By default, without code to handle a note off, the note and audio processing will be automatically terminated when one is received.
But most instruments continue making sound after a note is 'released'...
struct Subtractive : Note {
Saw osc;
LPF lpf;
Sine lfo;
ADSR adsr;
event on(Pitch pitch, Amplitude velocity) {
const Frequency frequency(pitch -> Frequency);
osc.set(frequency);
adsr.set(0.25, 0.25, 0.5, 5.0);
}
event off() {
adsr.release();
}
void process() {
signal mod = lfo(3) * 0.5 + 0.5;
osc * adsr >> lpf(mod) >> out;
if (adsr.finished())
stop();
}
};
This example shapes the note and adds a release stage using an ADSR amplitude envelope. The ADSR
is a type of Envelope
that takes four parameters (attack, decay, sustain, release - set in on()
) and uses its output to scale the (*) amplitude of the signal. To add the 'release' stage and continue processing audio after a note off, we add the off()
event and trigger the release of an ADSR envelope. Now, process()
will continue to be called until you tell it to stop()
, which we call when the ADSR is finished (that is, adsr.finished()
is true).
For further techniques, see the Examples below.
The /examples folder contains an evolving selection of examples (and tests):
- Supersaw.k - a basic, but capable JP-8000 SuperSaw synth
- DX7.k - a simple DX7 emulator, with five presets (TUB BELLS, E.PIANO 1, E.ORGAN 1, HARPSICH 1, STRINGS)
- Guitar.k - a Karplus-Strong-based exciter-resonator plucked string model
- Banjo.k - a variation of Guitar.k with extra twang
- THX.k - an versatile additive synthesiser based on stacked, detuned saw oscillators
See https://nash.audio/klang >> KLANG EXAMPLES for online, interactive demos of the above.
This object defines the processing for a single synth note that can then be used in any audio C++ project, placing the following code fragments at appropriate points in your code (e.g. myEffect/mySynth mini-plugin or any AU/VST plugin, JUCE app, etc.):
klang::Subtractive note;
note.start(pitch, velocity); // Note On
note.release(pitch, velocity); // Note Off
klang::Buffer buffer = { pfBuffer, numSamples };
if(!note.process(buffer))
note.stop();
For ready-made AU/VST compatible C++ templates for Xcode and Visual Studio, see the github.com/nashnet/myeffect and github.com/nashnet/mysynth repositories. rapIDE (Klang Studio) plugins also support a pure Klang live coding mode.
Klang Studio plugins feature native support for klang, providing a pure klang mode for synthesiser and effect plugin development, and will ultimately support generating/exporting of VS/Xcode/JUCE/WASM projects.
Klang Studio (aka rapIDE) (https://nash.audio/klang - coming soon) is a rapid audio prototyping (RAP) integrated development environment (IDE): a state-of-the-art C++ audio development environment... inside a DAW plugin, enabling the live C++ development of realtime audio processes, where you can open, edit, and recompile the code of the running plugin, within the DAW itself plugin's own UI and without having to stop and reload it.
For more information about the project, or to get involved, email Chris Nash ([email protected]).