8 people like it.

Her name is Cherry; we've just met

Third cut of a guitar chord shape generator. Given a fretted instrument with a particular tuning (eg. 6 string guitar tuned EADGBE), the generator will produce the frettings necessary to play any specified chord. This is not done from a chord library, but algorithmically (hence should work with whacky tunings). This version doesn't fully respect the limitations of the human hand beyond specifying a maximum 'stretch' of a few frets, so some of the shapes generated would need a friend to help play them! This will be dealt with in a future version. This third version contains improved handling of differing tunings and instruments (eg. DADGAD; banjo) but still doesn't check for unplayable shapes.

  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: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
178: 
179: 
180: 
181: 
182: 
183: 
184: 
185: 
186: 
187: 
188: 
189: 
190: 
191: 
192: 
193: 
194: 
195: 
196: 
197: 
198: 
199: 
200: 
201: 
202: 
203: 
204: 
205: 
206: 
207: 
208: 
209: 
210: 
211: 
212: 
213: 
214: 
215: 
216: 
217: 
218: 
219: 
220: 
221: 
222: 
223: 
224: 
225: 
226: 
227: 
228: 
229: 
230: 
231: 
232: 
233: 
234: 
235: 
236: 
237: 
238: 
239: 
240: 
241: 
242: 
243: 
244: 
245: 
246: 
247: 
248: 
249: 
250: 
251: 
252: 
253: 
254: 
255: 
256: 
257: 
258: 
259: 
260: 
261: 
262: 
263: 
264: 
265: 
266: 
267: 
268: 
269: 
270: 
271: 
272: 
273: 
274: 
275: 
276: 
277: 
278: 
279: 
280: 
281: 
282: 
283: 
284: 
285: 
286: 
287: 
288: 
289: 
290: 
291: 
292: 
293: 
294: 
295: 
296: 
297: 
298: 
299: 
300: 
301: 
302: 
303: 
304: 
305: 
306: 
307: 
308: 
309: 
310: 
311: 
312: 
313: 
314: 
315: 
316: 
317: 
318: 
319: 
320: 
321: 
322: 
323: 
324: 
325: 
326: 
327: 
328: 
329: 
330: 
331: 
332: 
333: 
334: 
335: 
336: 
337: 
338: 
339: 
340: 
341: 
342: 
343: 
344: 
345: 
346: 
347: 
348: 
349: 
350: 
351: 
352: 
353: 
354: 
355: 
356: 
357: 
358: 
359: 
360: 
361: 
362: 
363: 
364: 
365: 
366: 
367: 
368: 
369: 
370: 
371: 
372: 
373: 
374: 
375: 
376: 
377: 
378: 
379: 
380: 
381: 
382: 
383: 
384: 
385: 
386: 
387: 
388: 
389: 
390: 
391: 
392: 
393: 
394: 
395: 
396: 
397: 
398: 
399: 
400: 
401: 
402: 
403: 
404: 
405: 
406: 
407: 
408: 
409: 
410: 
411: 
412: 
413: 
414: 
415: 
416: 
417: 
418: 
419: 
420: 
421: 
422: 
423: 
424: 
425: 
426: 
427: 
428: 
429: 
430: 
431: 
432: 
433: 
434: 
435: 
436: 
437: 
438: 
439: 
440: 
441: 
442: 
443: 
444: 
445: 
446: 
447: 
448: 
449: 
450: 
451: 
452: 
453: 
454: 
455: 
456: 
457: 
458: 
459: 
460: 
461: 
462: 
463: 
464: 
465: 
466: 
467: 
468: 
469: 
470: 
471: 
472: 
473: 
474: 
475: 
476: 
477: 
478: 
479: 
480: 
481: 
482: 
483: 
484: 
485: 
486: 
487: 
488: 
489: 
490: 
491: 
492: 
493: 
494: 
495: 
496: 
497: 
498: 
499: 
500: 
501: 
502: 
503: 
504: 
505: 
506: 
507: 
// How many semitones in Western music:
let SEMITONES_PER_OCTAVE = 12

// Flat, Natural or Sharp:
type TAccidental = Flat | Natural | Sharp
// A note name, accidental and chromatic index but without specifying the octave it is in - eg. G#, A, or Bb:
type TNoteLabel = {name : char; accidental : TAccidental; chromaticIndex : int}
// A note including its specific octave - eg. G# in octave 2 (from an arbitrary lowest octave):
type TNote = {label : TNoteLabel; octave : int}
// An array of the chromatic indices of notes forming a chord type:
type TChordIndexes = array<int>
// Whether a chord is major or minor:
type TScaleType = Major | Minor
// A Relative Chord in terms of the chromatic indices of its notes - eg. [|0; 4; 7; 12|]; Major is an ordinary
// major chord:
type TChordType = {chordIndexes : TChordIndexes; scaleType : TScaleType}
// An Absolute Chord - eg. C major:
type TChord = array<TNote>
// When translating an index to a readable note, determines whether to prefer the sharp version
// or the flat version when encountering an enharmonic:
type TEnharmonicPreference = PreferFlat | PreferSharp | PreferNeither

