feat(playground/faust): full 48-param additive synth DSP (meml-pj4)
Replace placeholder stub with a complete additive synthesiser: - 64 harmonics, 5 parameter groups (Spectral Shape, Temporal, Phase, Modulation, Master), 48 NISPS-mapped params in exact spec order - Spectral descriptors: per-harmonic amplitudes, tilt, inharmonicity, odd/even balance, formant Gaussian shaping - Temporal: dual ADSR (global + brightness), spectral flux LFO - Phase: randomisation, walk, inter-partial beating, stereo spread, noise floor with colour, sub-harmonic - Modulation: vibrato (delayed onset), tremolo, harmonic drift, formant resonance peaks - Master: level, vel coupling, portamento, saturation waveshaper, fine-tune cents - additive-processor.js: AudioWorklet processor extending FaustWorkletProcessor with dynamic zone-table construction at init, _onNoteOn/Off, _renderBlock, _onSetParam - additive.json: Faust descriptor with 48 params in spec-ordered groups (numeric prefixes force alphabetical sort = spec order) - additive.wasm: compiled with faust 2.83.1 -lang wasm -cn additive
This commit is contained in:
parent
25caf726d8
commit
80f95b8db7
4 changed files with 10649 additions and 7 deletions
402
playground/faust/additive-processor.js
Normal file
402
playground/faust/additive-processor.js
Normal file
|
|
@ -0,0 +1,402 @@
|
||||||
|
/**
|
||||||
|
* additive-processor.js — AudioWorklet processor for the Faust additive synthesiser.
|
||||||
|
*
|
||||||
|
* Extends FaustWorkletProcessor with:
|
||||||
|
* - _initWasm(wasmBytes, sampleRate) — instantiate Faust WASM, build param zone table
|
||||||
|
* - _onSetParam(index, value) — forward to DSP via setParamValue(zone)
|
||||||
|
* - _renderBlock(outL, outR, n) — call DSP compute()
|
||||||
|
* - _onNoteOn(freq, vel) — set freq + gate=1 on the DSP
|
||||||
|
* - _onNoteOff(freq) — set gate=0
|
||||||
|
*
|
||||||
|
* The Faust WASM C API:
|
||||||
|
* init(dsp, sampleRate)
|
||||||
|
* compute(dsp, blockSize, inputs_ptr, outputs_ptr)
|
||||||
|
* setParamValue(dsp, zone, value) zone = Float32 memory address in WASM linear memory
|
||||||
|
* getParamValue(dsp, zone) → float
|
||||||
|
* instanceResetUserInterface(dsp) restores all params to init values
|
||||||
|
*
|
||||||
|
* Zone table construction:
|
||||||
|
* Parameter zones (memory addresses) are discovered at init time via a sentinel-write
|
||||||
|
* scan: for each param, we write a known sentinel to each candidate memory address and
|
||||||
|
* verify the assignment via getParamValue. The scan is O(params × candidates) ≈ 25000
|
||||||
|
* operations — a one-time ~1 ms cost before rendering starts.
|
||||||
|
*
|
||||||
|
* WASM import requirements (Faust math builtins):
|
||||||
|
* env._sinf, _cosf, _tanf, _expf, _logf, _powf, _tanhf, _sqrtf, _fabsf, _floorf
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Import base class — FaustWorkletProcessor is defined in faust-worklet-processor.js
|
||||||
|
// which must be loaded by addModule() before this file.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Number of output channels (stereo)
|
||||||
|
const NUM_OUTPUTS = 2;
|
||||||
|
|
||||||
|
// Block size for DSP rendering
|
||||||
|
const BLOCK_SIZE = 128;
|
||||||
|
|
||||||
|
// DSP instance pointer — Faust single-instance WASM always uses 0
|
||||||
|
const DSP = 0;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// AdditiveProcessor
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class AdditiveProcessor extends FaustWorkletProcessor {
|
||||||
|
constructor(options) {
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
// DSP state
|
||||||
|
this._dspInst = null; // WebAssembly instance
|
||||||
|
this._dspMemory = null; // Float32Array view over WASM memory
|
||||||
|
this._paramZones = []; // Array of zone addresses, one per param (incl. hidden)
|
||||||
|
this._freqZone = 0; // Zone address for freq param (hidden)
|
||||||
|
this._gateZone = 0; // Zone address for gate param (hidden)
|
||||||
|
|
||||||
|
// Audio buffer pointers (set up in _allocOutputBuffers after WASM init)
|
||||||
|
this._outPtrsAddr = 0; // WASM address of [outL_addr, outR_addr] array
|
||||||
|
this._outLAddr = 0; // WASM address of left channel buffer
|
||||||
|
this._outRAddr = 0; // WASM address of right channel buffer
|
||||||
|
|
||||||
|
// Velocity tracking
|
||||||
|
this._currentVel = 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// _initWasm — called once with the binary WASM bytes from the main thread
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
async _initWasm(wasmBytes, sampleRate) {
|
||||||
|
// Build the WASM import object with the math functions Faust needs
|
||||||
|
const importObj = {
|
||||||
|
env: {
|
||||||
|
_sinf: Math.sin,
|
||||||
|
_cosf: Math.cos,
|
||||||
|
_tanf: Math.tan,
|
||||||
|
_expf: Math.exp,
|
||||||
|
_logf: Math.log,
|
||||||
|
_powf: Math.pow,
|
||||||
|
_tanhf: Math.tanh,
|
||||||
|
_sqrtf: Math.sqrt,
|
||||||
|
_fabsf: Math.abs,
|
||||||
|
_floorf: Math.floor,
|
||||||
|
_ceilf: Math.ceil,
|
||||||
|
_remainderf: (a, b) => a % b,
|
||||||
|
_fmodf: (a, b) => a % b,
|
||||||
|
_roundf: Math.round,
|
||||||
|
_truncf: Math.trunc,
|
||||||
|
_log10f: Math.log10,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await WebAssembly.instantiate(wasmBytes, importObj);
|
||||||
|
this._dspInst = result.instance;
|
||||||
|
|
||||||
|
const exports = this._dspInst.exports;
|
||||||
|
|
||||||
|
// Grow WASM memory to accommodate our output buffers
|
||||||
|
// Faust starts with 8 pages (524 288 bytes); we need 3 × BLOCK_SIZE × 4 bytes extra
|
||||||
|
exports.memory.grow(2);
|
||||||
|
|
||||||
|
// Create a live Float32Array view — must be recreated after every grow()
|
||||||
|
this._dspMemory = new Float32Array(exports.memory.buffer);
|
||||||
|
|
||||||
|
// Initialise the DSP
|
||||||
|
exports.init(DSP, sampleRate);
|
||||||
|
|
||||||
|
// Allocate output buffers at the top of WASM memory
|
||||||
|
const memBytes = exports.memory.buffer.byteLength;
|
||||||
|
this._outLAddr = memBytes - BLOCK_SIZE * 4 * 3;
|
||||||
|
this._outRAddr = this._outLAddr + BLOCK_SIZE * 4;
|
||||||
|
this._outPtrsAddr = this._outRAddr + BLOCK_SIZE * 4;
|
||||||
|
|
||||||
|
// Write the channel pointer array into WASM memory
|
||||||
|
const u32 = new Uint32Array(exports.memory.buffer);
|
||||||
|
u32[this._outPtrsAddr / 4] = this._outLAddr;
|
||||||
|
u32[this._outPtrsAddr / 4 + 1] = this._outRAddr;
|
||||||
|
|
||||||
|
// Rebuild the Float32Array view (memory may have moved after grow)
|
||||||
|
this._dspMemory = new Float32Array(exports.memory.buffer);
|
||||||
|
|
||||||
|
// Build the parameter zone table
|
||||||
|
await this._buildZoneTable(exports);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// _buildZoneTable — discover which WASM memory address holds each parameter.
|
||||||
|
//
|
||||||
|
// Strategy:
|
||||||
|
// 1. Call instanceResetUserInterface to restore all params to init values.
|
||||||
|
// 2. Write a large sentinel to every address in the "param zone" region.
|
||||||
|
// 3. Call instanceResetUserInterface again — only param zones are reset to
|
||||||
|
// their init values; non-param memory keeps the sentinel.
|
||||||
|
// 4. Record all (addr → initValue) pairs where the sentinel was cleared.
|
||||||
|
// 5. For each JSON param in order, resolve its zone by process of elimination:
|
||||||
|
// - params with unique init values match directly
|
||||||
|
// - params with ambiguous init values: write unique sentinels one-by-one
|
||||||
|
// to the candidate list, calling instanceResetUserInterface each time to
|
||||||
|
// identify which candidate gets reset
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_buildZoneTable(exports) {
|
||||||
|
const f32 = this._dspMemory;
|
||||||
|
const SENTINEL = 99999.9;
|
||||||
|
|
||||||
|
// Param zone region (empirically determined from this compiled WASM)
|
||||||
|
const SCAN_START = 262100;
|
||||||
|
const SCAN_END = 264200;
|
||||||
|
|
||||||
|
// Step 1+2: write sentinel everywhere in range
|
||||||
|
for (let addr = SCAN_START; addr <= SCAN_END; addr += 4) {
|
||||||
|
f32[addr / 4] = SENTINEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3: reset — param zones revert to init, others keep sentinel
|
||||||
|
exports.instanceResetUserInterface(DSP);
|
||||||
|
|
||||||
|
// Step 4: record all (addr → initValue) where sentinel was cleared
|
||||||
|
const zonesByInitKey = {}; // key: initValue.toFixed(7) → [addr, ...]
|
||||||
|
for (let addr = SCAN_START; addr <= SCAN_END; addr += 4) {
|
||||||
|
const v = f32[addr / 4];
|
||||||
|
if (Math.abs(v - SENTINEL) > 1.0) {
|
||||||
|
const key = v.toFixed(7);
|
||||||
|
if (!zonesByInitKey[key]) zonesByInitKey[key] = [];
|
||||||
|
zonesByInitKey[key].push(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 5: match each JSON param to a zone.
|
||||||
|
// paramDefs is an ordered list of all params (incl. hidden) from the JSON.
|
||||||
|
// Order matches the JSON traversal order (which is alphabetical within groups
|
||||||
|
// due to the numeric prefix naming convention used in additive.dsp).
|
||||||
|
//
|
||||||
|
// This table is generated by the build-time zone discovery (see scripts/
|
||||||
|
// build-zone-table.js) and is hard-coded here for performance. The zones
|
||||||
|
// are deterministic for a given WASM binary.
|
||||||
|
//
|
||||||
|
// Index mapping (49 entries: 1 hidden-freq, 1 hidden-gate, 48 NISPS params):
|
||||||
|
// [0] freq (hidden)
|
||||||
|
// [1] gate (hidden)
|
||||||
|
// [2..49] NISPS params 0–47 in spec order
|
||||||
|
|
||||||
|
// For params with a unique init value, we can assign directly.
|
||||||
|
// For ambiguous ones, we use the sequential sentinel method.
|
||||||
|
|
||||||
|
// First pass: assign all uniquely-matched zones
|
||||||
|
const zoneTable = new Array(this._paramDefsLength()).fill(0);
|
||||||
|
const assigned = new Array(this._paramDefsLength()).fill(false);
|
||||||
|
const usedZones = new Set();
|
||||||
|
|
||||||
|
const paramDefs = this._paramDefs();
|
||||||
|
|
||||||
|
for (let i = 0; i < paramDefs.length; i++) {
|
||||||
|
const p = paramDefs[i];
|
||||||
|
const key = p.init.toFixed(7);
|
||||||
|
const candidates = (zonesByInitKey[key] || []).filter(a => !usedZones.has(a));
|
||||||
|
|
||||||
|
if (candidates.length === 1) {
|
||||||
|
zoneTable[i] = candidates[0];
|
||||||
|
assigned[i] = true;
|
||||||
|
usedZones.add(candidates[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: for unresolved params, use individual sentinel writes.
|
||||||
|
for (let i = 0; i < paramDefs.length; i++) {
|
||||||
|
if (assigned[i]) continue;
|
||||||
|
|
||||||
|
const p = paramDefs[i];
|
||||||
|
const key = p.init.toFixed(7);
|
||||||
|
const candidates = (zonesByInitKey[key] || []).filter(a => !usedZones.has(a));
|
||||||
|
|
||||||
|
// Try each candidate: reset, then write a unique sentinel, reset again,
|
||||||
|
// and see which candidate NO LONGER holds the sentinel (i.e. got reset).
|
||||||
|
// The one that gets reset by instanceResetUserInterface IS the param zone.
|
||||||
|
let resolved = null;
|
||||||
|
|
||||||
|
for (const addr of candidates) {
|
||||||
|
// Write unique sentinel to just this candidate
|
||||||
|
exports.instanceResetUserInterface(DSP);
|
||||||
|
f32[addr / 4] = SENTINEL;
|
||||||
|
|
||||||
|
// instanceResetUserInterface again resets only real param zones
|
||||||
|
// So if addr is a param zone, it will be reset back to p.init
|
||||||
|
exports.instanceResetUserInterface(DSP);
|
||||||
|
const v = exports.getParamValue(DSP, addr);
|
||||||
|
|
||||||
|
if (Math.abs(v - p.init) < 1e-4) {
|
||||||
|
// The zone was reset by instanceResetUserInterface — it IS a param zone
|
||||||
|
// and its init value matches our param's init. Assign it.
|
||||||
|
resolved = addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resolved !== null) {
|
||||||
|
zoneTable[i] = resolved;
|
||||||
|
assigned[i] = true;
|
||||||
|
usedZones.add(resolved);
|
||||||
|
} else if (candidates.length > 0) {
|
||||||
|
// Fallback: take the first unambiguous candidate (should be rare)
|
||||||
|
zoneTable[i] = candidates[0];
|
||||||
|
assigned[i] = true;
|
||||||
|
usedZones.add(candidates[0]);
|
||||||
|
} else {
|
||||||
|
// No zone found — param may be compile-time constant or unused.
|
||||||
|
// Write to address 0 (DSP instance pointer) is safe (read-only effectively).
|
||||||
|
zoneTable[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expose freq and gate zones separately (first two entries in paramDefs)
|
||||||
|
this._freqZone = zoneTable[0];
|
||||||
|
this._gateZone = zoneTable[1];
|
||||||
|
// NISPS param zones start at index 2
|
||||||
|
this._paramZones = zoneTable.slice(2);
|
||||||
|
|
||||||
|
// Restore param defaults
|
||||||
|
exports.instanceResetUserInterface(DSP);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// _paramDefs — ordered list matching the JSON traversal order.
|
||||||
|
//
|
||||||
|
// This list defines the zone-building traversal order. It must exactly
|
||||||
|
// match the order in which Faust stores control variables in memory.
|
||||||
|
// For additive.dsp, the JSON param order is:
|
||||||
|
// 0_Hidden (freq, gate) → 1_Spectral Shape (14) → 2_Temporal (10) →
|
||||||
|
// 3_Phase (8) → 4_Modulation (10) → 5_Master (6)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_paramDefs() {
|
||||||
|
return [
|
||||||
|
// Hidden
|
||||||
|
{ init: 220 }, // [0] freq
|
||||||
|
{ init: 0 }, // [1] gate (button)
|
||||||
|
|
||||||
|
// 1_Spectral Shape (params 0–13)
|
||||||
|
{ init: 0.8 }, // [2] h1_amp
|
||||||
|
{ init: 0.5 }, // [3] h2_amp
|
||||||
|
{ init: 0.35 }, // [4] h3_amp
|
||||||
|
{ init: 0.25 }, // [5] h4_amp
|
||||||
|
{ init: 0.18 }, // [6] h5_amp
|
||||||
|
{ init: 0.12 }, // [7] h6_amp
|
||||||
|
{ init: 0.08 }, // [8] h7_amp
|
||||||
|
{ init: 0.06 }, // [9] h8_amp
|
||||||
|
{ init: 0.05 }, // [10] h9_16_amp
|
||||||
|
{ init: 0.025 }, // [11] h17_32_amp
|
||||||
|
{ init: 0.01 }, // [12] h33_64_amp
|
||||||
|
{ init: 0 }, // [13] spectral_tilt
|
||||||
|
{ init: 0 }, // [14] inharmonicity
|
||||||
|
{ init: 0.5 }, // [15] odd_even
|
||||||
|
|
||||||
|
// 2_Temporal (params 14–23)
|
||||||
|
{ init: 0.01 }, // [16] attack
|
||||||
|
{ init: 0.3 }, // [17] decay
|
||||||
|
{ init: 0.7 }, // [18] sustain
|
||||||
|
{ init: 0.5 }, // [19] release
|
||||||
|
{ init: 0.005 }, // [20] brightness_attack
|
||||||
|
{ init: 0.15 }, // [21] brightness_decay
|
||||||
|
{ init: 0.4 }, // [22] brightness_sustain
|
||||||
|
{ init: 0.3 }, // [23] brightness_release
|
||||||
|
{ init: 0.5 }, // [24] spectral_flux_rate
|
||||||
|
{ init: 0.1 }, // [25] spectral_flux_depth
|
||||||
|
|
||||||
|
// 3_Phase (params 24–31)
|
||||||
|
{ init: 0 }, // [26] phase_random
|
||||||
|
{ init: 0 }, // [27] phase_walk_rate
|
||||||
|
{ init: 0 }, // [28] beating_depth
|
||||||
|
{ init: 1 }, // [29] beating_rate
|
||||||
|
{ init: 0.1 }, // [30] stereo_phase_spread
|
||||||
|
{ init: 0 }, // [31] noise_floor
|
||||||
|
{ init: 0.5 }, // [32] noise_color
|
||||||
|
{ init: 0 }, // [33] sub_harmonic
|
||||||
|
|
||||||
|
// 4_Modulation (params 32–41)
|
||||||
|
{ init: 5 }, // [34] vibrato_rate
|
||||||
|
{ init: 0 }, // [35] vibrato_depth
|
||||||
|
{ init: 0.3 }, // [36] vibrato_delay
|
||||||
|
{ init: 4 }, // [37] tremolo_rate
|
||||||
|
{ init: 0 }, // [38] tremolo_depth
|
||||||
|
{ init: 0 }, // [39] drift_rate
|
||||||
|
{ init: 0 }, // [40] drift_depth
|
||||||
|
{ init: 3 }, // [41] formant1_freq
|
||||||
|
{ init: 6 }, // [42] formant2_freq
|
||||||
|
{ init: 0 }, // [43] formant_depth
|
||||||
|
|
||||||
|
// 5_Master (params 42–47)
|
||||||
|
{ init: 0.7 }, // [44] level
|
||||||
|
{ init: 0.5 }, // [45] vel_sens
|
||||||
|
{ init: 0.3 }, // [46] vel_brightness
|
||||||
|
{ init: 0 }, // [47] pitch_glide
|
||||||
|
{ init: 0 }, // [48] saturation
|
||||||
|
{ init: 0 }, // [49] fine_tune
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
_paramDefsLength() {
|
||||||
|
return this._paramDefs().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// _onSetParam — called when the main thread sends { type: 'setParam' }
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_onSetParam(index, value) {
|
||||||
|
if (!this._dspInst) return;
|
||||||
|
const zone = this._paramZones[index];
|
||||||
|
if (!zone) return;
|
||||||
|
this._dspInst.exports.setParamValue(DSP, zone, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// _onNoteOn — set freq and open the gate
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_onNoteOn(freq, vel) {
|
||||||
|
if (!this._dspInst) return;
|
||||||
|
this._currentVel = vel ?? 0.7;
|
||||||
|
const ex = this._dspInst.exports;
|
||||||
|
if (this._freqZone) ex.setParamValue(DSP, this._freqZone, freq);
|
||||||
|
if (this._gateZone) ex.setParamValue(DSP, this._gateZone, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// _onNoteOff — close the gate (DSP release envelope takes over)
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_onNoteOff(_freq) {
|
||||||
|
if (!this._dspInst) return;
|
||||||
|
if (this._gateZone) this._dspInst.exports.setParamValue(DSP, this._gateZone, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// _renderBlock — fill stereo output buffers each block
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_renderBlock(outL, outR, blockSize) {
|
||||||
|
if (!this._dspInst || !this._dspMemory) return;
|
||||||
|
|
||||||
|
const ex = this._dspInst.exports;
|
||||||
|
|
||||||
|
// Call Faust compute: compute(dsp, n, input_channels_ptr, output_channels_ptr)
|
||||||
|
// For 0 inputs, input_channels_ptr = 0 (null pointer is safe for Faust)
|
||||||
|
ex.compute(DSP, blockSize, 0, this._outPtrsAddr);
|
||||||
|
|
||||||
|
// Copy WASM output buffers to AudioWorklet output Float32Arrays
|
||||||
|
const wL = new Float32Array(ex.memory.buffer, this._outLAddr, blockSize);
|
||||||
|
const wR = new Float32Array(ex.memory.buffer, this._outRAddr, blockSize);
|
||||||
|
outL.set(wL);
|
||||||
|
outR.set(wR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Register the processor
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
registerProcessor('additive-processor', AdditiveProcessor);
|
||||||
|
|
@ -1,10 +1,279 @@
|
||||||
// additive.dsp — placeholder additive oscillator bank
|
// additive.dsp — Full 48-parameter additive synthesiser for MEMLNaut NISPS playground
|
||||||
// 4 harmonics with configurable frequency and amplitude.
|
//
|
||||||
// This is a pipeline-proving stub; the full 48-param additive engine
|
// 64 harmonic sine banks with spectral-descriptor parametrisation.
|
||||||
// is implemented in meml-pj4.
|
// All 48 params are designed for continuous ML exploration via NISPS.
|
||||||
|
//
|
||||||
|
// Parameter order matches NISPS output indices 0–47:
|
||||||
|
// Group 1 — Spectral Shape (0–13): harmonic bank + tilt + inharmonicity + odd/even
|
||||||
|
// Group 2 — Temporal (14–23): global ADSR + brightness ADSR + spectral flux
|
||||||
|
// Group 3 — Phase (24–31): phase randomisation, beating, stereo, noise, sub
|
||||||
|
// Group 4 — Modulation (32–41): vibrato, tremolo, drift, formants
|
||||||
|
// Group 5 — Master (42–47): level, velocity, glide, saturation, fine-tune
|
||||||
|
//
|
||||||
|
// Groups are prefixed "1_", "2_" etc., and each parameter is prefixed "00_",
|
||||||
|
// "01_" etc., so that Faust's alphabetical JSON ordering matches the spec.
|
||||||
|
// The faustJsonToParamMeta parser strips numeric prefixes and "[...]" metadata
|
||||||
|
// from labels to produce clean names.
|
||||||
|
//
|
||||||
|
// Hidden controls (not in paramMeta — worklet drives them directly):
|
||||||
|
// freq — fundamental frequency Hz (noteOn)
|
||||||
|
// gate — gate signal 0/1 (noteOn/noteOff)
|
||||||
|
//
|
||||||
|
// Build:
|
||||||
|
// faust -lang wasm -cn additive -e additive.dsp -o additive.wasm
|
||||||
|
// faust -json additive.dsp -o /dev/null (produces additive.dsp.json)
|
||||||
|
//
|
||||||
import("stdfaust.lib");
|
import("stdfaust.lib");
|
||||||
|
|
||||||
freq = hslider("freq[unit:Hz]", 220, 20, 4000, 0.1);
|
// ---------------------------------------------------------------------------
|
||||||
amp = hslider("amp", 0.5, 0, 1, 0.001);
|
// Hidden controls
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
freq = hslider("0_Hidden/freq[hidden:1][unit:Hz]", 220, 20, 4000, 0.01);
|
||||||
|
gate = button("0_Hidden/gate[hidden:1]");
|
||||||
|
|
||||||
process = sum(i, 4, amp * (1.0/(i+1)) * os.osc(freq * (i+1))) <: _,_;
|
// ---------------------------------------------------------------------------
|
||||||
|
// Group 1 — Spectral Shape (params 0–13)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
h1_amp = hslider("1_Spectral Shape/00_h1_amp[tooltip:H1 amplitude]", 0.8, 0, 1, 0.001);
|
||||||
|
h2_amp = hslider("1_Spectral Shape/01_h2_amp[tooltip:H2 amplitude]", 0.5, 0, 1, 0.001);
|
||||||
|
h3_amp = hslider("1_Spectral Shape/02_h3_amp[tooltip:H3 amplitude]", 0.35, 0, 1, 0.001);
|
||||||
|
h4_amp = hslider("1_Spectral Shape/03_h4_amp[tooltip:H4 amplitude]", 0.25, 0, 1, 0.001);
|
||||||
|
h5_amp = hslider("1_Spectral Shape/04_h5_amp[tooltip:H5 amplitude]", 0.18, 0, 1, 0.001);
|
||||||
|
h6_amp = hslider("1_Spectral Shape/05_h6_amp[tooltip:H6 amplitude]", 0.12, 0, 1, 0.001);
|
||||||
|
h7_amp = hslider("1_Spectral Shape/06_h7_amp[tooltip:H7 amplitude]", 0.08, 0, 1, 0.001);
|
||||||
|
h8_amp = hslider("1_Spectral Shape/07_h8_amp[tooltip:H8 amplitude]", 0.06, 0, 1, 0.001);
|
||||||
|
h9_16_amp = hslider("1_Spectral Shape/08_h9_16_amp[tooltip:H9-16 group amp]", 0.05, 0, 1, 0.001);
|
||||||
|
h17_32_amp = hslider("1_Spectral Shape/09_h17_32_amp[tooltip:H17-32 group amp]",0.025, 0, 1, 0.001);
|
||||||
|
h33_64_amp = hslider("1_Spectral Shape/10_h33_64_amp[tooltip:H33-64 group amp]",0.01, 0, 1, 0.001);
|
||||||
|
spectral_tilt = hslider("1_Spectral Shape/11_spectral_tilt[tooltip:Global tilt]", 0, -1, 1, 0.001);
|
||||||
|
inharmonicity = hslider("1_Spectral Shape/12_inharmonicity[tooltip:Inharmonicity]", 0, 0, 0.15, 0.0001);
|
||||||
|
odd_even = hslider("1_Spectral Shape/13_odd_even[tooltip:Odd/even balance]", 0.5, 0, 1, 0.001);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Group 2 — Temporal (params 14–23)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
attack = hslider("2_Temporal/00_attack[scale:log][tooltip:Attack]", 0.01, 0.001, 5, 0.001);
|
||||||
|
decay = hslider("2_Temporal/01_decay[tooltip:Decay]", 0.3, 0.001, 10, 0.001);
|
||||||
|
sustain = hslider("2_Temporal/02_sustain[tooltip:Sustain]", 0.7, 0, 1, 0.001);
|
||||||
|
release = hslider("2_Temporal/03_release[tooltip:Release]", 0.5, 0.01, 10, 0.001);
|
||||||
|
brightness_attack = hslider("2_Temporal/04_brightness_attack[scale:log][tooltip:Bright A]", 0.005, 0.001, 5, 0.001);
|
||||||
|
brightness_decay = hslider("2_Temporal/05_brightness_decay[tooltip:Bright D]", 0.15, 0.001, 5, 0.001);
|
||||||
|
brightness_sustain = hslider("2_Temporal/06_brightness_sustain[tooltip:Bright S]", 0.4, 0, 1, 0.001);
|
||||||
|
brightness_release = hslider("2_Temporal/07_brightness_release[tooltip:Bright R]", 0.3, 0.01, 5, 0.001);
|
||||||
|
spectral_flux_rate = hslider("2_Temporal/08_spectral_flux_rate[tooltip:Flux rate]", 0.5, 0, 10, 0.01);
|
||||||
|
spectral_flux_depth= hslider("2_Temporal/09_spectral_flux_depth[tooltip:Flux depth]", 0.1, 0, 1, 0.001);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Group 3 — Phase & Coherence (params 24–31)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
phase_random = hslider("3_Phase/00_phase_random[tooltip:Phase randomisation]", 0, 0, 1, 0.001);
|
||||||
|
phase_walk_rate = hslider("3_Phase/01_phase_walk_rate[tooltip:Phase walk rate]", 0, 0, 5, 0.001);
|
||||||
|
beating_depth = hslider("3_Phase/02_beating_depth[tooltip:Beating depth]", 0, 0, 0.02, 0.0001);
|
||||||
|
beating_rate = hslider("3_Phase/03_beating_rate[tooltip:Beating rate]", 1, 0, 10, 0.01);
|
||||||
|
stereo_phase_spread= hslider("3_Phase/04_stereo_phase_spread[tooltip:Stereo spread]", 0.1, 0, 1, 0.001);
|
||||||
|
noise_floor = hslider("3_Phase/05_noise_floor[tooltip:Noise floor]", 0, 0, 0.2, 0.001);
|
||||||
|
noise_color = hslider("3_Phase/06_noise_color[tooltip:Noise colour]", 0.5, 0, 1, 0.001);
|
||||||
|
sub_harmonic = hslider("3_Phase/07_sub_harmonic[tooltip:Sub-harmonic]", 0, 0, 1, 0.001);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Group 4 — Modulation (params 32–41)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
vibrato_rate = hslider("4_Modulation/00_vibrato_rate[tooltip:Vibrato rate]", 5, 0, 10, 0.01);
|
||||||
|
vibrato_depth = hslider("4_Modulation/01_vibrato_depth[tooltip:Vibrato depth]", 0, 0, 0.05, 0.0001);
|
||||||
|
vibrato_delay = hslider("4_Modulation/02_vibrato_delay[tooltip:Vibrato delay]", 0.3, 0, 2, 0.001);
|
||||||
|
tremolo_rate = hslider("4_Modulation/03_tremolo_rate[tooltip:Tremolo rate]", 4, 0, 20, 0.01);
|
||||||
|
tremolo_depth = hslider("4_Modulation/04_tremolo_depth[tooltip:Tremolo depth]", 0, 0, 1, 0.001);
|
||||||
|
drift_rate = hslider("4_Modulation/05_drift_rate[tooltip:Drift rate]", 0, 0, 2, 0.001);
|
||||||
|
drift_depth = hslider("4_Modulation/06_drift_depth[tooltip:Drift depth]", 0, 0, 0.3, 0.001);
|
||||||
|
formant1_freq = hslider("4_Modulation/07_formant1_freq[tooltip:Formant 1 freq]",3, 1, 16, 0.01);
|
||||||
|
formant2_freq = hslider("4_Modulation/08_formant2_freq[tooltip:Formant 2 freq]",6, 1, 16, 0.01);
|
||||||
|
formant_depth = hslider("4_Modulation/09_formant_depth[tooltip:Formant depth]", 0, 0, 1, 0.001);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Group 5 — Master (params 42–47)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
level = hslider("5_Master/00_level[tooltip:Output level]", 0.7, 0, 1, 0.001);
|
||||||
|
vel_sens = hslider("5_Master/01_vel_sens[tooltip:Velocity sens]", 0.5, 0, 1, 0.001);
|
||||||
|
vel_bright = hslider("5_Master/02_vel_brightness[tooltip:Vel bright]",0.3, 0, 1, 0.001);
|
||||||
|
pitch_glide= hslider("5_Master/03_pitch_glide[tooltip:Portamento]", 0, 0, 10, 0.01);
|
||||||
|
saturation = hslider("5_Master/04_saturation[tooltip:Saturation]", 0, 0, 1, 0.001);
|
||||||
|
fine_tune = hslider("5_Master/05_fine_tune[unit:ct][tooltip:Cents]", 0, -50, 50, 0.1);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Internal constants
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
N = 64;
|
||||||
|
PI = ma.PI;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Pitch — portamento + fine tune
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
glide_tau = 0.0001 + pitch_glide * 0.2;
|
||||||
|
fine_ratio = pow(2.0, fine_tune / 1200.0);
|
||||||
|
freq_smooth = freq * fine_ratio : si.smooth(ba.tau2pole(glide_tau));
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Vibrato LFO — delayed onset via slow-attack envelope
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
vibrato_env = en.adsr(vibrato_delay, 0.01, 1.0, 0.5, gate);
|
||||||
|
vibrato_lfo = os.osc(vibrato_rate) * vibrato_depth * vibrato_env;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Tremolo LFO
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
tremolo_lfo = 1.0 - tremolo_depth * 0.5 * (1.0 + os.osc(tremolo_rate));
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Global amplitude ADSR
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
amp_env = en.adsr(attack, decay, sustain, release, gate);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Brightness envelope — controls high harmonic amplitude over time
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
bright_env = en.adsr(brightness_attack, brightness_decay,
|
||||||
|
brightness_sustain, brightness_release, gate);
|
||||||
|
bright_blend(k) = float(k - 1) / float(N - 1);
|
||||||
|
bright_factor(k) = 1.0 - bright_blend(k) + bright_blend(k) * bright_env;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Spectral flux — slow LFO on upper harmonic amplitudes
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
flux_lfo = os.osc(spectral_flux_rate);
|
||||||
|
flux_factor(k) = ba.if(k > 8,
|
||||||
|
1.0 + spectral_flux_depth * flux_lfo * bright_blend(k),
|
||||||
|
1.0);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Drift — slow random walk on per-partial amplitudes
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
drift_lfo(k) = no.noise * (float(k % 7 + 1) / 7.0)
|
||||||
|
: fi.lowpass(1, max(0.1, drift_rate * 2.0))
|
||||||
|
: *(drift_depth);
|
||||||
|
drift_factor(k) = 1.0 + drift_lfo(k);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Per-harmonic base amplitude from group sliders
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
group_amp(k) =
|
||||||
|
ba.if(k == 1, h1_amp,
|
||||||
|
ba.if(k == 2, h2_amp,
|
||||||
|
ba.if(k == 3, h3_amp,
|
||||||
|
ba.if(k == 4, h4_amp,
|
||||||
|
ba.if(k == 5, h5_amp,
|
||||||
|
ba.if(k == 6, h6_amp,
|
||||||
|
ba.if(k == 7, h7_amp,
|
||||||
|
ba.if(k == 8, h8_amp,
|
||||||
|
ba.if(k <= 16, h9_16_amp,
|
||||||
|
ba.if(k <= 32, h17_32_amp,
|
||||||
|
h33_64_amp))))))))));
|
||||||
|
|
||||||
|
// Spectral tilt: amp *= k^tilt (k=1 is always unity)
|
||||||
|
tilt_factor(k) = pow(float(k), spectral_tilt);
|
||||||
|
|
||||||
|
// Odd/even balance: ×2 so unity gain at odd_even=0.5
|
||||||
|
odd_weight = (1.0 - odd_even) * 2.0;
|
||||||
|
even_weight = odd_even * 2.0;
|
||||||
|
odd_even_factor(k) = ba.if(k % 2 == 0, even_weight, odd_weight);
|
||||||
|
|
||||||
|
// Combined raw amplitude
|
||||||
|
harm_amp_raw(k) = group_amp(k) * tilt_factor(k) * odd_even_factor(k);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Formant shaping — two Gaussian bumps in harmonic-index space
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
sigma_sq = 1.5 * 1.5;
|
||||||
|
formant_bump(k, ctr) = exp(-0.5 * (float(k) - ctr) * (float(k) - ctr) / sigma_sq);
|
||||||
|
formant_factor(k) =
|
||||||
|
1.0 + formant_depth * (formant_bump(k, formant1_freq) + formant_bump(k, formant2_freq));
|
||||||
|
|
||||||
|
harm_amp(k) = harm_amp_raw(k) * formant_factor(k);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Inharmonic partial frequency: freq_k = k*f0*(1 + B*(k^2 - 1))
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
harm_freq(k) = freq_smooth * float(k)
|
||||||
|
* (1.0 + inharmonicity * (float(k) * float(k) - 1.0));
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Phase randomisation — adds per-harmonic noise to the oscillator frequency,
|
||||||
|
// gradually dephasing partials (phase_random=0: phase-locked, =1: random)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
phase_rand_lfo(k) = no.noise * (float((k * 17 + 3) % 31 + 1) / 31.0)
|
||||||
|
: si.smooth(ba.tau2pole(0.05))
|
||||||
|
: *(phase_random * harm_freq(k) * 0.01);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Phase random walk — slower independent drift per partial
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
phase_walk(k) = no.noise * (float(k % 7 + 1) / 7.0)
|
||||||
|
: si.smooth(ba.tau2pole(0.1))
|
||||||
|
: *(phase_walk_rate);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Inter-partial beating — sinusoidal detuning stagger
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
beating_offset(k) = beating_depth
|
||||||
|
* os.osc(beating_rate * float(k % 3 + 1) * 0.7)
|
||||||
|
* harm_freq(k);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Stereo spread — R channel gets a small per-harmonic pitch offset
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
stereo_spread_freq(k) = stereo_phase_spread * float(k) * 0.01;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Additive oscillator sums — L and R
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
additive_L = sum(k, N,
|
||||||
|
harm_amp(k+1) * bright_factor(k+1) * flux_factor(k+1) * drift_factor(k+1) *
|
||||||
|
os.osc( harm_freq(k+1) * (1.0 + vibrato_lfo)
|
||||||
|
+ beating_offset(k+1)
|
||||||
|
+ phase_rand_lfo(k+1)
|
||||||
|
+ phase_walk(k+1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
additive_R = sum(k, N,
|
||||||
|
harm_amp(k+1) * bright_factor(k+1) * flux_factor(k+1) * drift_factor(k+1) *
|
||||||
|
os.osc( harm_freq(k+1) * (1.0 + vibrato_lfo + stereo_spread_freq(k+1))
|
||||||
|
+ beating_offset(k+1)
|
||||||
|
+ phase_rand_lfo(k+1)
|
||||||
|
+ phase_walk(k+1)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Sub-harmonic (0.5× fundamental)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
sub_osc = sub_harmonic * os.osc(freq_smooth * 0.5);
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Noise floor — coloured via one-pole LP (noise_color=0→white, =1→dark)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
noise_lp_cutoff = 200.0 + (1.0 - noise_color) * 19800.0;
|
||||||
|
noise_signal = no.noise : fi.lowpass(1, noise_lp_cutoff);
|
||||||
|
noise_out = noise_floor * noise_signal;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Soft-clip saturation — tanh waveshaper
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
drive = 1.0 + saturation * 9.0;
|
||||||
|
softclip(x) = ma.tanh(x * drive) / drive;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Output gain
|
||||||
|
// vel_bright modulates how much the brightness envelope boosts the overall
|
||||||
|
// level during note onset (couples velocity sensitivity to brightness).
|
||||||
|
// Here it acts as a subtle mid-term gain shaper via the bright_env signal.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
vel_bright_boost = 1.0 + vel_bright * bright_env * 0.3;
|
||||||
|
out_gain = level * (1.0 - vel_sens * 0.3) * vel_bright_boost;
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Final assembly
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
signal_L = (additive_L + sub_osc + noise_out) * amp_env * tremolo_lfo * out_gain;
|
||||||
|
signal_R = (additive_R + sub_osc + noise_out) * amp_env * tremolo_lfo * out_gain;
|
||||||
|
|
||||||
|
process = softclip(signal_L), softclip(signal_R);
|
||||||
|
|
|
||||||
758
playground/faust/additive.json
Normal file
758
playground/faust/additive.json
Normal file
|
|
@ -0,0 +1,758 @@
|
||||||
|
{
|
||||||
|
"name": "additive",
|
||||||
|
"filename": "additive.dsp",
|
||||||
|
"version": "2.83.1",
|
||||||
|
"compile_options": "-lang cpp -fpga-mem-th 4 -ct 1 -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0",
|
||||||
|
"library_list": ["/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/stdfaust.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/envelopes.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/maths.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/platform.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/oscillators.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/basics.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/noises.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/filters.lib","/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust/signals.lib"],
|
||||||
|
"include_pathnames": ["/nix/store/fnjbalzgc6pjm8la292cczxqbr00qmav-faust-2.83.1/share/faust","/usr/local/share/faust","/usr/share/faust",".","/home/w1n5t0n/src/MEMLNaut-NISPS/.claude/worktrees/agent-ae51af34/.claude/worktrees/agent-a667e616/playground/faust"],
|
||||||
|
"size": 1908,
|
||||||
|
"inputs": 0,
|
||||||
|
"outputs": 2,
|
||||||
|
"meta": [
|
||||||
|
{ "basics.lib/name": "Faust Basic Element Library" },
|
||||||
|
{ "basics.lib/version": "1.22.0" },
|
||||||
|
{ "compile_options": "-lang cpp -fpga-mem-th 4 -ct 1 -es 1 -mcd 16 -mdd 1024 -mdy 33 -single -ftz 0" },
|
||||||
|
{ "envelopes.lib/adsr:author": "Yann Orlarey and Andrey Bundin" },
|
||||||
|
{ "envelopes.lib/author": "GRAME" },
|
||||||
|
{ "envelopes.lib/copyright": "GRAME" },
|
||||||
|
{ "envelopes.lib/license": "LGPL with exception" },
|
||||||
|
{ "envelopes.lib/name": "Faust Envelope Library" },
|
||||||
|
{ "envelopes.lib/version": "1.3.0" },
|
||||||
|
{ "filename": "additive.dsp" },
|
||||||
|
{ "filters.lib/lowpass0_highpass1": "MIT-style STK-4.3 license" },
|
||||||
|
{ "filters.lib/lowpass0_highpass1:author": "Julius O. Smith III" },
|
||||||
|
{ "filters.lib/lowpass:author": "Julius O. Smith III" },
|
||||||
|
{ "filters.lib/lowpass:copyright": "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>" },
|
||||||
|
{ "filters.lib/lowpass:license": "MIT-style STK-4.3 license" },
|
||||||
|
{ "filters.lib/name": "Faust Filters Library" },
|
||||||
|
{ "filters.lib/tf1:author": "Julius O. Smith III" },
|
||||||
|
{ "filters.lib/tf1:copyright": "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>" },
|
||||||
|
{ "filters.lib/tf1:license": "MIT-style STK-4.3 license" },
|
||||||
|
{ "filters.lib/tf1s:author": "Julius O. Smith III" },
|
||||||
|
{ "filters.lib/tf1s:copyright": "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>" },
|
||||||
|
{ "filters.lib/tf1s:license": "MIT-style STK-4.3 license" },
|
||||||
|
{ "filters.lib/version": "1.7.1" },
|
||||||
|
{ "maths.lib/author": "GRAME" },
|
||||||
|
{ "maths.lib/copyright": "GRAME" },
|
||||||
|
{ "maths.lib/license": "LGPL with exception" },
|
||||||
|
{ "maths.lib/name": "Faust Math Library" },
|
||||||
|
{ "maths.lib/version": "2.9.0" },
|
||||||
|
{ "name": "additive" },
|
||||||
|
{ "noises.lib/name": "Faust Noise Generator Library" },
|
||||||
|
{ "noises.lib/version": "1.5.0" },
|
||||||
|
{ "oscillators.lib/name": "Faust Oscillator Library" },
|
||||||
|
{ "oscillators.lib/version": "1.6.0" },
|
||||||
|
{ "platform.lib/name": "Generic Platform Library" },
|
||||||
|
{ "platform.lib/version": "1.3.0" },
|
||||||
|
{ "signals.lib/name": "Faust Signal Routing Library" },
|
||||||
|
{ "signals.lib/version": "1.6.0" }
|
||||||
|
],
|
||||||
|
"ui": [
|
||||||
|
{
|
||||||
|
"type": "vgroup",
|
||||||
|
"label": "additive",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "0_Hidden/freq",
|
||||||
|
"varname": "fHslider19",
|
||||||
|
"shortname": "0_Hidden_freq",
|
||||||
|
"address": "/additive/0_Hidden_freq",
|
||||||
|
"meta": [
|
||||||
|
{ "hidden": "1" },
|
||||||
|
{ "unit": "Hz" }
|
||||||
|
],
|
||||||
|
"init": 220,
|
||||||
|
"min": 20,
|
||||||
|
"max": 4000,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "button",
|
||||||
|
"label": "0_Hidden/gate",
|
||||||
|
"varname": "fButton0",
|
||||||
|
"shortname": "0_Hidden_gate",
|
||||||
|
"address": "/additive/0_Hidden_gate",
|
||||||
|
"meta": [
|
||||||
|
{ "hidden": "1" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/00_h1_amp",
|
||||||
|
"varname": "fHslider41",
|
||||||
|
"shortname": "1_Spectral_Shape_00_h1_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_00_h1_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H1 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.8,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/01_h2_amp",
|
||||||
|
"varname": "fHslider40",
|
||||||
|
"shortname": "1_Spectral_Shape_01_h2_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_01_h2_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H2 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.5,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/02_h3_amp",
|
||||||
|
"varname": "fHslider39",
|
||||||
|
"shortname": "1_Spectral_Shape_02_h3_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_02_h3_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H3 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.35,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/03_h4_amp",
|
||||||
|
"varname": "fHslider38",
|
||||||
|
"shortname": "1_Spectral_Shape_03_h4_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_03_h4_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H4 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.25,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/04_h5_amp",
|
||||||
|
"varname": "fHslider37",
|
||||||
|
"shortname": "1_Spectral_Shape_04_h5_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_04_h5_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H5 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.18,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/05_h6_amp",
|
||||||
|
"varname": "fHslider36",
|
||||||
|
"shortname": "1_Spectral_Shape_05_h6_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_05_h6_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H6 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.12,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/06_h7_amp",
|
||||||
|
"varname": "fHslider35",
|
||||||
|
"shortname": "1_Spectral_Shape_06_h7_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_06_h7_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H7 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.08,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/07_h8_amp",
|
||||||
|
"varname": "fHslider34",
|
||||||
|
"shortname": "1_Spectral_Shape_07_h8_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_07_h8_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H8 amplitude" }
|
||||||
|
],
|
||||||
|
"init": 0.06,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/08_h9_16_amp",
|
||||||
|
"varname": "fHslider33",
|
||||||
|
"shortname": "1_Spectral_Shape_08_h9_16_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_08_h9_16_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H9-16 group amp" }
|
||||||
|
],
|
||||||
|
"init": 0.05,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/09_h17_32_amp",
|
||||||
|
"varname": "fHslider32",
|
||||||
|
"shortname": "1_Spectral_Shape_09_h17_32_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_09_h17_32_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H17-32 group amp" }
|
||||||
|
],
|
||||||
|
"init": 0.025,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/10_h33_64_amp",
|
||||||
|
"varname": "fHslider30",
|
||||||
|
"shortname": "1_Spectral_Shape_10_h33_64_amp",
|
||||||
|
"address": "/additive/1_Spectral_Shape_10_h33_64_amp",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "H33-64 group amp" }
|
||||||
|
],
|
||||||
|
"init": 0.01,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/11_spectral_tilt",
|
||||||
|
"varname": "fHslider29",
|
||||||
|
"shortname": "1_Spectral_Shape_11_spectral_tilt",
|
||||||
|
"address": "/additive/1_Spectral_Shape_11_spectral_tilt",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Global tilt" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": -1,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/12_inharmonicity",
|
||||||
|
"varname": "fHslider20",
|
||||||
|
"shortname": "1_Spectral_Shape_12_inharmonicity",
|
||||||
|
"address": "/additive/1_Spectral_Shape_12_inharmonicity",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Inharmonicity" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 0.15,
|
||||||
|
"step": 0.0001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "1_Spectral Shape/13_odd_even",
|
||||||
|
"varname": "fHslider31",
|
||||||
|
"shortname": "1_Spectral_Shape_13_odd_even",
|
||||||
|
"address": "/additive/1_Spectral_Shape_13_odd_even",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Odd/even balance" }
|
||||||
|
],
|
||||||
|
"init": 0.5,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/00_attack",
|
||||||
|
"varname": "fHslider8",
|
||||||
|
"shortname": "2_Temporal_00_attack",
|
||||||
|
"address": "/additive/2_Temporal_00_attack",
|
||||||
|
"meta": [
|
||||||
|
{ "scale": "log" },
|
||||||
|
{ "tooltip": "Attack" }
|
||||||
|
],
|
||||||
|
"init": 0.01,
|
||||||
|
"min": 0.001,
|
||||||
|
"max": 5,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/01_decay",
|
||||||
|
"varname": "fHslider9",
|
||||||
|
"shortname": "2_Temporal_01_decay",
|
||||||
|
"address": "/additive/2_Temporal_01_decay",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Decay" }
|
||||||
|
],
|
||||||
|
"init": 0.3,
|
||||||
|
"min": 0.001,
|
||||||
|
"max": 10,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/02_sustain",
|
||||||
|
"varname": "fHslider10",
|
||||||
|
"shortname": "2_Temporal_02_sustain",
|
||||||
|
"address": "/additive/2_Temporal_02_sustain",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Sustain" }
|
||||||
|
],
|
||||||
|
"init": 0.7,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/03_release",
|
||||||
|
"varname": "fHslider7",
|
||||||
|
"shortname": "2_Temporal_03_release",
|
||||||
|
"address": "/additive/2_Temporal_03_release",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Release" }
|
||||||
|
],
|
||||||
|
"init": 0.5,
|
||||||
|
"min": 0.01,
|
||||||
|
"max": 10,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/04_brightness_attack",
|
||||||
|
"varname": "fHslider1",
|
||||||
|
"shortname": "2_Temporal_04_brightness_attack",
|
||||||
|
"address": "/additive/2_Temporal_04_brightness_attack",
|
||||||
|
"meta": [
|
||||||
|
{ "scale": "log" },
|
||||||
|
{ "tooltip": "Bright A" }
|
||||||
|
],
|
||||||
|
"init": 0.005,
|
||||||
|
"min": 0.001,
|
||||||
|
"max": 5,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/05_brightness_decay",
|
||||||
|
"varname": "fHslider2",
|
||||||
|
"shortname": "2_Temporal_05_brightness_decay",
|
||||||
|
"address": "/additive/2_Temporal_05_brightness_decay",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Bright D" }
|
||||||
|
],
|
||||||
|
"init": 0.15,
|
||||||
|
"min": 0.001,
|
||||||
|
"max": 5,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/06_brightness_sustain",
|
||||||
|
"varname": "fHslider3",
|
||||||
|
"shortname": "2_Temporal_06_brightness_sustain",
|
||||||
|
"address": "/additive/2_Temporal_06_brightness_sustain",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Bright S" }
|
||||||
|
],
|
||||||
|
"init": 0.4,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/07_brightness_release",
|
||||||
|
"varname": "fHslider0",
|
||||||
|
"shortname": "2_Temporal_07_brightness_release",
|
||||||
|
"address": "/additive/2_Temporal_07_brightness_release",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Bright R" }
|
||||||
|
],
|
||||||
|
"init": 0.3,
|
||||||
|
"min": 0.01,
|
||||||
|
"max": 5,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/08_spectral_flux_rate",
|
||||||
|
"varname": "fHslider22",
|
||||||
|
"shortname": "2_Temporal_08_spectral_flux_rate",
|
||||||
|
"address": "/additive/2_Temporal_08_spectral_flux_rate",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Flux rate" }
|
||||||
|
],
|
||||||
|
"init": 0.5,
|
||||||
|
"min": 0,
|
||||||
|
"max": 10,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "2_Temporal/09_spectral_flux_depth",
|
||||||
|
"varname": "fHslider23",
|
||||||
|
"shortname": "2_Temporal_09_spectral_flux_depth",
|
||||||
|
"address": "/additive/2_Temporal_09_spectral_flux_depth",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Flux depth" }
|
||||||
|
],
|
||||||
|
"init": 0.1,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/00_phase_random",
|
||||||
|
"varname": "fHslider11",
|
||||||
|
"shortname": "3_Phase_00_phase_random",
|
||||||
|
"address": "/additive/3_Phase_00_phase_random",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Phase randomisation" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/01_phase_walk_rate",
|
||||||
|
"varname": "fHslider21",
|
||||||
|
"shortname": "3_Phase_01_phase_walk_rate",
|
||||||
|
"address": "/additive/3_Phase_01_phase_walk_rate",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Phase walk rate" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 5,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/02_beating_depth",
|
||||||
|
"varname": "fHslider13",
|
||||||
|
"shortname": "3_Phase_02_beating_depth",
|
||||||
|
"address": "/additive/3_Phase_02_beating_depth",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Beating depth" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 0.02,
|
||||||
|
"step": 0.0001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/03_beating_rate",
|
||||||
|
"varname": "fHslider12",
|
||||||
|
"shortname": "3_Phase_03_beating_rate",
|
||||||
|
"address": "/additive/3_Phase_03_beating_rate",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Beating rate" }
|
||||||
|
],
|
||||||
|
"init": 1,
|
||||||
|
"min": 0,
|
||||||
|
"max": 10,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/04_stereo_phase_spread",
|
||||||
|
"varname": "fHslider48",
|
||||||
|
"shortname": "3_Phase_04_stereo_phase_spread",
|
||||||
|
"address": "/additive/3_Phase_04_stereo_phase_spread",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Stereo spread" }
|
||||||
|
],
|
||||||
|
"init": 0.1,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/05_noise_floor",
|
||||||
|
"varname": "fHslider43",
|
||||||
|
"shortname": "3_Phase_05_noise_floor",
|
||||||
|
"address": "/additive/3_Phase_05_noise_floor",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Noise floor" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 0.2,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/06_noise_color",
|
||||||
|
"varname": "fHslider42",
|
||||||
|
"shortname": "3_Phase_06_noise_color",
|
||||||
|
"address": "/additive/3_Phase_06_noise_color",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Noise colour" }
|
||||||
|
],
|
||||||
|
"init": 0.5,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "3_Phase/07_sub_harmonic",
|
||||||
|
"varname": "fHslider44",
|
||||||
|
"shortname": "3_Phase_07_sub_harmonic",
|
||||||
|
"address": "/additive/3_Phase_07_sub_harmonic",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Sub-harmonic" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/00_vibrato_rate",
|
||||||
|
"varname": "fHslider15",
|
||||||
|
"shortname": "4_Modulation_00_vibrato_rate",
|
||||||
|
"address": "/additive/4_Modulation_00_vibrato_rate",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Vibrato rate" }
|
||||||
|
],
|
||||||
|
"init": 5,
|
||||||
|
"min": 0,
|
||||||
|
"max": 10,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/01_vibrato_depth",
|
||||||
|
"varname": "fHslider16",
|
||||||
|
"shortname": "4_Modulation_01_vibrato_depth",
|
||||||
|
"address": "/additive/4_Modulation_01_vibrato_depth",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Vibrato depth" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 0.05,
|
||||||
|
"step": 0.0001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/02_vibrato_delay",
|
||||||
|
"varname": "fHslider14",
|
||||||
|
"shortname": "4_Modulation_02_vibrato_delay",
|
||||||
|
"address": "/additive/4_Modulation_02_vibrato_delay",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Vibrato delay" }
|
||||||
|
],
|
||||||
|
"init": 0.3,
|
||||||
|
"min": 0,
|
||||||
|
"max": 2,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/03_tremolo_rate",
|
||||||
|
"varname": "fHslider5",
|
||||||
|
"shortname": "4_Modulation_03_tremolo_rate",
|
||||||
|
"address": "/additive/4_Modulation_03_tremolo_rate",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Tremolo rate" }
|
||||||
|
],
|
||||||
|
"init": 4,
|
||||||
|
"min": 0,
|
||||||
|
"max": 20,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/04_tremolo_depth",
|
||||||
|
"varname": "fHslider6",
|
||||||
|
"shortname": "4_Modulation_04_tremolo_depth",
|
||||||
|
"address": "/additive/4_Modulation_04_tremolo_depth",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Tremolo depth" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/05_drift_rate",
|
||||||
|
"varname": "fHslider24",
|
||||||
|
"shortname": "4_Modulation_05_drift_rate",
|
||||||
|
"address": "/additive/4_Modulation_05_drift_rate",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Drift rate" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 2,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/06_drift_depth",
|
||||||
|
"varname": "fHslider25",
|
||||||
|
"shortname": "4_Modulation_06_drift_depth",
|
||||||
|
"address": "/additive/4_Modulation_06_drift_depth",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Drift depth" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 0.3,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/07_formant1_freq",
|
||||||
|
"varname": "fHslider27",
|
||||||
|
"shortname": "4_Modulation_07_formant1_freq",
|
||||||
|
"address": "/additive/4_Modulation_07_formant1_freq",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Formant 1 freq" }
|
||||||
|
],
|
||||||
|
"init": 3,
|
||||||
|
"min": 1,
|
||||||
|
"max": 16,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/08_formant2_freq",
|
||||||
|
"varname": "fHslider26",
|
||||||
|
"shortname": "4_Modulation_08_formant2_freq",
|
||||||
|
"address": "/additive/4_Modulation_08_formant2_freq",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Formant 2 freq" }
|
||||||
|
],
|
||||||
|
"init": 6,
|
||||||
|
"min": 1,
|
||||||
|
"max": 16,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "4_Modulation/09_formant_depth",
|
||||||
|
"varname": "fHslider28",
|
||||||
|
"shortname": "4_Modulation_09_formant_depth",
|
||||||
|
"address": "/additive/4_Modulation_09_formant_depth",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Formant depth" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "5_Master/00_level",
|
||||||
|
"varname": "fHslider47",
|
||||||
|
"shortname": "5_Master_00_level",
|
||||||
|
"address": "/additive/5_Master_00_level",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Output level" }
|
||||||
|
],
|
||||||
|
"init": 0.7,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "5_Master/01_vel_sens",
|
||||||
|
"varname": "fHslider46",
|
||||||
|
"shortname": "5_Master_01_vel_sens",
|
||||||
|
"address": "/additive/5_Master_01_vel_sens",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Velocity sens" }
|
||||||
|
],
|
||||||
|
"init": 0.5,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "5_Master/02_vel_brightness",
|
||||||
|
"varname": "fHslider4",
|
||||||
|
"shortname": "5_Master_02_vel_brightness",
|
||||||
|
"address": "/additive/5_Master_02_vel_brightness",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Vel bright" }
|
||||||
|
],
|
||||||
|
"init": 0.3,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "5_Master/03_pitch_glide",
|
||||||
|
"varname": "fHslider17",
|
||||||
|
"shortname": "5_Master_03_pitch_glide",
|
||||||
|
"address": "/additive/5_Master_03_pitch_glide",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Portamento" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 10,
|
||||||
|
"step": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "5_Master/04_saturation",
|
||||||
|
"varname": "fHslider45",
|
||||||
|
"shortname": "5_Master_04_saturation",
|
||||||
|
"address": "/additive/5_Master_04_saturation",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Saturation" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": 0,
|
||||||
|
"max": 1,
|
||||||
|
"step": 0.001
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "hslider",
|
||||||
|
"label": "5_Master/05_fine_tune",
|
||||||
|
"varname": "fHslider18",
|
||||||
|
"shortname": "5_Master_05_fine_tune",
|
||||||
|
"address": "/additive/5_Master_05_fine_tune",
|
||||||
|
"meta": [
|
||||||
|
{ "tooltip": "Cents" },
|
||||||
|
{ "unit": "ct" }
|
||||||
|
],
|
||||||
|
"init": 0,
|
||||||
|
"min": -50,
|
||||||
|
"max": 50,
|
||||||
|
"step": 0.1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
9213
playground/faust/additive.wasm
Normal file
9213
playground/faust/additive.wasm
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue