Table of Contents

Class Control

Namespace
Sigil.Sound
Assembly
Sigil.Sound.dll

A value the game or UI sets while sound is playing, such as engine RPM or how tense the music is. The audio thread follows it smoothly, so a jump in Sigil.Sound.Control.Value (a game frame is 16 ms, a block is 5 ms) glides over slewSeconds instead of clicking. Setting it from any thread is safe and takes no lock.

public sealed class Control

Inheritance

Inherited Members

Examples

// A control is a value the game changes while the sound plays. Here an engine note follows an RPM control.
var rpm = new Control(800, min: 600, max: 7000, slewSeconds: 0.03);
var engine = Saw(rpm / 30).LowPass(rpm.Map(200, 4000, ControlCurve.Exponential));
rpm.Value = 3500;   // set from the game loop, every frame
engine * 0.3

Remarks

A control converts to a Sigil.Sound.Param and to a Sigil.Sound.Sound, so it goes anywhere a modulating value does. One control can drive any number of sounds and voices; each reads it once per block. A graph compiled later starts at the current value, with no glide from the default.

Constructors

Control(double, double, double, double, string?)

public Control(double value = 0, double min = 0, double max = 1, double slewSeconds = 0.02, string? name = null)

Parameters

value double

The starting value.

min double

The lowest value; Sigil.Sound.Control.Value is clamped to it.

max double

The highest value; Sigil.Sound.Control.Value is clamped to it.

slewSeconds double

The glide time: after this long the sound has covered about 63% of a jump. 0 follows at once, which can click on gain, pitch and cutoff.

name string?

A label for debugging and for showing the control in a UI.

Properties

Max

The highest value.

public float Max { get; }

Property Value

float

Min

The lowest value.

public float Min { get; }

Property Value

float

Name

The label given at creation, or null.

public string? Name { get; }

Property Value

string?

Options

The names of the choices when the control is a selector (see Sigil.Sound.Control.Choice(System.String,System.Collections.Generic.IReadOnlyList{System.String},System.Int32)); null otherwise. The value is the index of the chosen option and only takes whole numbers.

public IReadOnlyList<string>? Options { get; }

Property Value

IReadOnlyList<string>?

Polarity

What a signal sent to Sigil.Sound.Control.SetFromSignal(System.Double) spans. Defaults to Sigil.Sound.ControlPolarity.Unipolar.

public ControlPolarity Polarity { get; init; }

Property Value

ControlPolarity

SlewSeconds

The glide time in seconds.

public float SlewSeconds { get; }

Property Value

float

Style

The widget a host UI is advised to show. Defaults to Sigil.Sound.ControlStyle.Knob.

public ControlStyle Style { get; init; }

Property Value

ControlStyle

Taper

How a UI's travel maps onto the value; Sigil.Sound.Control.Travel applies it. A hint for a host UI: the sound does not care. Set it when creating the control: new Control(1200, 40, 18000) { Taper = ControlTaper.Log }.

public ControlTaper Taper { get; init; }

Property Value

ControlTaper

Exceptions

ArgumentOutOfRangeException

Sigil.Sound.ControlTaper.Log with a minimum that is not above zero, or an unknown taper.

Travel

The value as a position from 0 (the minimum) to 1 (the maximum), through Sigil.Sound.Control.Taper. A UI reads it to place a knob and sets it as the knob turns, so the UI never needs to know the taper. Setting it is thread-safe like Sigil.Sound.Control.Value, and the sound still glides over Sigil.Sound.Control.SlewSeconds. A selector's travel is the choice's place along its options.

public double Travel { get; set; }

Property Value

double

Examples

// A knob reports its position from 0 to 1 and the control applies the taper: half way is the geometric middle, 1000 Hz.
var cutoff = new Control(100, min: 100, max: 10000) { Taper = ControlTaper.Log };
cutoff.Travel = 0.5;
Saw(110).LowPass(cutoff) * 0.4