// A way of noting which notes have been covered during the generation of a chord:
type TNoteMapping = {mappedNote : TNote; mutable useCount : int}

// How an instrument is tuned - eg. conventional guitar tuning is EADGBE', 'dropped D' tuning is DADGBE'.
type TTuning = array<TNote>

// A combination of string and fret - the actual location of a fingering on the neck:
type TFretting = {stringIndex : int; fretIndex : int}
// A fretting plus the note that would result from that fretting:
type TFrettedNote = {fretting : TFretting; note : TNote}

/// Any fretted instrument:
type TInstrument (fretCount : int, tuning : TTuning) = 
    member this.fretCount = fretCount // Includes nut at 0
    member this.tuning = tuning
    // TODO ensure tuning is the same size as strings

/// All human readable note names, including enharmonics (but not bothering with double-flats, double-sharps):
let allNotes =
    [|
        {name = 'A'; accidental = Natural; chromaticIndex = 0}
        {name = 'A'; accidental = Sharp; chromaticIndex = 1}

        {name = 'B'; accidental = Flat; chromaticIndex = 1}
        {name = 'B'; accidental = Natural; chromaticIndex = 2}
        {name = 'B'; accidental = Sharp; chromaticIndex = 3}

        {name = 'C'; accidental = Flat; chromaticIndex = 2}
        {name = 'C'; accidental = Natural; chromaticIndex = 3}
        {name = 'C'; accidental = Sharp; chromaticIndex = 4}

        {name = 'D'; accidental = Flat; chromaticIndex = 4}
        {name = 'D'; accidental = Natural; chromaticIndex = 5}
        {name = 'D'; accidental = Sharp; chromaticIndex = 6}

        {name = 'E'; accidental = Flat; chromaticIndex = 6}
        {name = 'E'; accidental = Natural; chromaticIndex = 7}
        {name = 'E'; accidental = Sharp; chromaticIndex = 8}

        {name = 'F'; accidental = Flat; chromaticIndex = 7}
        {name = 'F'; accidental = Natural; chromaticIndex = 8}
        {name = 'F'; accidental = Sharp; chromaticIndex = 9}

        {name = 'G'; accidental = Flat; chromaticIndex = 9}
        {name = 'G'; accidental = Natural; chromaticIndex = 10}
        {name = 'G'; accidental = Sharp; chromaticIndex = 11}

        {name = 'A'; accidental = Flat; chromaticIndex = 11}
    |]

/// Some useful constants for notes:
let ANat = {name = 'A'; accidental = Natural; chromaticIndex = 0}
let ASharp = {name = 'A'; accidental = Sharp; chromaticIndex = 1}

let BFlat = {name = 'B'; accidental = Flat; chromaticIndex = 1}
let BNat = {name = 'B'; accidental = Natural; chromaticIndex = 2}
let BSharp = {name = 'B'; accidental = Sharp; chromaticIndex = 3}

let CFlat = {name = 'C'; accidental = Flat; chromaticIndex = 2}
let CNat = {name = 'C'; accidental = Natural; chromaticIndex = 3}
let CSharp = {name = 'C'; accidental = Sharp; chromaticIndex = 4}

let DFlat = {name = 'D'; accidental = Flat; chromaticIndex = 4}
let DNat = {name = 'D'; accidental = Natural; chromaticIndex = 5}
let DSharp = {name = 'D'; accidental = Sharp; chromaticIndex = 6}

let EFlat = {name = 'E'; accidental = Flat; chromaticIndex = 6}
let ENat = {name = 'E'; accidental = Natural; chromaticIndex = 7}
let ESharp = {name = 'E'; accidental = Sharp; chromaticIndex = 8}

let FFlat = {name = 'F'; accidental = Flat; chromaticIndex = 7}
let FNat = {name = 'F'; accidental = Natural; chromaticIndex = 8}
let FSharp = {name = 'F'; accidental = Sharp; chromaticIndex = 9}

let GFlat = {name = 'G'; accidental = Flat; chromaticIndex = 9}
let GNat = {name = 'G'; accidental = Natural; chromaticIndex = 10}
let GSharp = {name = 'G'; accidental = Sharp; chromaticIndex = 11}

let AFlat = {name = 'A'; accidental = Flat; chromaticIndex = 11}

/// An operator to concatenate two arrays:
let (@@) a b =
    Array.concat [a; b]

// Common Relative Chords, in terms of the chromatic indexes of their constituent tones
let major : TChordType = {chordIndexes = [|0; 4; 7; 12|]; scaleType = Major}
let minor : TChordType = {chordIndexes = [|0; 3; 7; 12|]; scaleType = Minor}
let diminished : TChordType = {chordIndexes = [|0; 3; 6; 12|]; scaleType = Minor}
let augmented : TChordType = {chordIndexes = [|0; 5; 8; 12|]; scaleType = Major} // TODO check
let seventh : TChordType = {chordIndexes = major.chordIndexes @@ [|10|]; scaleType = Major}
let majorSeventh : TChordType = {chordIndexes = major.chordIndexes @@ [|11|]; scaleType = Major}
let minorSeventh : TChordType = {chordIndexes = minor.chordIndexes @@ [|10|]; scaleType = Minor}

