Builtin Modulators procedurally modulate anode Parameters. For more motivation, see here.
Like Anodes, Modulators are created via Ascene and have their own parameters.
Unlike Anodes, Modulators generate parameter value changes and not an
audio signal. For this reason, Modulators require special wiring into
the graph through Ascene's ModulateParam
method. Modulators are either
free running
or triggered
and produce a modulation value between 0
and 1 that is often remapped
to match the range of its target parameter.
snippet
let ascene = await Ascene.BeginFiber(this);
let inst = ascene.NewAnode("Vital");
let preset = {shape: "triangle"};
let lfo = ascene.NewModulator("Hz.ModLFO", JSON.stringify(preset));
ascene.Chain(inst, ascene.GetDAC());
ascene.ModulateParam(lfo, inst, "Oscillator 1 Pan"/*parameter name*/, optionalRemapper);
await ascene.Sync();
lfo.SetParam("Frequency", .1); // .1 Hz => 10 second period.
Modulators can easily be confused with audio modulators like
Hz.LFO. Just remember that
these Modulators
are wired to external plugin parameters.
Hz.Syntho further muddies these
waters by allowing its internal module parameters to be driven by
audio modulators.
Hz.ModLFO
is the most general/versatile of the builtin parameter modulators.
The LFO shape is described by a curve that is delivered via a preset mechanism.
The preset
parameter can be one of triangle
, sine
, square
, sawUp
,
sawDown
or a shape object
with an arbitrary shape description described
below.
let lfo = ascene.NewModulator("Hz.ModLFO", "triangle");
Name | Values | Description |
---|---|---|
Trigger |
0:NoteOn, 1:NoteOff, 2:Free Running | When not free-running, the NoteOn/Off events must be delivered. |
TriggerOrigin |
0:Start, 1:Global, 2:Random, 3:Point Cycle | When triggered, this param selects the LFO temporal origin. Point Cycle proceeds from one segment in the knotlist to the next. |
Loop |
0 or 1 | |
Period |
0 - 10 (Sec) | Used only for PeriodMeasure:0 |
PeriodMeasure |
0:Seconds, 1:KeyTracked | When keytracking, we combine the key frequency with Keytrack Offset to produce the LFO period. Default is 0. |
KeytrackOffset |
-100 - 100 | Semitones to offset incoming notes in keytracking mode. Default is -12 (one octave). |
Detune |
-10 - 10 | Semitones to randomly detune target frequency in keytracking mode. Default is 0. |
Presets are string parameters encoding a JSON object with name/value parameters. You can request an LFO shape in two ways.
shape
parameterknotlist
parameterModLFO Named Preset | Description |
---|---|
phasor , sawup |
linear ramp from 0 to 1 |
sawdown |
linear ramp from 1 to 0 |
triangle |
triangle wave from 0 to 1 at midpoint to 0 |
sine |
sine-like waveform from 0 to 1 (unless bipolar) |
square |
square waveform from 0 to 1 at midpoint |
Here's the explicit representation of the square
preset. The
data array is a series of 3 numbers representing the x, y coordinates
and the power value. When power is 0 we have a line. Otherwise
when > 0 it's a convex curve and when < 0 it's concave.
The useful range for power is around -5 - 5.
{ knotlist: {
name: "square",
smooth: false,
data: [
// t, v, power
0, 1, 0,
0, 0, 0,
.5, 0, 0,
.5, 1, 0,
1, 1, 0,
]
}
}
Hz.ModRand
supports a number of random modes
to generate a
its modulation value.
// a snippet to modulate Anode osc's "Transpose" parameter.
let rand = scene.NewModulator("Hz.ModRand", {
choices: [0, 3, 7, -5, 12, -12]
});
rand.SetParam("Mode", 6); // 'choice'
scene.ModulateParam(rand, osc, "Transpose");
Name | Values | Description |
---|---|---|
Mode |
0:random, 1:random-hold, 2:lerp, 3:smooth, 4:smoother, 5:catrom, 6:choice, 7:draw | Selects the mode. When mode is 6 or 7 (choice or draw) the preset must define the choices available as shown above. |
TriggerOrigin |
0:Start, 1:Global | |
Frequency |
0 - 100 (Hz) |
Hz.ModEnv
produces a modulation envelope equivalent to
Hz.ADSR. It requires triggering
via NoteOn/Off methods. This can be done implicitly via
Voices or explicitly. As with
all modulators, use this only when you have one or more anode parameters
that you'd like to drive with note or program-triggered envelope.
code snippet
let env = scene.NewModulator("Hz.ModEnv");
let remap = env.NewRemapper({mode: 1}); // usually envelopes are set, not added
scene.ModulateParam(mod, anotherNode, "Parameter Name", remap);
Name | Description | Range | Default |
---|---|---|---|
Delay |
Time between trigger and envelope start | 0 - 10 | 0 |
A |
Attack time | 0 - 10 | 0.1 |
Apower |
Attack curve power | -10 - 10 | -3 |
D |
Decay time | 0-1 | 0.2 |
Dpower |
Decay curve power | -10 - 10 | -3 |
S |
Sustain level | 0-1 | 0.8 |
R |
Release time | 0 - 10 | 0.3 |
Rpower |
Release curve power | -10 - 10 | -3 |
T |
Tail duration (after release) | 0 - 10 | 0 |
BroadcastState |
emit NoteDone message for use by Voices | 0 or 1 | 1 |
Hz.ModExpr
is used to drive an arbitrary anode parameter via a Clap/MIDI note
expression. Instantiate an instance of Hz.ModExpr
and make sure its in a
position to receive MIDI events from a MIDI device or file. Next, use
the instance-method SelectSignal()
to establish the specific note
expression event the instance should listen (see the table below).
Finally, wire the instance into agraph using scene.ModulatorParam
and
an optional Remapper
.
code snippet
let mod = scene.NewModulator("Hz.ModExpr");
mod.SelectSignal(mod.Signals.ModWheel);
scene.ModulateParam(mod, anotherNode, "parameter name", optionalRemapper);
// make sure NoteOn/Off, NoteExpression and MIDI events are delivered to mod.
Name | Clap ID | Notes |
---|---|---|
Volume | 0 | |
Pan | 1 | |
Tuning | 2 | |
Expression | 4 | range [0-1] |
Brightness | 5 | range [0-1] |
Pressure | 6 | range [0-1] |
_reserved0 | 7 | |
_reserved1 | 8 | |
_reserved2 | 9 | |
_reserved3 | 10 | |
_reserved4 | 11 | |
_reserved5 | 12 | |
MidiCC | 13 | Select a particular MIDI CC via SelectSignal(13, ccnum) [0-1] |
ModWheel | 14 | 13: [0-1] |
Note | 15 | [0-127] |
Velocity | 16 | [0-1] |
Semitone | 17 | [0-12) |