Skip to content

Commit 74ed762

Browse files
Update README.md
1 parent f7d2299 commit 74ed762

6 files changed

Lines changed: 34 additions & 22 deletions

File tree

README.md

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ Released under MIT License.
55

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

8-
The main motivation behind the development of this package is to provide reference Swift and C++ implementations of the _Resonate_ algorithm, a low latency, low memory footprint, and low computational cost algorithm for evaluating perceptually relevant spectral information from audio signals, at the same time resolution as that of the input signal.
8+
The main motivation behind the development of this package is to provide reference Swift and C++ implementations of the [_Resonate_](http://alexandrefrancois.org/Resonate) algorithm, a low latency, low memory footprint, and low computational cost algorithm for evaluating perceptually relevant spectral information from audio signals, at the same time resolution as that of the input signal.
99

10-
The package offers various implementations of resonator banks independently tuned at arbitrary frequencies. The best candidates on hardware that supports SIMD acceleration are `ResonatorBankVec` (Swift) or its C++ counterpart, which offer a vectorized implementation that uses the Accelerate framework.
10+
The package offers various implementations of resonator banks independently tuned at arbitrary frequencies, as well as tracking resonator banks that continuously self-tune to the frequency components in the input signal.
11+
The best candidates on hardware that supports SIMD acceleration are the vectorized implementation that uses the Accelerate framework, namely:
12+
- `ResonatorBankVec` (Swift) or its C++ counterpart for fixed resonant frequency resonator banks, and
13+
- `TrackingResonatorBankVec` (Swift) or its C++ counterpart for tracking resonator banks.
1114

1215

1316
## Phasor
@@ -46,7 +49,7 @@ At each tick of the clock (driven by the sampling rate of the output signal),
4649

4750
### Classes
4851

49-
- `Oscillator`: a simple generator class, adopts `OscillatorProtocol`
52+
- `Oscillator`: a simple sinusoidal signal generator class, adopts `OscillatorProtocol`
5053

5154
## Resonators
5255

@@ -58,7 +61,7 @@ The resonator accumulates the signal's contribution over time using the Exponent
5861

5962
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]):
6063

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

6366
The pattern _v <- (1-k) * v + k * s_, where k is a constant in [0,1] is the iterative implementation of the EWMA. The single parameter _k_, which can be related to a time constant, controls the dynamics of the system, i.e. how quickly it adapts to variations in the input signal, as well as the frequency resolution.
6467

@@ -74,45 +77,59 @@ This is followed by another EWMA to dampen amplitude and phase oscillations.
7477

7578
At any tick, the resonator's amplitude is the norm of P, i.e. _sqrt(pc*pc + ps*ps)_, and the phase offset is _arctan(ps/pc)_.
7679

80+
In the presence of significant response to an input signal, the instantaneous frequency can be estimated from the phase change of the complex state after processing each input sample. The tracking resonator adjusts its resonant frequency to track that instantaneous frequency.
7781

7882
### Classes
7983

80-
- `Resonator`: computes contributions at 0 and PI/2 (sine and cosine), adopts `ResonatorProtocol`
84+
- `Resonator`: computes contributions at 0 and PI/2 (sine and cosine); adopts `ResonatorProtocol`
85+
- `TrackingResonator`: computes contributions at 0 and PI/2 (sine and cosine), estimates phase differential and tracks estimated frequency; adopts `TrackingResonatorProtocol`
86+
8187

8288
## Resonator Banks
8389

8490
### Overview
8591

86-
Resonator banks implement independents resonators typically tuned to various frequencies within a range.
92+
Resonator banks implement independents resonators initially tuned to various frequencies within a range.
93+
Plain resonators have fixed resonant frequencies, while tracking resonator banks continuously self-tune to the frequency components in the input signal.
8794

8895
### Classes
8996