/// Work out the human-readable note name for a particular chromatic index
let indexToName (index : int) (enharmonicPreference : TEnharmonicPreference) =
    allNotes
    |> Array.sortBy (fun item -> 
                            match enharmonicPreference with
                            | PreferFlat ->
                                            match item.accidental with
                                            | Flat -> 0
                                            | Natural -> 1
                                            | Sharp -> 2
                            | PreferSharp ->
                                            match item.accidental with
                                            | Sharp -> 0
                                            | Natural -> 1
                                            | Flat -> 2
                            | PreferNeither ->
                                            match item.accidental with
                                            | Natural -> 0
                                            | Flat -> 1
                                            | Sharp -> 2
                    )
    |> Array.find (fun item -> item.chromaticIndex = index)

/// Work out the absolute chromatic index of a given note (ie. including the octave)
let noteToIndex (note : TNote) =
    (note.octave * SEMITONES_PER_OCTAVE) + note.label.chromaticIndex

/// Work out into what octave a particular semitone falls (from an arbitrary lower basis)
let indexToOctave (index : int) =
    index / SEMITONES_PER_OCTAVE

/// Work out the human-readable note (including octave) for a particular semitone
let indexToNote (index : int) (enharmonicPreference : TEnharmonicPreference) =
    {label = indexToName (index % SEMITONES_PER_OCTAVE) enharmonicPreference; octave = indexToOctave index}

/// An operator to detect whether one note is the same as or is an enharmonic of another (ignoring octave)
let (=~) note1 note2 =
    note1.chromaticIndex = note2.chromaticIndex

/// As =~ but the compared notes must also be the same octave
let (==~) note1 note2 =
    (note1.label =~ note2.label)
    && (note1.octave = note2.octave)

/// Return a note which is n semitones higher than the input note
let addSemitones note semitones enharmonicPreference =
    let newIndex = noteToIndex(note) + semitones
    indexToNote newIndex enharmonicPreference 

/// Return the note which results from playing the specified string at the specified fret:
let frettingToNote (instrument : TInstrument) (fretting : TFretting) : TNote =
    let openNote = instrument.tuning.[fretting.stringIndex]
    let frettedNote = addSemitones openNote fretting.fretIndex PreferNeither
    frettedNote

/// Given the root note and scale type of a chord, work out whether any sharps/flats in the chord
/// should be expressed using the sharp or the flat of an enharmonic pair 
let rootNoteToEnharmonicPreference (rootNote : TNote) (scaleType : TScaleType) =
    match (rootNote.label.name, rootNote.label.accidental) with
        // TODO many of these need checking
        | ('A', Natural) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferFlat
        | ('A', Sharp) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferSharp
        | ('B', Flat) -> 
            match scaleType with
                | Major -> PreferFlat
                | Minor -> PreferFlat
        | ('B', Natural) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferFlat
        | ('C', Natural) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferFlat
        | ('C', Sharp) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferSharp
        | ('D', Flat) -> 
            match scaleType with
                | Major -> PreferFlat
                | Minor -> PreferFlat
        | ('D', Natural) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferFlat
        | ('D', Sharp) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferSharp
        | ('E', Flat) -> 
            match scaleType with
                | Major -> PreferFlat
                | Minor -> PreferFlat
        | ('E', Natural) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferFlat
        | ('F', Natural) -> 
            match scaleType with
                | Major -> PreferFlat
                | Minor -> PreferSharp
        | ('F', Sharp) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferSharp
        | ('G', Flat) -> 
            match scaleType with
                | Major -> PreferFlat
                | Minor -> PreferFlat
        | ('G', Natural) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferSharp
        | ('G', Sharp) -> 
            match scaleType with
                | Major -> PreferSharp
                | Minor -> PreferSharp
        | ('A', Flat) -> 
            match scaleType with
                | Major -> PreferFlat
                | Minor -> PreferFlat
        | _ -> failwith "rootNoteToEnharmonicPreference: Unexpected root note: %A" rootNote

/// Takes a root note and chord type and returns the actual notes of the chord:
let chordOf (rootNote : TNote) (chordType : TChordType) =
    chordType.chordIndexes
    |> Array.map (fun index -> addSemitones rootNote index (rootNoteToEnharmonicPreference rootNote chordType.scaleType) )

/// List all the notes you could play on a given string between a lowest and highest fret
let notesBetween (instrument : TInstrument) (stringIndex : int) (lowestFret : int) (highestFret : int) : seq<TFrettedNote> =
    let frettedNotes = 
        seq {
            for fret in lowestFret..highestFret do 
                let aFretting = {stringIndex = stringIndex; fretIndex = fret}
                let aNote = frettingToNote instrument aFretting
                yield {fretting = aFretting; note = aNote}
        } 
    frettedNotes

