Table of Contents

Struct NoteEvent

Namespace
Sigil.Sound
Assembly
Sigil.Sound.Notes.dll

One thing that happens to a note in a Sigil.Sound.NoteStream: it starts, or it ends. Unlike a Sigil.Sound.Note in a pattern, which knows how long it lasts, a live note has no length: it lasts until its Sigil.Sound.NoteEventKind.Off arrives.

public readonly record struct NoteEvent : IEquatable<NoteEvent>

Implements

Inherited Members

Remarks

Sigil.Sound.NoteEvent.Id is what pairs the two events. Every operator keeps the pairing: an Off always ends the notes that its On produced, whatever the operator would compute for that note now. The pitch of a note is the nearest MIDI pitch and Sigil.Sound.NoteEvent.Cents the distance from it, so notes from other tunings and bent notes keep their exact pitch through every operator.

Constructors

NoteEvent(NoteEventKind, long, int, float, float, int)

One thing that happens to a note in a Sigil.Sound.NoteStream: it starts, or it ends. Unlike a Sigil.Sound.Note in a pattern, which knows how long it lasts, a live note has no length: it lasts until its Sigil.Sound.NoteEventKind.Off arrives.

public NoteEvent(NoteEventKind Kind, long Id, int Pitch, float Velocity = 0.8, float Cents = 0, int Channel = 0)

Parameters

Kind NoteEventKind

Starts or ends the note.

Id long

Identifies the note; the same on its On and its Off. Unique among the notes sounding in one stream.

Pitch int

The nearest MIDI pitch, 0 to 127; 60 is middle C.

Velocity float

How hard the note was played, from 0 to 1. Meaningful for an On.

Cents float

Hundredths of a semitone above Pitch (negative for below).

Channel int

A routing tag that operators leave alone; a function of yours may set or read it (n with { Channel = 2 }).

Remarks

Sigil.Sound.NoteEvent.Id is what pairs the two events. Every operator keeps the pairing: an Off always ends the notes that its On produced, whatever the operator would compute for that note now. The pitch of a note is the nearest MIDI pitch and Sigil.Sound.NoteEvent.Cents the distance from it, so notes from other tunings and bent notes keep their exact pitch through every operator.

Properties

Cents

Hundredths of a semitone above Pitch (negative for below).

public float Cents { get; init; }

Property Value

float

Channel

A routing tag that operators leave alone; a function of yours may set or read it (n with { Channel = 2 }).

public int Channel { get; init; }

Property Value

int

Frequency

The note's frequency in Hz, in 12-tone equal temperament with A4 (MIDI 69) at 440 Hz, including Sigil.Sound.NoteEvent.Cents.

public double Frequency { get; }

Property Value

double

Id

Identifies the note; the same on its On and its Off. Unique among the notes sounding in one stream.

public long Id { get; init; }

Property Value

long

IsOn

True for the event that starts the note.

public bool IsOn { get; }

Property Value

bool

Kind

Starts or ends the note.

public NoteEventKind Kind { get; init; }

Property Value

NoteEventKind

Pitch

The nearest MIDI pitch, 0 to 127; 60 is middle C.

public int Pitch { get; init; }

Property Value

int

PitchWithCents

The pitch as a fraction of a MIDI note number: 60.5 is a quarter tone above middle C.

public double PitchWithCents { get; }

Property Value

double

Velocity

How hard the note was played, from 0 to 1. Meaningful for an On.

public float Velocity { get; init; }

Property Value

float

Methods

Chance(double, int)

True for a random share of notes: Where(n => n.Chance(0.3)) lets 3 in 10 through. Which ones depends only on the seed and the note's Sigil.Sound.NoteEvent.Id, so the same performance is picked the same way every time.

public bool Chance(double probability, int seed = 0)

Parameters

probability double

The share, 0 to 1.

seed int

Another seed picks other notes.

Returns

bool

Examples

