A chord voicing is an instance of a Chord
that can be played or sung.
Music.Internal.Voicing.ThreePart.Voicing
This package's recommended way of creating three-part Voicing
s is to use the Chord.voiceThreeParts function along with VoicingMethod
s like the ones in this module:
Chord.voiceThreeParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
}
[ basic ]
(Chord.majorSeventh PitchClass.c)
In this example, we pass the following to voiceThreeParts
:
Range
s of the instruments involvedVoicingMethod
s to be usedThis uses the characteristics of the VoicingMethod
to return a List
of all possible Voicing
s.
From here, you may choose from this list based on some criteria:
myGeneratedVoicings
|> List.filter
(\voicing ->
containsPitchInVoiceOne Pitch.e5 voicing
&& (span voicing >= Interval.perfectOctave)
)
|> List.sortWith (centerOrder Pitch.g4)
|> List.head
This does the following:
Voicing
s which have E5 in the top voice, and have a span of at least an octave from bottom to top voiceVoicing
s which are centered around the pitch G4 are at the beginningThese sorting and filtering processes allow you to account for considerations like voice leading, or the harmonization of a melody. You'll find comparison functions in this module for doing that.
There are cases where you may want to create a specific voicing you have in mind:
voicing : Pitches -> Music.Internal.Chord.Chord -> Result (List Music.PitchClass.PitchClass) Voicing
Create a voicing from pitches and a chord:
voicing
{ voiceOne = Pitch.g4
, voiceTwo = Pitch.e4
, voiceThree = Pitch.c4
}
(Chord.majorSix PitchClass.c)
== Ok Voicing ...
If the pitches given do not match the chord, this function will return Err
with the erroneous pitch classes:
voicing
{ voiceOne = Pitch.g4
, voiceTwo = Pitch.d4
, voiceThree = Pitch.c4
}
(Chord.majorSix PitchClass.c)
== Err [ PitchClass.d ]
chord : Voicing -> Music.Internal.Chord.Chord
Get the chord being voiced:
chord myVoicing == Chord.majorSixNine PitchClass.c
span : Voicing -> Music.Internal.Interval.Interval
Get the interval from the lowest to the highest pitch in the voicing:
span myVoicing == Interval.minorSeventh
center : Voicing -> Basics.Int
Get the midpoint between the highest and lowest voices in semitones:
center myVoicing
== Pitch.semitones Pitch.fSharp3
voiceOne : Voicing -> Music.Internal.Pitch.Pitch
Get the first (highest) pitch of the voicing:
voiceOne myVoicing == Pitch.d5
voiceTwo : Voicing -> Music.Internal.Pitch.Pitch
Get the second pitch of the voicing:
voiceTwo myVoicing == Pitch.a4
voiceThree : Voicing -> Music.Internal.Pitch.Pitch
Get the third (lowest) pitch of the voicing:
voiceThree myVoicing == Pitch.g4
containsPitch : Music.Internal.Pitch.Pitch -> Voicing -> Basics.Bool
Find out whether a voicing contains a specific pitch:
containsPitch Pitch.d5 myVoicing == True
containsPitchInVoiceOne : Music.Internal.Pitch.Pitch -> Voicing -> Basics.Bool
Find out whether a voicing has a specific pitch in the first voice:
containsPitchInVoiceOne Pitch.d5 myVoicing == True
containsPitchInVoiceTwo : Music.Internal.Pitch.Pitch -> Voicing -> Basics.Bool
Find out whether a voicing has a specific pitch in the second voice:
containsPitchInVoiceTwo Pitch.a4 myVoicing == True
containsPitchInVoiceThree : Music.Internal.Pitch.Pitch -> Voicing -> Basics.Bool
Find out whether a voicing has a specific pitch in the third voice:
containsPitchInVoiceThree Pitch.g4 myVoicing == True
commonTones : Voicing -> Voicing -> List Music.Internal.Pitch.Pitch
Get all pitches in common between two voicings:
commonTones bFlatVoicing bDimVoicing
== [ Pitch.d4
, Pitch.f4
]
usesContraryMotion : Voicing -> Voicing -> Basics.Bool
Find out whether the first and third voices move in opposite directions (known as contrary motion).
containsParallelFifths : Voicing -> Voicing -> Basics.Bool
Find out whether any two moving voices maintain a perfect fifth interval between them. Identifying parallel fifths and octaves is important in the study of counterpoint.
containsParallelOctaves : Voicing -> Voicing -> Basics.Bool
Find out whether any two moving voices maintain a perfect octave interval between them.
totalSemitoneDistance : Voicing -> Voicing -> Basics.Int
Given two voicings, find out how far in semitones all voices move.
semitoneDistanceVoiceOne : Voicing -> Voicing -> Basics.Int
Given two voicings, find out how far in semitones the first (top) voice moves.
semitoneDistanceVoiceTwo : Voicing -> Voicing -> Basics.Int
Given two voicings, find out how far in semitones the second voice moves.
semitoneDistanceVoiceThree : Voicing -> Voicing -> Basics.Int
Given two voicings, find out how far in semitones the third voice moves.
isWithinLowIntervalLimits : Voicing -> Basics.Bool
A low interval limit is the lowest pitch at which the character of an interval cannot be heard clearly. I have heard this explained in terms of the harmonic series, but it seems to be taught as more of a guideline for arrangers than a physical absolute.
sortWeighted : List ( Voicing -> Voicing -> Basics.Order, Basics.Float ) -> List Voicing -> List Voicing
Sort by multiple ordering functions:
sortWeighted
[ ( totalSemitoneDistanceOrder previousVoicing, 10.0 )
, ( contraryMotionOrder previousVoicing, 5.0 )
, ( commonTonesOrder previousVoicing, 2.0 )
]
voicingList
orderWeighted : List ( Voicing -> Voicing -> Basics.Order, Basics.Float ) -> Voicing -> Voicing -> Basics.Order
Combine multiple ordering functions:
orderWeighted
[ ( totalSemitoneDistanceOrder previousVoicing, 10.0 )
, ( contraryMotionOrder previousVoicing, 5.0 )
, ( commonTonesOrder previousVoicing, 2.0 )
]
|> List.orderWith
centerOrder : Music.Internal.Pitch.Pitch -> Voicing -> Voicing -> Basics.Order
Compare voicings by how far their centers are from a goal pitch:
myVoicingList
|> List.sortWith (centerOrder Pitch.g4)
Useful for finding voicings that are centered around a particular pitch.
commonTonesOrder : Voicing -> Voicing -> Voicing -> Basics.Order
Compare voicings by how many pitches they have in common with a previous voicing:
myVoicingList
|> List.sortWith (commonTonesOrder previousVoicing)
contraryMotionOrder : Voicing -> Voicing -> Voicing -> Basics.Order
Compare voicings by whether they use contrary motion from a previous voicing:
myVoicingList
|> List.sortWith (contraryMotionOrder previousVoicing)
"Contrary motion" here is in respect to the top and bottom voices.
totalSemitoneDistanceOrder : Voicing -> Voicing -> Voicing -> Basics.Order
Compare voicings by absolute difference in semitones from a previous voicing:
myVoicingList
|> List.sortWith (totalSemitoneDistanceOrder previousVoicing)
semitoneDistanceVoiceOneOrder : Voicing -> Voicing -> Voicing -> Basics.Order
Compare voicings by absolute difference in semitones in voice one:
myVoicingList
|> List.sortWith (semitoneDistanceVoiceOneOrder previousVoicing)
semitoneDistanceVoiceTwoOrder : Voicing -> Voicing -> Voicing -> Basics.Order
Compare voicings by absolute difference in semitones in voice two:
myVoicingList
|> List.sortWith (semitoneDistanceVoiceTwoOrder previousVoicing)
semitoneDistanceVoiceThreeOrder : Voicing -> Voicing -> Voicing -> Basics.Order
Compare voicings by absolute difference in semitones in voice three:
myVoicingList
|> List.sortWith (semitoneDistanceVoiceThreeOrder previousVoicing)
{ voiceOne : Music.Internal.Pitch.Pitch
, voiceTwo : Music.Internal.Pitch.Pitch
, voiceThree : Music.Internal.Pitch.Pitch
}
The pitches contained in a voicing.
These are in order from highest (voiceOne
) to lowest (voiceThree
), the way you might read them on a staff.
toPitches : Voicing -> Pitches
Get all pitches contained in a voicing:
toPitches myVoicing
== { voiceOne = Pitch.d5
, voiceTwo = Pitch.a4
, voiceThree = Pitch.g4
}
toPitchList : Voicing -> List Music.Internal.Pitch.Pitch
Get all pitches contained in a voicing, as a List
:
toPitchList myVoicing
== [ Pitch.d5
, Pitch.a4
, Pitch.g4
]
toString : Voicing -> String
Get all pitches contained in a voicing, as a stringified list:
toPitchList myVoicing
== "D5, A4, G4, E4, C4"
{ threeToOne : Music.Internal.Interval.Interval
, threeToTwo : Music.Internal.Interval.Interval
, twoToOne : Music.Internal.Interval.Interval
}
toIntervals : Voicing -> Intervals
Get all intervals between each pitch in a voicing:
toIntervals myVoicing
== { threeToOne = Interval.majorSixth
, threeToTwo = Interval.perfectFourth
, twoToOne = Interval.majorThird
}
toIntervalList : Voicing -> List Music.Internal.Interval.Interval
Get all intervals between each pitch in a voicing as a List
:
toIntervalList myVoicing
== [ Interval.majorThird
, Interval.perfectFourth
, Interval.majorSixth
]
basic : VoicingMethod
A basic textbook method for voicing a chord in root position:
Chord.voiceThreeParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
}
[ basic ]
(Chord.major PitchClass.c)
|> List.map toString
== [ "G3, E3, C3"
, "G4, E4, C4"
]
shell : VoicingMethod
Voice a chord with the "shell" method:
Chord.voiceThreeParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
}
[ shell ]
(Chord.majorSeventh PitchClass.c)
|> List.map toString
== [ "E4, B3, C3"
, -- 3 others...
]
Popularized by Bud Powell and Thelonious Monk, "shell" voicings include the essential pitches in jazz chords, and are useful for minimalistic accompaniment.
Voicing methods are a deep and nuanced topic, that I hope to make approachable. I've modeled this API with three main concepts of chord voicing in mind:
Here are the steps in building a voicing method:
Since chords can vary, use some method of categorizing the factors of a chord into groups that you can guarantee are present. Examples of this type of categorization function are Chord.categorizeFactors
and Chord.availableTensions
.
Select factors using the with...
functions in this section.
Use the placeSelectedFactors
function, passing a SpacingLimits
.
Example:
myCustomVoicingMethod : VoicingMethod
myCustomVoicingMethod =
custom
ChordType.categorizeFactors
(\factors ->
selectFactors
|> withFactor factors.fifth
|> withFactor factors.third
|> withFactor Interval.perfectUnison
|> placeSelectedFactors spacingLimits
)
spacingLimits =
{ twoToOne =
Interval.range
Interval.augmentedUnison
Interval.perfectOctave
, threeToTwo =
Interval.range
Interval.augmentedUnison
Interval.perfectOctave
}
Music.Internal.Voicing.ThreePart.VoicingMethod
{ twoToOne : Music.Internal.Interval.Range
, threeToTwo : Music.Internal.Interval.Range
}
method : (Music.Internal.ChordType.ChordType -> Maybe categorized) -> (categorized -> List Music.Internal.Voicing.ThreePart.VoicingClass) -> VoicingMethod
Begin a custom voicing method:
method Chord.categorizeFactors
(\categorized ->
...
)
selectFactors : Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> Music.Internal.Voicing.ThreePart.VoicingClass)
Begin selecting factors for a voicing method.
withFactor : Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select a chord factor for use in a voice.
withUniqueFactor : Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select a factor that has not yet been used.
withFactorFrom : List Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select a factor from a list of options.
withUniqueFactorFrom : List Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select a factor that has not yet been used, from a list of options.
withTwoFactorsFrom : List Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select two factors from a list of options.
withUniqueTwoFactorsFrom : List Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select two factors that have not yet been used, from a list of options.
withThreeFactorsFrom : List Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select three factors from a list of options.
withUniqueThreeFactorsFrom : List Music.Internal.Interval.Interval -> Music.Internal.VoicingClass.VoicingClassBuilder (Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> Music.Internal.Interval.Interval -> a) -> Music.Internal.VoicingClass.VoicingClassBuilder a
Select two factors that have not yet been used, from a list of options.
placeSelectedFactors : SpacingLimits -> Music.Internal.VoicingClass.VoicingClassBuilder Music.Internal.Voicing.ThreePart.VoicingClass -> List Music.Internal.Voicing.ThreePart.VoicingClass
Finish selecting factors for a voicing method and place them according to the spacing limits.
combineVoicingMethods : List VoicingMethod -> VoicingMethod
Combine multiple VoicingMethod
s together:
myComboVoicingMethod =
combineVoicingMethods [ voicingMethodOne, voicingMethodTwo, voicingMethodThree ]
This is useful if you want to define multiple VoicingMethod
s that act as a group (e.g. inversions or similar methods that use different chord factors).