/// As notesBetween but also including the note produced by the same string played open
let notesBetweenAndOpen (instrument : TInstrument) (stringIndex : int) (lowestFret : int) (highestFret : int) : seq<TFrettedNote> =
    (notesBetween instrument stringIndex 0 0) |> Seq.append <| (notesBetween instrument stringIndex lowestFret highestFret)

/// List all the notes which could be played in a range of frets, including notes available by playing a string open
let notesInBox (instrument : TInstrument) (lowestFret : int) (highestFret : int) =
    [|(Array.length instrument.tuning)-1..-1..0|] // Reverse order because the lowest pitch string is conventionally numbered highest
    |> Array.map (fun stringIndex -> notesBetweenAndOpen instrument stringIndex lowestFret highestFret)

/// Given two sequences and a comparator function, find the pairs of items for which the comparator returns true
let findPairs compare seqT seqU =
    seq {
            for t in seqT do
                for u in seqU do
                    if (compare t u) then
                        yield (t, u)
    }

/// Given a two sequences and a comparator function, find the first pair of items for which the comparator returns true
let tryFindFirstPair compare seqT seqU =
    let matches = findPairs compare seqT seqU
    if not (Seq.isEmpty matches) then
        Some(Seq.nth 0 matches)
    else
        None

/// Print the frettings for a shape
let printShape (label : string) (shape : seq<TFrettedNote>) =
    printfn "%s" label
    shape
    |> Seq.iter (fun fretting -> printfn "String %i fret %i" (fretting.fretting.stringIndex+1) (fretting.fretting.fretIndex) )
    |> ignore

/// For a given chord, search through the notes which could be played within a given range of frets to try and
/// provide a set of frettings which plays the notes for the chord:
let findShape (instrument : TInstrument) (lowestFret : int) (highestFret : int) (chord : TChord) =
    // Create a map of required notes and how many times they have been found (initially all 0):
    let wantedNotes = chord |> Array.map (fun note -> {mappedNote = note; useCount = 0})
    // A way to update the map to indicate that this note of the chord has been successfully provided:
    let markDone note =
        let mapIndex = wantedNotes |> Array.findIndex (fun item -> item.mappedNote = note)
        wantedNotes.[mapIndex].useCount <- wantedNotes.[mapIndex].useCount + 1
    // Create a list of notes are needed in priority order, where priority is defined as
    // first, prioritise notes which haven't been found at all; and second, prioritise notes in low-to-high order:
    // (Defined as a function() so that when a note is marked as provided it goes to the back of the queue.)
    let notesInPriorityOrder() = 
        let result = 
            wantedNotes 
            |> Array.sortBy (fun item -> (item.useCount*100) + (noteToIndex item.mappedNote))
            |> Array.map (fun item -> item.mappedNote)
            |> Seq.ofArray
        result
    // Set up a value and flag to help ensure we find the root note first:
    let rootNote = chord.[0]
    let rootNoteFound = ref false
    // Go through the strings from low to high listing the notes that string could play:
    let frettings =
        seq {for availableNotesForString in (notesInBox instrument lowestFret highestFret) do
                // Search the available notes and the required notes (the latter in priority order) finding the first
                // instance (if any) on this string where the required note can be played. (Since we use the =~ this might be in
                // any octave.)
                let hit = tryFindFirstPair (fun wantedNote availNote -> availNote.note.label =~ wantedNote.label) 
                                                (notesInPriorityOrder()) availableNotesForString 
                // If we found a note (if we haven't yet found the root note, this needs to be the root note):
                if (hit <> None) && (((snd(hit.Value).note.label) =~ rootNote.label) || !rootNoteFound) then 
                    // If we just found the root note, flag the fact:
                    if not !rootNoteFound then
                        rootNoteFound := true;
                    // Flag that this note has been found at least once:
                    markDone (fst(hit.Value))
                    // Yield the note together with its fretting:
                    yield snd(hit.Value) 
        }
    // Sort the output by string:
    frettings
    |> Seq.sortBy (fun fretting -> fretting.fretting.stringIndex)
    
// Examples:


// Ordinary 6-string with EADGBE tuning:
let standardGuitar = new TInstrument(
                                19, // Including nut
                                [|  // Treble side
                                    {label=ENat; octave=2}
                                    {label=BNat; octave=2}
                                    {label=GNat; octave=1}
                                    {label=DNat; octave=1}
                                    {label=ANat; octave=1}
                                    {label=ENat; octave=0}
                                    // Bass side
                                |]
                              )

let droppedDGuitar = new TInstrument(
                                19, // Including nut
                                [|  // Treble side
                                    {label=ENat; octave=2}
                                    {label=BNat; octave=2}
                                    {label=GNat; octave=1}
                                    {label=DNat; octave=1}
                                    {label=ANat; octave=1}
                                    {label=DNat; octave=0}
                                    // Bass side
                                |]
                              )

