Table of Contents

Class VoiceSeparator

Namespace
Celeritas.Core.Analysis
Assembly
Celeritas.dll

Algorithm for separating polyphonic music into individual voices. Uses pitch proximity and voice leading principles.

public static class VoiceSeparator
Inheritance
VoiceSeparator
Inherited Members

Methods

Separate(NoteBuffer, int)

Separate notes into voices using pitch-proximity algorithm. Notes that overlap in time are forced into different voices; the VoiceSeparatorOptions overload adds voice-crossing and stepwise-motion penalties on top of that.

public static VoiceSeparationResult Separate(NoteBuffer buffer, int maxVoices = 4)

Parameters

buffer NoteBuffer
maxVoices int

Returns

VoiceSeparationResult

Exceptions

ArgumentNullException

buffer is null.

Separate(NoteBuffer, int, VoiceSeparatorOptions)

Separate notes into voices with custom options. At each onset the notes go to distinct voices at the least total cost, a note's cost being its distance from the voice's last pitch: a line continues in the voice nearest its last note, a note further than MaxMelodicInterval from every voice opens a new one while a voice is free, and notes that overlap in time are forced into different voices. VoiceSeparatorOptions adds a penalty for voice-order violations when AllowCrossings is false and a superlinear penalty for motion beyond a whole step when PreferStepwise is set. The voices come back highest first by average pitch, named for their register.

public static VoiceSeparationResult Separate(NoteBuffer buffer, int maxVoices, VoiceSeparatorOptions options)

Parameters

buffer NoteBuffer
maxVoices int
options VoiceSeparatorOptions

Returns

VoiceSeparationResult

Remarks

The assignment within an onset used to keep the voices in register order whatever AllowCrossings said — the higher note always went to the lower-numbered voice — so a line entering above an active voice took that voice over and pushed its continuation into a new one: two lines cut and re-joined, and a canon answered an octave above its subject came back from DetectImitation(NoteBuffer, int) as answered below, or not at all, depending on the register the subject started in. Opening a new voice was also cheap enough — the seed's distance plus 4 — that a line moving by a third or a fourth was cut in two whenever a free voice was seeded nearby. The order constraint now applies only when crossings are forbidden, and a new voice costs more than any melodic continuation.

Exceptions

ArgumentNullException

buffer or options is null.

SeparateIntoSatb(NoteBuffer, VoiceSeparatorOptions?)

Convenience SATB separation: returns exactly 4 voices named Soprano/Alto/Tenor/Bass.

public static SatbSeparationResult SeparateIntoSatb(NoteBuffer buffer, VoiceSeparatorOptions? options = null)

Parameters

buffer NoteBuffer
options VoiceSeparatorOptions

Returns

SatbSeparationResult

Exceptions

ArgumentNullException

buffer is null.

SeparateIntoSatb(IEnumerable<NoteEvent>, VoiceSeparatorOptions?)

Convenience SATB separation: returns exactly 4 voices named Soprano/Alto/Tenor/Bass.

public static SatbSeparationResult SeparateIntoSatb(IEnumerable<NoteEvent> notes, VoiceSeparatorOptions? options = null)

Parameters

notes IEnumerable<NoteEvent>
options VoiceSeparatorOptions

Returns

SatbSeparationResult

Exceptions

ArgumentNullException

notes is null.