Exceptions

ArgumentOutOfRangeException

Set to NaN or infinity.

Value

The value the sound is heading for. Set it from any thread; out-of-range values are clamped to Sigil.Sound.Control.Min and Sigil.Sound.Control.Max.

public double Value { get; set; }

Property Value

double

Exceptions

ArgumentOutOfRangeException

The value is NaN or infinite.

Methods

Choice(string, IReadOnlyList<string>, int)

Creates a selector: a control that picks one of a few named options. The value is the index of the chosen option, it changes at once with no glide, and its style is Sigil.Sound.ControlStyle.Selector.

public static Control Choice(string name, IReadOnlyList<string> options, int selected = 0)

Parameters

name string

A label for the UI.

options IReadOnlyList<string>

The names of the choices, at least two.

selected int

The index of the starting choice.

Returns

Control

Examples

// A selector holds the index of the picked option. Here option 1 ("Saw") opens the filter further than option 0.
var wave = Control.Choice("Wave", ["Sine", "Saw", "Square"], selected: 1);
Saw(110).LowPass(wave * 600 + 400) * 0.4

Map(double, double, ControlCurve)

The control mapped from its own range onto outMin to outMax. The glide happens before the mapping, so an exponential cutoff sweep stays smooth.

public Param Map(double outMin, double outMax, ControlCurve curve = ControlCurve.Linear)

Parameters

outMin double

The output when the control is at Sigil.Sound.Control.Min.

outMax double

The output when the control is at Sigil.Sound.Control.Max.

curve ControlCurve

Use Sigil.Sound.ControlCurve.Exponential for frequencies.

Returns

Param

Map(double, double, double, double, ControlCurve)

The control mapped from inMin to inMax onto the output range; values outside the input range extend the line.

public Param Map(double inMin, double inMax, double outMin, double outMax, ControlCurve curve = ControlCurve.Linear)

Parameters

inMin double

The input value that maps to outMin.

inMax double

The input value that maps to outMax.

outMin double

The output at inMin.

outMax double

The output at inMax.

curve ControlCurve

Use Sigil.Sound.ControlCurve.Exponential for frequencies.

Returns

Param

SetFromSignal(double)

Sets the control from a signal that arrives from outside, such as a modulator the host wired in. The signal is read through Sigil.Sound.Control.Polarity (0 to 1, or -1 to 1) and then Sigil.Sound.Control.Taper; a signal beyond the span stops at the ends.

public void SetFromSignal(double signal)

Parameters

signal double

The incoming value.

Exceptions

ArgumentOutOfRangeException

The signal is NaN or infinite.

ToString()

A short description of the control, such as its current value.

public override string ToString()

Returns

string

Operators

operator +(Control, double)

The control plus a constant, as a signal.

public static Sound operator +(Control control, double offset)

Parameters

control Control
offset double

Returns

Sound

operator /(Control, double)

The control divided by a constant, as a signal.

public static Sound operator /(Control control, double divisor)

Parameters

control Control
divisor double

Returns

Sound

implicit operator Param(Control)

Uses the control as a parameter; the value is read live, once per block.

public static implicit operator Param(Control control)

Parameters

control Control

Returns

Param

implicit operator Sound(Control)

Uses the control as a sound, so it can be added to, scaled and fed to other sounds.

public static implicit operator Sound(Control control)

Parameters

control Control

Returns

Sound

operator *(Control, double)

The control times a constant, as a signal.

public static Sound operator *(Control control, double gain)

Parameters

control Control
gain double

Returns

Sound

operator *(double, Control)

The control times a constant, as a signal.

public static Sound operator *(double gain, Control control)

Parameters

gain double
control Control

Returns

Sound

operator -(Control, double)

The control minus a constant, as a signal.

public static Sound operator -(Control control, double offset)

Parameters

control Control
offset double

Returns

Sound