let celticGuitar =  new TInstrument(
                                19, // Including nut
                                [|  // Treble side
                                    {label=DNat; octave=2}
                                    {label=ANat; octave=2}
                                    {label=GNat; octave=1}
                                    {label=DNat; octave=1}
                                    {label=ANat; octave=1}
                                    {label=DNat; octave=0}
                                    // Bass side
                                |]
                              )

// This is the first and last time I shall have involvement with 'progressive Metal'.
// Seven stringed guitar used by 'TesseracT' - no, really: http://en.wikipedia.org/wiki/DADGAD
let tesseractGuitar =  new TInstrument(
                                19, // Including nut
                                [|  // Treble side
                                    {label=EFlat; octave=2}
                                    {label=BFlat; octave=2}
                                    {label=GFlat; octave=1}
                                    {label=EFlat; octave=1}
                                    {label=BFlat; octave=1}
                                    {label=FNat; octave=0}
                                    {label=BFlat; octave=0}
                                    // Bass side
                                |]
                              )

let plectrumBanjo =  new TInstrument(
                                23, // Including nut
                                [|  // Treble side
                                    {label=DNat; octave=1}
                                    {label=BNat; octave=0}
                                    {label=GNat; octave=0}
                                    {label=CNat; octave=0}
                                    // Bass side
                                |]
                              )

// Some chords to play:
let CMaj = chordOf {label=CNat; octave=1} major
let DMaj = chordOf {label=DNat; octave=1} major
let DMin = chordOf {label=DNat; octave=1} minor
let D7 = chordOf {label=DNat; octave=1} seventh
let DMaj7 = chordOf {label=DNat; octave=1} majorSeventh
let EMaj = chordOf {label=ENat; octave=0} major
let EMin = chordOf {label=ENat; octave=0} minor
let AMaj = chordOf {label=ANat; octave=1} major
let AMin = chordOf {label=ANat; octave=1} minor
let ADim = chordOf {label=ANat; octave=1} diminished

// Generate fingerings for a standard guitar
findShape standardGuitar 0 3 CMaj |> printShape "C Major" |> ignore
findShape standardGuitar 0 3 EMaj |> printShape "E Major" |> ignore
findShape standardGuitar 0 3 EMin |> printShape "E Minor" |> ignore
findShape standardGuitar 0 3 AMaj |> printShape "A Major" |> ignore
findShape standardGuitar 0 3 AMin |> printShape "A Minor" |> ignore
findShape standardGuitar 0 3 ADim |> printShape "A Dim" |> ignore
findShape standardGuitar 0 3 DMaj |> printShape "D Major" |> ignore
findShape standardGuitar 0 3 DMin |> printShape "D Minor" |> ignore
findShape standardGuitar 0 3 D7 |> printShape "D seventh" |> ignore
findShape standardGuitar 0 3 DMaj7 |> printShape "D major seventh" |> ignore

// Some lower D-chords for the dropped D guitar and Celtic guitars:
let DMajLow = chordOf {label=DNat; octave=0} major
let DMinLow = chordOf {label=DNat; octave=0} minor
let D7Low = chordOf {label=DNat; octave=0} seventh
let DMaj7Low = chordOf {label=DNat; octave=0} majorSeventh

// Generate fingerings for a dropped-D guitar
findShape droppedDGuitar 0 3 CMaj |> printShape "C Major" |> ignore
findShape droppedDGuitar 0 3 EMaj |> printShape "E Major" |> ignore
findShape droppedDGuitar 0 3 EMin |> printShape "E Minor" |> ignore
findShape droppedDGuitar 0 3 AMaj |> printShape "A Major" |> ignore
findShape droppedDGuitar 0 3 AMin |> printShape "A Minor" |> ignore
findShape droppedDGuitar 0 3 ADim |> printShape "A Dim" |> ignore
findShape droppedDGuitar 0 3 DMajLow |> printShape "D Major (low)" |> ignore
findShape droppedDGuitar 0 3 DMinLow |> printShape "D Minor (low)" |> ignore
findShape droppedDGuitar 0 3 D7Low |> printShape "D seventh (low)" |> ignore
findShape droppedDGuitar 0 3 DMaj7Low |> printShape "D major seventh (low)" |> ignore

// Generate fingerings for a Celtic guitar
findShape celticGuitar 0 3 CMaj |> printShape "C Major" |> ignore
findShape celticGuitar 0 3 EMaj |> printShape "E Major" |> ignore
findShape celticGuitar 0 3 EMin |> printShape "E Minor" |> ignore
findShape celticGuitar 0 3 AMaj |> printShape "A Major" |> ignore
findShape celticGuitar 0 3 AMin |> printShape "A Minor" |> ignore
findShape celticGuitar 0 3 ADim |> printShape "A Dim" |> ignore
// Needs a bit more of a stretch to get an F#
findShape celticGuitar 0 4 DMajLow |> printShape "D Major (low)" |> ignore 
findShape celticGuitar 0 3 DMinLow |> printShape "D Minor (low)" |> ignore
findShape celticGuitar 0 3 D7Low |> printShape "D seventh (low)" |> ignore
findShape celticGuitar 0 3 DMaj7Low |> printShape "D major seventh (low)" |> ignore