9097
- `ResonatorBankVec`: a bank of independent resonators implemented as a single array (i.e. vectorized), to allow 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.
9198
- `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.
99+
- `TrackingResonatorBankVec`: a bank of independent resonators implemented as a single array (i.e. vectorized), to allow 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.
100+
- `TrackingResonatorBankArray`: 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.
101+
92102

93103
### Concurrency
94104

95-
The Swift `ResonatorBankArray` class implements 2 update functions:
105+
The Swift `ResonatorBankArray` and `TrackingResonatorBankArray` classes implements 2 update functions each:
96106
- `update` calls the update function for each resonator sequentially
97107
- `updateConcurrent` calls update for each resonator concurrently, with update calls grouped in a fixed number of concurrent tasks
98108

109+
99110
## C++ Implementation
100111

101-
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.
112+
The package features C++ version of the Phasor, Oscillator, Resonator, ResonatorBank (as a vector of Resonator instances), ResonatorBankVec (vectorized implementation), TrackingResonator and TrackingResonatorBankVec, in an Objective-C++ wrapper to bridge with Swift. The wrapper provides similar interfaces to the Swift implementations to facilitate comparative performance evaluation.
102113

103114
### C++ classes
104115

105116
- `oscillator_cpp::Phasor`: the base class for independent oscillators
117+
- `oscillator_cpp::Oscillator`: a simple sinusoidal generator class
106118
- `oscillator_cpp::Resonator`: resonator (same computations as the Swift `Resonator` implementation)
107119
- `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).
108120
- `oscillator_cpp::ResonatorBankVec`: a bank of independent resonators implemented as a single vector, to allow single calls to Accelerate functions across the resonators. SIMD parallelism makes this implementation extremely efficient on most hardware.
121+
- `oscillator_cpp::TrackingResonator`: tracking resonator (same computations as the Swift `TrackingResonator` implementation)
122+
- `oscillator_cpp::TrackingResonatorBank`: tracking resonator bank as vector of TrackingResonator instances. The update function for live processing triggers resonator updates in sequential or concurrent task groups (using Apple's Grand Central Dispatch).
123+
- `oscillator_cpp::TrackingResonatorBankVec`: a bank of independent tracking resonators implemented as a single vector, to allow single calls to Accelerate functions across the resonators. SIMD parallelism makes this implementation extremely efficient on most hardware.
109124

110125
### Concurrency
111126

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

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

131+
These methods are not thoroughly tested.
132+
116133
### Objective-C++ wrappers
117134

118135
These classes provide an Objective-C++ interface for the C++ classes so they can be used in Swift code.
@@ -122,3 +139,6 @@ These classes provide an Objective-C++ interface for the C++ classes so they can
122139
- `ResonatorCpp`
123140
- `ResonatorBankCpp`
124141
- `ResonatorBankVecCpp`
142+
- `TrackingResonatorCpp`
143+
- `TrackingResonatorBankCpp`
144+
- `TrackingResonatorBankVecCpp`

Sources/Oscillators/Oscillator.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import Foundation
2626

2727
fileprivate let twoPi = Float.pi * 2.0
2828

29-
/// Oscillator base class:
29+
/// Oscillator class:
3030
/// an oscillator is characterized by its frequency and amplitude.
3131
/// Waveform values are computed recursively with a complex phasor.
3232
/// Incremental calculations depend on frequency and sampling rate.

Sources/Oscillators/Phasor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fileprivate let twoPi = Float.pi * 2.0
2929
/// Phasor class:
3030
/// A complex phasor allows to compute sinusoid values recursively.
3131
/// Incremental calculations depend on frequency and sampling rate.
32-
/// This is the base class for individual oscillators and resonators.
32+
/// This is the base class for individual oscillators and resonators.
3333
open class Phasor : PhasorProtocol {
3434
public var frequency: Float {
3535
get {

Sources/OscillatorsCpp/Oscillator.hpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,12 @@ SOFTWARE.
3131

3232
namespace oscillators_cpp {
3333

34-
// Phasor class: base for individual oscillators
34+
// Oscillator class: simple signal generator
3535
class Oscillator : public Phasor {
3636
protected:
3737
float m_amplitude;
3838

3939
public:
40-
// Oscillator & operator=(const Oscillator&) = delete;
41-
// Oscillator(const Oscillator&) = delete;
42-
// virtual ~Oscillator() = default;
43-
4440
Oscillator(float frequency, float sampleRate, float amplitude = 1.0f, bool angular = false);
4541

4642
float amplitude() const { return m_amplitude; }

Sources/OscillatorsCpp/Phasor.hpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,7 @@ class Phasor {
5050

5151
void updateMultiplier();
5252

53-
public:
54-
// Phasor & operator=(const Phasor&) = delete;
55-
// Phasor(const Phasor&) = delete;
56-
// virtual ~Phasor() = default;
57-
53+
public:
5854
Phasor(float frequency, float sampleRate, bool angular = false);
5955

6056
float omega() const { return m_omega; }

Sources/OscillatorsCpp/include/PhasorCpp.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
MIT License
33
4-
Copyright (c) 2022-2025 Alexandre R. J. Francois
4+
Copyright (c) 2022-2026 Alexandre R. J. Francois
55
66
Permission is hereby granted, free of charge, to any person obtaining a copy
77
of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,7 @@ SOFTWARE.
2424

2525
#import <Foundation/Foundation.h>
2626

27-
// Wrapper for the base Oscillator class
27+
// Wrapper for the base Phasor class
2828
@interface PhasorCpp : NSObject
2929
- (instancetype)initWithFrequency:(float)frequency sampleRate:(float)sampleRate angular:(bool)angular;
3030
- (float)frequency;

0 commit comments

Comments
 (0)