Synthesizers
Overview
Synthesizers are one of the most engaging parts of any DSP library, as they involve the actual creation of sounds. What makes synthesizers so engaging is the level of control they offer over sound creation. A synthesizer allows a user to shape and mold a sound by adjusting parameters such as waveform shape, frequency, amplitude, and filter settings. This level of control enables users to create expressive and unique sounds that can be used in a variety of contexts, ranging from music production to sound design for film and video games.
The advancements in DSP technology have made synthesizers even more powerful and flexible. Users can now create sounds that were previously impossible to achieve with traditional analog synthesizers. The Q DSP library provides some common synthesizers such as sine-wave, square, pulse, triangle and saw-tooth, as well as various generators for sculpting the sound envelopes with controls for attack, decay, hold sustain and release. These are designed as moduler building blocks that are combined to form more complex synthesizers.
Oscillator
Oscillator is a concept representation of an oscillator that generates periodic waveforms.
Oscillators are function objects that take in a phase_iterator: an iterator over the phase. The output is typically a floating point value.
Declaration
namespace cycfi::q::concepts
{
template <typename T>
concept Oscillator =
std::copy_constructible<T> &&
std::assignable_from<T&, T> &&
std::default_initializable<T> &&
requires(T o, T a, T b, phase_iterator pi)
{
o(pi); // Generate a periodic waveform given `{phase_iterator}`, `pi`.
};
}
Expressions
Constructors and Assignment
| Expression | Semantics |
|---|---|
|
Default construct an |
|
Copy construct from |
|
Assign |
| C++ brace initialization may also be used. |
Function Call
| Expression | Semantics | Return Type |
|---|---|---|
|
Generate a periodic waveform given |
|
BasicOscillator
BasicOscillator is a refinement of the Oscillator concept. BasicOscillator is not bandwidth limited. This is is suitable in certain cases. Moreover, some oscillators are inherently bandwidth limited.
Declaration
namespace cycfi::q::concepts
{
template <typename T>
concept BasicOscillator =
Oscillator<T> &&
requires(T o, phase ph)
{
o(ph); // Generate a periodic waveform given `{phase}`, `pi`.
};
}
Expressions
In addition to valid expressions for Oscillator, BasicOscillator allows these expressions.
Function Call
| Expression | Semantics | Return Type |
|---|---|---|
|
Generate a periodic waveform given |
|
BandwidthLimitedOscillator
Waveforms with hard discontinuities such as sawtooth and square waves can generate harmonics that extend beyond the Nyquist frequency range or half the sampling rate. Oscillators may be bandwidth limited to ensure that the harmonics generated fall within the Nyquist frequency range to prevent aliasing, which causes unwanted spectral artifacts in the signal.
BandwidthLimitedOscillator is a refinement of the Oscillator concept. These oscillators are bandwidth limited.
Declaration
namespace cycfi::q::concepts
{
template <typename T>
concept BandwidthLimitedOscillator =
Oscillator<T> &&
requires(T o, phase ph, phase dt)
{
o(ph, dt); // Generate a periodic waveform given `{phase}`, `pi`
// and another `{phase}`, `dt` representing the delta
// phase between two samples of the waveform (this is
// equivalent to the `_step` member function of the
// `{phase_iterator}`). (ph))`
};
}
Expressions
In addition to valid expressions for Oscillator, BandwidthLimitedOscillator allows these expressions.
Function Call
| Expression | Semantics | Return Type |
|---|---|---|
|
Generate a periodic waveform given |
|
Generator
Generator is a concept representation of a generator. Generators are function objects that take no function arguments and return an output that is typically a floating point value. Generators are typically non-periodic. Generators are useful for constructing complex signals, envelopes and tapers (also known as window functions).
Declaration
namespace cycfi::q::concepts
{
template <typename T>
concept Generator = requires(T v, T o, T a, T b, phase_iterator pi)
{
T(o); // Copy construct from `o`.
a = b; // Assign `b` to `a`.
v(); // Generate a signal.
};
}
EnvelopeGenerator
EnvelopeGenerator is a concept representation of an envelope generator: a Generator that is started and stopped, and that says where it is. An FM Operator takes any type that models it, so a voice can carry the DX7 shaped DX Envelope Generator, an adsr_envelope_gen, or one of your own.
config is the envelope’s own parameter type, given at construction or set in place. Setting in place keeps the current level, so a note in flight follows the change instead of restarting; that is what a knob under a player’s hand needs. gain is a master volume on the output, which is where amplitude modulation is applied.
Declaration
namespace cycfi::q::concepts
{
template <typename T>
concept EnvelopeGenerator =
Generator<T> &&
requires(T e, typename T::config const& cfg, float sps, float g)
{
T(cfg, sps); // Construct from a config at a sample rate.
e.set(cfg, sps); // Reconfigure in place, the state kept.
e.attack(); // Start.
e.release(); // Stop: run out from wherever it is.
e.reset(); // Idle and silent.
{ e.in_idle_phase() } -> std::convertible_to<bool>;
{ e.in_release_phase() } -> std::convertible_to<bool>;
e.gain(g);
{ e.gain() } -> std::convertible_to<float>;
};
}
Expressions
Notation
e-
Instance of a type that conforms to
EnvelopeGenerator. cfg-
An envelope configuration,
T::config. sps-
Floating point value representing samples per second.
g-
Linear gain. A
float.
Function Call
In addition to valid expressions for Generator, EnvelopeGenerator allows these expressions.
| Expression | Semantics | Return Type |
|---|---|---|
|
Reconfigure in place, keeping the current level. |
|
|
Start the envelope. |
|
|
Release it, from wherever it is. |
|
|
Idle and silent at once. |
|
|
Whether the envelope is idle. |
|
|
Whether it has been released. |
|
|
Set the master volume on its output. |
|
|
Get the master volume. |
|
Ramp
Ramp is a concept representation of a generator that generates non-periodic signals from 0.0 to 1.0 or from 1.0 to 0.0. It is a refinement of the Generator concept. Ramp(s) are suitable for generating envelopes. A Ramp represents a segment of an envelope. Essentially, an envelope comprises two or more upward and downward `Ramp`s.
Declaration
namespace cycfi::q::concepts
{
template <typename T>
concept Ramp =
Generator<T> &&
requires(T v, duration w, float sps)
{
T(w, sps); // Construct a Ramp given duration, w, and sps.
v.reset(); // Reset the Ramp to the start.
v.config(w, sps); // Configure a Ramp given duration, w, and sps.
};
}
Expressions
In addition to valid expressions for Generator, Ramp allows these expressions.
Notation
r-
Instance of a type that conforms to
Ramp. w-
Object of type
duration. sps-
Floating point value representing samples per second.