// Generate fingerings for a TesseracT's guitar
findShape tesseractGuitar 0 3 CMaj |> printShape "C Major" |> ignore
findShape tesseractGuitar 0 3 EMaj |> printShape "E Major" |> ignore
findShape tesseractGuitar 0 3 EMin |> printShape "E Minor" |> ignore
findShape tesseractGuitar 0 3 AMaj |> printShape "A Major" |> ignore
findShape tesseractGuitar 0 3 AMin |> printShape "A Minor" |> ignore

// We have to go up the neck a bit to find some Ds - and even then these are
// probably unplayable at the moment:
findShape tesseractGuitar 4 7 ADim |> printShape "A Dim" |> ignore
findShape tesseractGuitar 4 7 DMaj |> printShape "D Major" |> ignore
findShape tesseractGuitar 4 7 DMin |> printShape "D Minor" |> ignore
findShape tesseractGuitar 4 7 D7 |> printShape "D seventh" |> ignore
findShape tesseractGuitar 4 7 DMaj7 |> printShape "D major seventh" |> ignore

// Generate fingerings for a plectrum banjo
findShape plectrumBanjo 0 3 CMaj |> printShape "C Major" |> ignore

// Up the neck a bit for Es - I don't have a banjo to check these are playable!
findShape plectrumBanjo 1 4 EMaj |> printShape "E Major" |> ignore
findShape plectrumBanjo 1 4 EMin |> printShape "E Minor" |> ignore

findShape plectrumBanjo 0 3 AMaj |> printShape "A Major" |> ignore
findShape plectrumBanjo 0 3 AMin |> printShape "A Minor" |> ignore
findShape plectrumBanjo 0 3 ADim |> printShape "A Dim" |> ignore
findShape plectrumBanjo 0 3 DMaj |> printShape "D Major" |> ignore
findShape plectrumBanjo 0 3 DMin |> printShape "D Minor" |> ignore
findShape plectrumBanjo 0 3 D7 |> printShape "D seventh" |> ignore
findShape plectrumBanjo 0 3 DMaj7 |> printShape "D major seventh" |> ignore

// Example output for the first standard guitar line:
//  C Major
//  String 1 fret 0
//  String 2 fret 1
//  String 3 fret 0
//  String 4 fret 2
//  String 5 fret 3

// Example output for the final banjo line:
//  D major seventh
//  String 1 fret 0
//  String 2 fret 2
//  String 3 fret 2
//  String 4 fret 2
val SEMITONES_PER_OCTAVE : int

Full name: Script.SEMITONES_PER_OCTAVE
type TAccidental =
  | Flat
  | Natural
  | Sharp

Full name: Script.TAccidental
union case TAccidental.Flat: TAccidental
union case TAccidental.Natural: TAccidental
union case TAccidental.Sharp: TAccidental
type TNoteLabel =
  {name: char;
   accidental: TAccidental;
   chromaticIndex: int;}

Full name: Script.TNoteLabel
TNoteLabel.name: char
Multiple items
val char : value:'T -> char (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.char

--------------------
type char = System.Char

Full name: Microsoft.FSharp.Core.char
TNoteLabel.accidental: TAccidental
TNoteLabel.chromaticIndex: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
type TNote =
  {label: TNoteLabel;
   octave: int;}

Full name: Script.TNote
TNote.label: TNoteLabel
TNote.octave: int
type TChordIndexes = int array

Full name: Script.TChordIndexes
type 'T array = 'T []

Full name: Microsoft.FSharp.Core.array<_>
type TScaleType =
  | Major
  | Minor

Full name: Script.TScaleType
union case TScaleType.Major: TScaleType
union case TScaleType.Minor: TScaleType
type TChordType =
  {chordIndexes: TChordIndexes;
   scaleType: TScaleType;}

Full name: Script.TChordType
TChordType.chordIndexes: TChordIndexes
TChordType.scaleType: TScaleType
type TChord = TNote array

Full name: Script.TChord
type TEnharmonicPreference =
  | PreferFlat
  | PreferSharp
  | PreferNeither

Full name: Script.TEnharmonicPreference
union case TEnharmonicPreference.PreferFlat: TEnharmonicPreference
union case TEnharmonicPreference.PreferSharp: TEnharmonicPreference
union case TEnharmonicPreference.PreferNeither: TEnharmonicPreference
type TNoteMapping =
  {mappedNote: TNote;
   mutable useCount: int;}

Full name: Script.TNoteMapping
TNoteMapping.mappedNote: TNote
TNoteMapping.useCount: int
type TTuning = TNote array

Full name: Script.TTuning
type TFretting =
  {stringIndex: int;
   fretIndex: int;}

