Skip to content

Digital oscillator models for signal synthesis and analysis, suitable for real-time audio processing.

License

Notifications You must be signed in to change notification settings

alexandrefrancois/Oscillators

Repository files navigation

Oscillators

Copyright (c) 2022-2024 Alexandre R. J. François
Released under MIT License.

This package implements digital sinusoidal oscillator models for signal synthesis and analysis, suitable for real-time audio processing,

The main motivation behind the development of this package is to provide an efficient implementation of a bank of resonators of arbitrary frequencies, as an alternative to the Fast Fourier Transform in audio analysis applications. The best candidate on hardware that supports SIMD acceleration is ResonatorBankVec, a vectorized implementation that uses the Accelerate framework. The next best solution is the C++ implementation ResonatorBankCpp, with concurrent updates.

Oscillator

Overview

An oscillator is defined by its frequency and amplitude. The sinusoidal waveform values are computed recursively using a complex phasor.

A complex phasor Z = Zc + i Zs allows to recursively compute sinusoidals at a specified frequency and sampling rate. At each step, of duration 1 / sampleRate:

Z <- Z * W

where:

  • W = Wc + i Ws
  • w = 2 * PI * frequency / sampleRate
  • Wc = cos(w), Ws = sin(w)

Zc and Zs are cosine and sine (resp.) waveforms of same frequency; Z has magnitude 1, which can be used to regularly correct for accumulation of numerical approximations.

Classes

  • Oscillator: the base oscillator class, adopts OscillatorProtocol

Generator

Overview

The oscillator's phasor readily provides a sinusoidal signal to generate a signal at the chosen sampling rate and frequency.

At each tick of the clock (driven by the sampling rate of the output signal),

  • iterate the phasor value calculation
  • take the current value of either Zc (cosine) or Zs (sine)
  • output the value scaled by the amplitude

Classes

  • Generator: a simple generator class, adopts GeneratorProtocol

Resonators

Overview

A resonator is an oscillator which, when submitted to an input signal, oscillates with a larger amplitude when its resnonant frequency is present in the input signal. A resonator is characterized by its (resonant) frequency. The sinusoidal waveform is provided by the phasor.

The resonator's amplitude is updated at each tick of the clock, i.e. for each input sample, from the resonator's current amplitude value a (in [0,1]), its current waveform value w (in [-1,1]), and the input sample value s (in [-1,1]):

_a <- (1-k) * a + k * s * w,  where k in [0,1]_

The pattern v <- (1-k) * v + k * s, where k is a constant in [0,1], is known as a low-pass filter, as it smooths out high frequency variations in the input signal. The constant k dictates the "smoothing", in this case the dynamic behavior of the system, i.e. how quickly it adapts to variations in the input signal. This is also known as an exponentially weighted moving average.

The instantaneous contribution of each input sample value to the amplitude is proportional to s * w, which intuitively will be maximal when peaks in the input signal and peaks in the resonator's waveform are both equally spaced and aligned, i.e. when they have same frequency and are in phase.

In order to account for phase offset, the above calculation is performed at 2 phase values (there are only 2 degrees of freedom). For a sine waveform sin(x), the natural candidates are phases 0 and 𝜋/2, i.e. sin(x) and sin(x+𝜋/2) = cos(x), which are conveniently computed by the oscillator's phasor.

The resonator maintains two values, real and imaginary parts of a complex number P = Pc + i Ps, updated at each tick of the clock. For each input sample, from the current value of P, the current phasor value Z (of norm 1), and the input sample value s:

P <- (1-k) * P + k * s * Z, where k in [0,1]

At any tick, the resonator's amplitude is the norm of P, i.e. sqrt(pcpc + psps), and the phase offset is arctan(ps/pc).

Classes

  • Resonator: computes contributions at 0 and PI/2 (sine and cosine), adopts ResonatorProtocol

Resonator Banks

Overview

Resonator banks implement independents resonators typically tuned to various frequencies within a range.

Classes

  • ResonatorBankVec: a bank of independent resonators implemented as a single array (i.e. vectorized), resulting in single calls to Accelerate functions across the resonators. The use of unsafe pointers and of SIMD parallelism makes this implementation extremely efficient on most hardware.
  • ResonatorBankArray: a bank of independent resonators implemented as instances of the Swift resonator class. The update function for live processing triggers resonator updates in concurrent task groups.

Concurrency

The Swift ResonatorBankArray class implements 2 update functions:

  • update calls the update function for each resonator sequentially
  • updateConcurrent calls update for each resonator concurrently, with update calls grouped in a fixed number of concurrent tasks

C++ Implementation

The package features C++ version of the Oscillator, Resonator and ResonatorBank (as a vector of Resonator instances), in an Objective-C++ wrapper to bridge with Swift. The wrapper provides similar interfaces to the Swift implementations to facilitate comparative performance evaluation.

C++ classes

  • oscillator_cpp::Oscillator: the base oscillator class
  • oscillator_cpp::Resonator: resonator (same computations as the Swift Resonator implementation)
  • oscillator_cpp::ResonatorBank: resonator bank as vector of Resonator instances. The update function for live processing triggers resonator updates in sequential or concurrent task groups (using Apple's Grand Central Dispatch).

Concurrency

The C++ oscillator_cpp::ResonatorBank class by defaults utilizes Apple's Grand Central Dispatch to implement the concurrent update function updateConcurrent.

The code also provides a sample implementation of the updateConcurrent function utilizing std::async, which is not used by default.

Objective-C++ wrappers

These classes provide an Objective-C++ interface for the C++ classes so they can be used in Swift code.

  • OscillatorCpp
  • OscillatorCppProtected
  • ResonatorCpp
  • ResonatorBankCpp

About

Digital oscillator models for signal synthesis and analysis, suitable for real-time audio processing.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published