REF / Music API / Modulator

Ascene . Agraph . Aengine
Anode . Modulator . Envelope
Songbook . Song . TimeKeeper
Voices . SampleMgr . StreamMgr
Loader . Async . Plot
Random . Rhythm . Util
MIDI . OSC . HID . Piano
Music Theory with Tonal

right-click to navigate to page sections


Modulators drive parameter-changes in Anodes.

Currently, only built-in modulators offer this capability.

Traditionally audio synthesis engines define two (or more) kinds of signals, audio and control. Audio signals have a high, fixed sample rate and a value range of [-1, 1]. Control signals are often sampled at a fraction of the audio rate and defined over an arbitrary [min, max] range. Control signals ultimately modulate the output audio signal either directly (eg ADSR) or indirectly (eg a filter's resonance parameter).

Already your music programs can directly invoke SetParam and ModParam. What's more, you can spawn JavaScript or Lua fibers whose express purpose is to periodically update any number of Anode parameters. You can even define your own control-rate, signal patterns and targeting schemes.

Such general capabilities can be cumbersome for common modulation tricks. We provide automatic/programatic modulation to describe modulation setups and to perform them automatically within the audio engine. Several efficiencies, both in workflow and processing, are gained by expressing modulation effects indirectly.

Many popular audio engines support parameter and signal modulation via a drag-drop interface to define the modulation source and its target. In order to support multiple targets, a separate set of settings may be required to characterize the remapping of the source modulation signal. So we have two concepts here: Modulator (class) and Modulator Routing which includes:

  1. establishing connections between modulator and Anode parameter.
  2. optionally remapping the values along its connections.

Like Anodes, Modulators are created via Ascene. Unlike Anode, Modulators require special wiring into the graph through Ascene's ModulateParam method.

let ascene = await Ascene.BeginFiber(this);
let inst = ascene.NewAnode("Vital");
let lfo = ascene.NewModulator("Hz.ModLFO", "triangle");
ascene.Chain(inst, ascene.GetDAC());
ascene.ModulateParam(lfo, inst, "Oscillator 1 Pan");
await ascene.Sync();
lfo.SetParam("Frequency", .1); // .1 Hz => 10 second period.

Remap

When connecting the output of a modulator to a downstream parameter of an Anode you have the option of defining a remapper. This is done by invoking the modulator's NewRemapper method. Here's the JavaScript method signature:

NewRemapper(scale, bipolar, power=0, offset=0, mode=0)

Note that the NewRemapper method accepts up to six positional parameters. You can also invoke this method with a single parameter where the parameter is an object whose keys are any of these named parameters as shown here.

let scale = .5;
let bipolar = false;
let power = .25;
ascene.ModulateParam(lfo, inst, "Oscillator 1 Pan", 
                    lfo.NewRemapper({scale, bipolar, power}));

Parameters

Remapper Param Description
scale scale [0,1] to a range appropriate for target
bipolar (true or false) causes the scaled value to be centered around 0 (allowing negative numbers)
power controls remapping curve, 0 is linear, > 0 convex, < 0 concave, range:[-5, 5]
offset offsets values produced by the scale and bipolar values. Valuable primarily in mode:1.
mode select between 0:add and 1:set. Default is 0 but mode:1 is useful for envelopes.
home .. topics .. interface .. reference .. examples .. tipjar