Full name: Script.TFretting
TFretting.stringIndex: int
TFretting.fretIndex: int
type TFrettedNote =
  {fretting: TFretting;
   note: TNote;}

Full name: Script.TFrettedNote
TFrettedNote.fretting: TFretting
TFrettedNote.note: TNote
Multiple items
type TInstrument =
  new : fretCount:int * tuning:TTuning -> TInstrument
  member fretCount : int
  member tuning : TTuning

Full name: Script.TInstrument


 Any fretted instrument:


--------------------
new : fretCount:int * tuning:TTuning -> TInstrument
val fretCount : int
val tuning : TTuning
val this : TInstrument
member TInstrument.fretCount : int

Full name: Script.TInstrument.fretCount
member TInstrument.tuning : TTuning

Full name: Script.TInstrument.tuning
val allNotes : TNoteLabel []

Full name: Script.allNotes


 All human readable note names, including enharmonics (but not bothering with double-flats, double-sharps):
val ANat : TNoteLabel

Full name: Script.ANat


 Some useful constants for notes:
val ASharp : TNoteLabel

Full name: Script.ASharp
val BFlat : TNoteLabel

Full name: Script.BFlat
val BNat : TNoteLabel

Full name: Script.BNat
val BSharp : TNoteLabel

Full name: Script.BSharp
val CFlat : TNoteLabel

Full name: Script.CFlat
val CNat : TNoteLabel

Full name: Script.CNat
val CSharp : TNoteLabel

Full name: Script.CSharp
val DFlat : TNoteLabel

Full name: Script.DFlat
val DNat : TNoteLabel

Full name: Script.DNat
val DSharp : TNoteLabel

Full name: Script.DSharp
val EFlat : TNoteLabel

Full name: Script.EFlat
val ENat : TNoteLabel

Full name: Script.ENat
val ESharp : TNoteLabel

Full name: Script.ESharp
val FFlat : TNoteLabel

Full name: Script.FFlat
val FNat : TNoteLabel

Full name: Script.FNat
Multiple items
val FSharp : TNoteLabel

Full name: Script.FSharp

--------------------
namespace Microsoft.FSharp
val GFlat : TNoteLabel

Full name: Script.GFlat
val GNat : TNoteLabel

Full name: Script.GNat
val GSharp : TNoteLabel

Full name: Script.GSharp
val AFlat : TNoteLabel

Full name: Script.AFlat
val a : 'a []
val b : 'a []
module Array

from Microsoft.FSharp.Collections
val concat : arrays:seq<'T []> -> 'T []

Full name: Microsoft.FSharp.Collections.Array.concat
val major : TChordType

Full name: Script.major
val minor : TChordType

Full name: Script.minor
val diminished : TChordType

Full name: Script.diminished
val augmented : TChordType

Full name: Script.augmented
val seventh : TChordType

Full name: Script.seventh
val majorSeventh : TChordType

Full name: Script.majorSeventh
val minorSeventh : TChordType

Full name: Script.minorSeventh
val indexToName : index:int -> enharmonicPreference:TEnharmonicPreference -> TNoteLabel

Full name: Script.indexToName


 Work out the human-readable note name for a particular chromatic index
val index : int
val enharmonicPreference : TEnharmonicPreference
val sortBy : projection:('T -> 'Key) -> array:'T [] -> 'T [] (requires comparison)