// Seven in ten of the notes get through, the same ones every time.
var keys = new NoteInput();
var sound = keys.Stream.Where(n => n.Chance(0.7, seed: 4))
    .Play(v => Saw(v.Frequency).LowPass(1800).Adsr(0.005, 0.2, 0.5, 0.2), polyphony: 12);
keys.NoteOn("c3 d3 e3 f3 g3 a3 b3 c4");
sound * 0.2

Detune(double)

This note moved by cents hundredths of a semitone, carrying whole semitones into the pitch.

public NoteEvent Detune(double cents)

Parameters

cents double

How far to move, up (positive) or down.

Returns

NoteEvent

Examples

// Every note 30 cents sharp, so against an untouched copy of the stream the pair beats slowly.
var keys = new NoteInput();
var sound = (keys.Stream + keys.Stream.Select(n => n.Detune(30)))
    .Play(v => Saw(v.Frequency).LowPass(1800).Adsr(0.005, 0.2, 0.5, 0.25));
keys.NoteOn("c3 g3");
sound * 0.3

InScale(Scale)

True when the note is a tone of scale, in any octave. Where(n => n.InScale(scale)) keeps those.

public bool InScale(Scale scale)

Parameters

scale Scale

The scale, such as Scale.Parse("d dorian").

Returns

bool

Examples

// Only the keys that belong to D dorian get through: the C# and G# are left out.
var keys = new NoteInput();
var dorian = Scale.Parse("d dorian");
var sound = keys.Stream.Where(n => n.InScale(dorian))
    .Play(v => Square(v.Frequency).LowPass(1500).Adsr(0.005, 0.2, 0.4, 0.2));
keys.NoteOn("d3 c#3 f3 g#3 a3");
sound * 0.2

Snap(Scale, QuantizeMode)

This note moved to a tone of scale, in any octave; a note already in the scale is returned as it is. The cents of a moved note are cleared. Select(n => n.Snap(scale)) quantizes a stream.

public NoteEvent Snap(Scale scale, QuantizeMode mode = QuantizeMode.Nearest)

Parameters

scale Scale

The tones allowed.

mode QuantizeMode

Which tone a note between two goes to. Defaults to the closest, and the lower one when two are equally close.

Returns

NoteEvent

Examples

// Keys outside D dorian are moved to the nearest tone of it, so whatever is played stays in the scale.
var keys = new NoteInput();
var dorian = Scale.Parse("d dorian");
var sound = keys.Stream.Select(n => n.Snap(dorian))
    .Play(v => Triangle(v.Frequency).LowPass(2000).Adsr(0.01, 0.2, 0.6, 0.3));
keys.NoteOn("d3 f#3 a3 c#4");
sound * 0.3

Start(long, int, float, float, int)

An event that starts a note.

public static NoteEvent Start(long id, int pitch, float velocity = 0.8, float cents = 0, int channel = 0)

Parameters

id long
pitch int
velocity float
cents float
channel int

Returns

NoteEvent

Stop(long, int, float, int)

An event that ends a note.

public static NoteEvent Stop(long id, int pitch, float cents = 0, int channel = 0)

Parameters

id long
pitch int
cents float
channel int

Returns

NoteEvent

Transpose(int)

This note moved by semitones. A note moved out of the MIDI range is dropped by the stream that gets it.

public NoteEvent Transpose(int semitones)

Parameters

semitones int

How far to move, up (positive) or down.

Returns

NoteEvent

Examples

// A function of your own that moves a note: loud ones up an octave, soft ones down a fifth.
var keys = new NoteInput();
var sound = keys.Stream.Select(n => n.Velocity > 0.7f ? n.Transpose(12) : n.Transpose(-5))
    .Play(v => Saw(v.Frequency).LowPass(1800).Adsr(0.005, 0.2, 0.5, 0.25));
keys.NoteOn("c3:0.9 e3:0.4");
sound * 0.3