-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
ChordVoiceLeading.fs
62 lines (48 loc) · 2.61 KB
/
ChordVoiceLeading.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
namespace Vaughan
module ChordVoiceLeading =
open Chords
open Notes
let private isLeadFunctionOnChordDesiredFunction (chord: Chord) desiredNoteFunction desiredPosition =
snd (chord.Notes |> desiredPosition) = desiredNoteFunction
let rec private repeatInversion (chord: Chord) times =
match times with
| 0 -> chord
| _ -> repeatInversion (chord |> invert) (times - 1)
let private allInversions (chord: Chord) =
let notesInChord = chord.Notes |> List.length
[ for index in 1 .. notesInChord do
yield repeatInversion chord index ]
let private inversionForFunction (chord: Chord) desiredNoteFunction desiredPosition =
allInversions chord
|> List.filter (fun (c: Chord) -> isLeadFunctionOnChordDesiredFunction c desiredNoteFunction desiredPosition)
|> List.head
let private closestChord (minOf: Chord -> Chord -> Chord) (list: Chord list) =
list |> List.fold minOf (list |> List.head)
let private distanceBetweenNoteAndChordNote chord desiredPosition note =
measureAbsoluteSemitones (desiredPosition chord) note
let private chordWithNoteInDesiredPositionCosestToNote note desiredPosition c1 c2 =
if (distanceBetweenNoteAndChordNote c1 desiredPosition note) < (distanceBetweenNoteAndChordNote c2
desiredPosition note) then
c1
else
c2
let private invertionWithNoteClosestToNote chord note desiredPosition =
allInversions chord
|> closestChord (chordWithNoteInDesiredPositionCosestToNote note desiredPosition)
let inversionForFunctionAsLead: InversionForFunctionAsLead =
fun chord desiredNoteFunction -> inversionForFunction chord desiredNoteFunction List.last
let inversionForFunctionAsBass: InversionForFunctionAsBass =
fun chord desiredNoteFunction -> inversionForFunction chord desiredNoteFunction List.head
let invertionWithLeadClosestToNote: InvertionWithLeadClosestToNote =
fun chord note -> invertionWithNoteClosestToNote chord note lead
let invertionWithBassClosestToNote: InvertionWithBassClosestToNote =
fun chord note -> invertionWithNoteClosestToNote chord note bass
let voiceLead: VoiceLead =
fun strategy (chords: Chord List) ->
chords
|> List.fold (fun acc chord ->
if acc.Length = 0 then
acc @ [ chord ]
else
acc
@ [ invertionWithNoteClosestToNote chord (strategy (acc |> List.last)) strategy ]) []