Analog Character: DelayLine Interpolation + ConsoleBus
Overview
Two targeted changes to reduce digital artifacts and add analog warmth to the signal path:
- DelayLine Hermite interpolation — eliminates metallic coloring in chorus/flanger/short-delay effects
- ConsoleBus component — models analog summing bus character at mixing junctions
DelayLine Hermite Interpolation
Problem
Linear interpolation between delay buffer samples introduces high-frequency artifacts (metallic coloring) at short delay times (< 20ms), which is especially audible in chorus and flanger effects.
Solution
Added a 3rd parameter Interpolation (enum: Linear=0, Hermite=1, default=1) and a readHermite() method alongside the existing readInterpolated().
Hermite cubic interpolation uses 4 buffer samples and a 3rd-order polynomial:
Given samples s[-1], s[0], s[1], s[2] and fractional position t:
a = -0.5*s[-1] + 1.5*s[0] - 1.5*s[1] + 0.5*s[2]
b = s[-1] - 2.5*s[0] + 2.0*s[1] - 0.5*s[2]
c = -0.5*s[-1] + 0.5*s[1]
d = s[0]
output = ((a*t + b)*t + c)*t + d
Cost: ~3 extra multiplies per sample vs linear. The process() method branches on the atomic interpolation_ load to select the interpolation mode at runtime.
Buffer constraints
- Linear: max delay =
kMaxDelaySamples - 2(needs idx+1) - Hermite: max delay =
kMaxDelaySamples - 3(needs idx+2)
Files changed
FolioDSP/.../Primitives/DelayLine.h—kInterpolationparam,interpolation_atomic,readHermite()declarationFolioDSP/.../Primitives/DelayLine.cpp—readHermite()implementation, process() branching, parameter routingFolioDSP/components.json— Interpolation parameter with enum labelsFolioDSP/.../Core/ComponentsData.cpp— enum labels array, 3rd ParameterDescriptor, param count 2→3
Recipe usage
Set "Interpolation": 1.0 on any DelayLine node to use Hermite (this is the default for new instances, but existing recipe JSON files may need updating). The prospero.json recipe was updated as a reference.
ConsoleBus Component
Design
A lightweight processor (ComponentType 68, category "Color") that models analog summing bus character. Ultra-subtle by default — designed to sit at mixing junctions or as a "stage" between effects.
Parameters
| Index | Name | Range | Default | Unit | Description |
|---|---|---|---|---|---|
| 0 | Drive | 0–1 | 0.15 | Raw | Input gain into saturation |
| 1 | Tone | 200–20000 | 12000 | Hz | One-pole LPF cutoff (HF rolloff) |
| 2 | Noise Floor | -100–-40 | -80 | dB | Shaped noise level (-100 = off) |
| 3 | Mix | 0–100 | 100 | % | Dry/wet blend |
Processing chain (per sample)
- Soft asymmetric saturation:
tanh(x * (1 + drive)) + 0.1 * drive * x * x— thex²term generates even harmonics (transformer character), scaled by drive. Very gentle at default 0.15. - HF rolloff: One-pole LPF at Tone frequency. Mimics summing amp bandwidth limitation.
- Noise floor: xorshift32 PRNG → one-pole LPF at ~1 kHz (pink-ish shaping) → scale by
10^(noiseFloorDb/20). Adds the analog "air" between samples. - DC blocker: One-pole HP at ~10 Hz removes DC offset from the asymmetric saturation.
- Dry/wet mix.
No oversampling needed — at these low drive levels, aliasing products are below the noise floor.
Snapshot fields
inputLevel(float, 0–1)outputLevel(float, 0–1)driveAmount(float, 0–1) — current smoothed drivegainReduction(float, 0–6 dB) — saturation compression
Files created
FolioDSP/.../Color/ConsoleBus.hFolioDSP/.../Color/ConsoleBus.cpp
Files modified
FolioDSP/.../Core/Types.h—ConsoleBus = 68FolioDSP/.../Core/Snapshots.h—ConsoleBusSnapshotFolioDSP/.../FolioDSP.h— umbrella includeFolioDSP/components.json— full component entryFolioDSP/.../Core/ComponentsData.cpp— params, snapshots, descriptor (array 68→69)FolioDSPBridge.h/FolioDSPBridge.mm—ConsoleBusBridgePackages/Touchstone/.../BridgeAdapter.swift—case consoleBus = "Console Bus"+ init case
Warm Bus Recipe
Reference recipe demonstrating the analog console channel strip pattern:
TubeWarmth → TapeSaturation → TransformerColor → ConsoleBus → DCBlocker
Exposed parameters: Warmth (tube drive), Saturation (tape drive), Air (transformer rolloff), Console (bus drive).
File: Packages/Touchstone/Sources/Touchstone/Recipes/warm_bus.json
Design notes
- Why not oversample ConsoleBus? At Drive=0.15 (default), the saturation is so gentle that aliasing harmonics are 60+ dB below the fundamental. TubeWarmth and TransformerColor already have 2x oversampling for when heavier saturation is needed.
- Why Hermite over higher-order interpolation? Hermite (4-point cubic) gives the best quality/cost tradeoff for audio delay lines. Lagrange or sinc interpolation would improve HF response further but at 2-5x the cost per sample — not justified for the typical use cases.
- Noise PRNG choice: xorshift32 is sufficient for shaped noise floor — it's fast (3 XOR + shift ops), has a full 2^32 period, and the one-pole shaping filter masks any statistical imperfections.