A chord voicing is an instance of a Chord
that can be played or sung.
Music.Internal.Voicing.FourPart.Voicing
This package's recommended way of creating four-part Voicing
s is to use the Chord.voiceFourParts function along with VoicingMethod
s like the ones in this module:
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ basic ]
(Chord.majorSeventh PitchClass.c)
In this example, we pass the following to voiceFourParts
:
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.c5
, voiceTwo = Pitch.a4
, voiceThree = Pitch.g4
, voiceFour = Pitch.e4
}
(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.c5
, voiceTwo = Pitch.d4
, voiceThree = Pitch.g4
, voiceFour = Pitch.e4
}
(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 pitch of the voicing:
voiceThree myVoicing == Pitch.g4
voiceFour : Voicing -> Music.Internal.Pitch.Pitch
Get the fourth (lowest) pitch of the voicing:
voiceFour myVoicing == Pitch.e4
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
containsPitchInVoiceFour : Music.Internal.Pitch.Pitch -> Voicing -> Basics.Bool
Find out whether a voicing has a specific pitch in the fourth voice:
containsPitchInVoiceFour Pitch.e4 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 fourth 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.
semitoneDistanceVoiceFour : Voicing -> Voicing -> Basics.Int
Given two voicings, find out how far in semitones the fourth (bottom) 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)
semitoneDistanceVoiceFourOrder : Voicing -> Voicing -> Voicing -> Basics.Order
Compare voicings by absolute difference in semitones in voice four:
myVoicingList
|> List.sortWith (semitoneDistanceVoiceFourOrder previousVoicing)
{ voiceOne : Music.Internal.Pitch.Pitch
, voiceTwo : Music.Internal.Pitch.Pitch
, voiceThree : Music.Internal.Pitch.Pitch
, voiceFour : Music.Internal.Pitch.Pitch
}
The pitches contained in a voicing.
These are in order from highest (voiceOne
) to lowest (voiceFour
), 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
, voiceFour = Pitch.e4
}
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
, Pitch.e4
]
toString : Voicing -> String
Get all pitches contained in a voicing, as a stringified list:
toPitchList myVoicing
== "D5, A4, G4, E4"
{ fourToOne : Music.Internal.Interval.Interval
, fourToTwo : Music.Internal.Interval.Interval
, fourToThree : Music.Internal.Interval.Interval
, 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
== { fourToOne = Interval.majorSixth
, fourToTwo = Interval.majorSecond
, fourToThree = Interval.majorThird
, threeToOne = Interval.perfectFifth
, threeToTwo = Interval.majorSecond
, twoToOne = Interval.perfectFourth
}
toIntervalList : Voicing -> List Music.Internal.Interval.Interval
Get all intervals between each pitch in a voicing as a List
:
toIntervalList myVoicing
== [ Interval.majorSecond
, Interval.majorSecond
, Interval.majorThird
, Interval.perfectFourth
, Interval.perfectFifth
, Interval.majorSixth
]
basic : VoicingMethod
A basic textbook method for voicing a chord in root position:
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ basic ]
(Chord.majorSeventh PitchClass.c)
|> List.map toString
== [ "B4, G4, E4, C4"
, -- 2 others...
]
These methods were adapted from Jazz Arranging Techniques by Gary Lindsay.
Notes:
close : VoicingMethod
Voice a chord using the "four-way close" method:
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ close ]
(Chord.majorSeventh PitchClass.c)
|> List.map toString
== [ "C4, B3, G3, E3"
, -- 39 others...
]
This method voices all four notes "closely" within the span of an octave.
drop2 : VoicingMethod
Voice a chord using the "four-way drop-2" method:
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ drop2 ]
(Chord.majorSeventh PitchClass.c)
|> List.map toString
== [ "C4, G3, E3, B2"
, -- 55 others...
]
This method is the same as four-way close, but with the second pitch from the top dropped by an octave for a wider, semi-open sound.
drop3 : VoicingMethod
Voice a chord using the "four-way drop-3" method:
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ drop3 ]
(Chord.majorSeventh PitchClass.c)
|> List.map toString
== [ "C4, G3, E3, B2"
, -- 55 others...
]
Same as drop-2, but with the third pitch from the top dropped instead of the second.
drop2and4 : VoicingMethod
Voice a chord using the "four-way drop-2-and-4" method:
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ drop2and4 ]
(Chord.majorSeventh PitchClass.c)
|> List.map toString
== [ "G4, C4, E3, B2"
, -- 55 others...
]
A double drop voicing, with the second and fourth pitches from the top dropped for a wide, open sound.
spread : VoicingMethod
Voice a chord using the "four-way spread" method:
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ spread ]
(Chord.majorSeventh PitchClass.c)
|> List.map toString
== [ "C4, B3, E3, G2"
, -- 22 others...
]
Another open voicing method, with the root of the chord on the bottom for a dramatic effect.
Note: these classical methods were developed before jazz harmony, and so chord extensions and added tones will not be included.
rootPosition : VoicingMethod
Voice a chord in "root position":
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ rootPosition ]
(Chord.major PitchClass.c)
|> List.map toString
== [ "G4, E4, G3, C3"
, -- 30 others...
]
A root position voicing is any voicing where the root is in the lowest voice.
firstInversion : VoicingMethod
Voice a chord in "first inversion":
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ firstInversion ]
(Chord.major PitchClass.c)
|> List.map toString
== [ "C6, C5, G4, E3"
, -- 32 others...
]
A first inversion voicing is any voicing where the third of the chord is in the lowest voice.
secondInversion : VoicingMethod
Voice a chord in "second inversion":
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ secondInversion ]
(Chord.major PitchClass.c)
|> List.map toString
== [ "E4, G3, C3, G2"
, -- 32 others...
]
A second inversion voicing is any voicing where the fifth of the chord is in the lowest voice.
thirdInversion : VoicingMethod
Voice a chord in "third inversion":
Chord.voiceFourParts
{ voiceOne = Range.sopranoVoice
, voiceTwo = Range.altoVoice
, voiceThree = Range.tenorVoice
, voiceFour = Range.bassVoice
}
[ thirdInversion ]
(Chord.dominantSeventh PitchClass.c)
|> List.map toString
== [ "E4, C4, C3, B♭2"
, -- 32 others...
]
A third inversion voicing is any voicing where the seventh of the chord is in the lowest voice.
Note: this will return an empty list when used with triad chord types like major and minor, because a seventh must be included.
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
|> withFactorFrom
(List.filterMap identity
[ Just Interval.perfectUnison
, factors.sixthOrSeventh
]
)
|> 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
, fourToThree =
Interval.range
Interval.augmentedUnison
Interval.perfectOctave
}
Music.Internal.Voicing.FourPart.VoicingMethod
{ twoToOne : Music.Internal.Interval.Range
, threeToTwo : Music.Internal.Interval.Range
, fourToThree : Music.Internal.Interval.Range
}
method : (Music.Internal.ChordType.ChordType -> Maybe categorized) -> (categorized -> List Music.Internal.Voicing.FourPart.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.Interval.Interval -> Music.Internal.Voicing.FourPart.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.FourPart.VoicingClass -> List Music.Internal.Voicing.FourPart.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).