Full name: Microsoft.FSharp.Collections.Array.sortBy
val item : TNoteLabel
val find : predicate:('T -> bool) -> array:'T [] -> 'T

Full name: Microsoft.FSharp.Collections.Array.find
val noteToIndex : note:TNote -> int

Full name: Script.noteToIndex


 Work out the absolute chromatic index of a given note (ie. including the octave)
val note : TNote
val indexToOctave : index:int -> int

Full name: Script.indexToOctave


 Work out into what octave a particular semitone falls (from an arbitrary lower basis)
val indexToNote : index:int -> enharmonicPreference:TEnharmonicPreference -> TNote

Full name: Script.indexToNote


 Work out the human-readable note (including octave) for a particular semitone
val note1 : TNoteLabel
val note2 : TNoteLabel
val note1 : TNote
val note2 : TNote
val addSemitones : note:TNote -> semitones:int -> enharmonicPreference:TEnharmonicPreference -> TNote

Full name: Script.addSemitones


 Return a note which is n semitones higher than the input note
val semitones : int
val newIndex : int
val frettingToNote : instrument:TInstrument -> fretting:TFretting -> TNote

Full name: Script.frettingToNote


 Return the note which results from playing the specified string at the specified fret:
val instrument : TInstrument
val fretting : TFretting
val openNote : TNote
property TInstrument.tuning: TTuning
val frettedNote : TNote
val rootNoteToEnharmonicPreference : rootNote:TNote -> scaleType:TScaleType -> TEnharmonicPreference

Full name: Script.rootNoteToEnharmonicPreference


 Given the root note and scale type of a chord, work out whether any sharps/flats in the chord
 should be expressed using the sharp or the flat of an enharmonic pair
val rootNote : TNote
val scaleType : TScaleType
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val chordOf : rootNote:TNote -> chordType:TChordType -> TNote []

Full name: Script.chordOf


 Takes a root note and chord type and returns the actual notes of the chord:
val chordType : TChordType
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val notesBetween : instrument:TInstrument -> stringIndex:int -> lowestFret:int -> highestFret:int -> seq<TFrettedNote>

Full name: Script.notesBetween


 List all the notes you could play on a given string between a lowest and highest fret
val stringIndex : int
val lowestFret : int
val highestFret : int
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val frettedNotes : seq<TFrettedNote>
val fret : int
val aFretting : TFretting
val aNote : TNote
val notesBetweenAndOpen : instrument:TInstrument -> stringIndex:int -> lowestFret:int -> highestFret:int -> seq<TFrettedNote>

Full name: Script.notesBetweenAndOpen


 As notesBetween but also including the note produced by the same string played open
module Seq

from Microsoft.FSharp.Collections
val append : source1:seq<'T> -> source2:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.append
val notesInBox : instrument:TInstrument -> lowestFret:int -> highestFret:int -> seq<TFrettedNote> []

Full name: Script.notesInBox


 List all the notes which could be played in a range of frets, including notes available by playing a string open
val length : array:'T [] -> int

Full name: Microsoft.FSharp.Collections.Array.length
val findPairs : compare:('a -> 'b -> bool) -> seqT:seq<'a> -> seqU:seq<'b> -> seq<'a * 'b>

Full name: Script.findPairs


 Given two sequences and a comparator function, find the pairs of items for which the comparator returns true
val compare : ('a -> 'b -> bool)
val seqT : seq<'a>
val seqU : seq<'b>
val t : 'a
val u : 'b
val tryFindFirstPair : compare:('a -> 'b -> bool) -> seqT:seq<'a> -> seqU:seq<'b> -> ('a * 'b) option

Full name: Script.tryFindFirstPair


 Given a two sequences and a comparator function, find the first pair of items for which the comparator returns true
val matches : seq<'a * 'b>
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
val isEmpty : source:seq<'T> -> bool

Full name: Microsoft.FSharp.Collections.Seq.isEmpty
union case Option.Some: Value: 'T -> Option<'T>
val nth : index:int -> source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.nth
union case Option.None: Option<'T>
val printShape : label:string -> shape:seq<TFrettedNote> -> unit

Full name: Script.printShape


 Print the frettings for a shape
val label : string
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
val shape : seq<TFrettedNote>
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
val fretting : TFrettedNote
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val findShape : instrument:TInstrument -> lowestFret:int -> highestFret:int -> chord:TChord -> seq<TFrettedNote>

Full name: Script.findShape


 For a given chord, search through the notes which could be played within a given range of frets to try and
 provide a set of frettings which plays the notes for the chord:
val chord : TChord
val wantedNotes : TNoteMapping []
val markDone : (TNote -> unit)
val mapIndex : int
val findIndex : predicate:('T -> bool) -> array:'T [] -> int

Full name: Microsoft.FSharp.Collections.Array.findIndex
val item : TNoteMapping
val notesInPriorityOrder : (unit -> seq<TNote>)
val result : seq<TNote>
val ofArray : source:'T [] -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.ofArray
val rootNoteFound : bool ref
Multiple items
val ref : value:'T -> 'T ref

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
val frettings : seq<TFrettedNote>
val availableNotesForString : seq<TFrettedNote>
val hit : (TNote * TFrettedNote) option
val wantedNote : TNote
val availNote : TFrettedNote
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
property Option.Value: TNote * TFrettedNote
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Seq.sortBy
val standardGuitar : TInstrument

Full name: Script.standardGuitar
val droppedDGuitar : TInstrument

Full name: Script.droppedDGuitar
val celticGuitar : TInstrument

Full name: Script.celticGuitar
val tesseractGuitar : TInstrument

Full name: Script.tesseractGuitar
val plectrumBanjo : TInstrument

Full name: Script.plectrumBanjo
val CMaj : TNote []

Full name: Script.CMaj
val DMaj : TNote []

Full name: Script.DMaj
val DMin : TNote []

Full name: Script.DMin
val D7 : TNote []

Full name: Script.D7
val DMaj7 : TNote []

Full name: Script.DMaj7
val EMaj : TNote []

Full name: Script.EMaj
val EMin : TNote []

Full name: Script.EMin
val AMaj : TNote []

Full name: Script.AMaj
val AMin : TNote []

Full name: Script.AMin
val ADim : TNote []

Full name: Script.ADim
val DMajLow : TNote []

Full name: Script.DMajLow
val DMinLow : TNote []

Full name: Script.DMinLow
val D7Low : TNote []

Full name: Script.D7Low
val DMaj7Low : TNote []

Full name: Script.DMaj7Low

More information

Link:http://fssnip.net/76
Posted:4 years ago
Author:Kit Eason
Tags: guitar , chord , music