/// <inheritdoc cref="GetNotes(IChord, ChordNoteMappingSource, NotePitch, NotePitch)"/> internal static IEnumerable <NotePitch> GetNotes(IChord chord, ChordNoteMappingSource mappingSource, int minOctave = 0, int maxOctave = 9) { int basePitch = MusicTheoryServices.SemitonesInOctave; NotePitch minPitch = (NotePitch)(basePitch + (minOctave * MusicTheoryServices.SemitonesInOctave)); NotePitch maxPitch = (NotePitch)(basePitch + ((maxOctave + 1) * MusicTheoryServices.SemitonesInOctave) - 1); return(MusicTheoryServices.GetNotes(chord, mappingSource, minPitch, maxPitch)); }
/// <summary> /// Returns notes that sound "good" under the given chord and pitch range restriction. /// </summary> /// <param name="chord"> he requested chrod to map the notes against. </param> /// <param name="mappingSource"> The mapping source - either scale notes or the chord's arpeggio notes. </param> /// <param name="minPitch"> Lower bound pitch range constraint for the mapped notes. </param> /// <param name="maxPitch"> Upper bound pitch range constraint for the mapped notes. </param> /// <returns> Notes that sound "good" under the given chord, mapping source, and pitch range restriction. </returns> internal static IEnumerable <NotePitch> GetNotes(IChord chord, ChordNoteMappingSource mappingSource, NotePitch minPitch, NotePitch maxPitch) { // build the scale (sequence of intervals from the chord's root note) var rootNote = ConvertToExternalNoteName(chord.ChordRoot); Scale scale = null; switch (chord.ChordType) { case ChordType.Diminished: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Three, Interval.Three, Interval.Six }, rootNote); } else // diminished arppeigo with added 9th { scale = new Scale(new Interval[] { Interval.One, Interval.Two, Interval.Three, Interval.Six }, rootNote); } break; case ChordType.Dominant7: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Three, Interval.Three, Interval.Two }, rootNote); } else // mixolydian scale with omitted 4th { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.Three, Interval.Two, Interval.One, Interval.Two }, rootNote); } break; case ChordType.Dominant7b9: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Three, Interval.Three, Interval.Three, Interval.FromHalfSteps(-1) }, rootNote); } else // harmonic minor v scale with 6th omitted { scale = new Scale(new Interval[] { Interval.One, Interval.Three, Interval.One, Interval.Two, Interval.Three, Interval.Two }, rootNote); } break; case ChordType.Dominant7Suspended4: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Five, Interval.Two, Interval.Three, Interval.Two }, rootNote); } else // mixolydian scale { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.One, Interval.Two, Interval.Two, Interval.One, Interval.Two }, rootNote); } break; case ChordType.Dominant7Augmented5: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Four, Interval.Two, Interval.Two }, rootNote); } else // whole tone scale { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.Two, Interval.Two, Interval.Two, Interval.Two }, rootNote); } break; case ChordType.Dominant7Sharped9: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Three, Interval.Three, Interval.Four, Interval.FromHalfSteps(-3) }, rootNote); } else // mixolydian #2 scale with omitted 4th { scale = new Scale(new Interval[] { Interval.Three, Interval.One, Interval.Three, Interval.Two, Interval.One, Interval.Two }, rootNote); } break; case ChordType.HalfDiminished: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Three, Interval.Three, Interval.Four, Interval.Two }, rootNote); } else // locrian mode scale with ommited 2nd { scale = new Scale(new Interval[] { Interval.Three, Interval.Two, Interval.One, Interval.Two, Interval.Two, Interval.Two }, rootNote); } break; case ChordType.Major: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Three, Interval.Five }, rootNote); } else // dorian major scale with omitted 4th and 7th { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.Three, Interval.Two, Interval.Three }, rootNote); } break; case ChordType.Major7: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Three, Interval.Four, Interval.One }, rootNote); } else // dorian major scale with omitted 4th { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.Three, Interval.Two, Interval.Two, Interval.One }, rootNote); } break; case ChordType.MajorAugmented5: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Four, Interval.Four }, rootNote); } else // lydian augmented scale { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.Two, Interval.Two, Interval.One, Interval.Two, Interval.One }, rootNote); } break; case ChordType.MajorSuspended4: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Five, Interval.Two, Interval.Five }, rootNote); } else // mixolydian scale { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.One, Interval.Two, Interval.Two, Interval.One, Interval.Two }, rootNote); } break; case ChordType.Minor: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Three, Interval.Four, Interval.Five }, rootNote); } else // aeolian minor scale with omitted 2nd and 6th { scale = new Scale(new Interval[] { Interval.Three, Interval.Two, Interval.Two, Interval.Three, Interval.Two }, rootNote); } break; case ChordType.Minor6: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Three, Interval.Four, Interval.Two, Interval.Three }, rootNote); } else // dorian minor scale with omitted 7th { scale = new Scale(new Interval[] { Interval.Two, Interval.One, Interval.Two, Interval.Two, Interval.Two, Interval.Three }, rootNote); } break; case ChordType.Minor7: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Three, Interval.Four, Interval.Three, Interval.Two }, rootNote); } else // aeolian minor scale with omitted 6th { scale = new Scale(new Interval[] { Interval.Two, Interval.One, Interval.Two, Interval.Two, Interval.Three, Interval.Two }, rootNote); } break; case ChordType.MinorMajor7: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Three, Interval.Four, Interval.Four, Interval.One }, rootNote); } else // harmonic minor scale { scale = new Scale(new Interval[] { Interval.Two, Interval.One, Interval.Two, Interval.Two, Interval.One, Interval.Three, Interval.One }, rootNote); } break; case ChordType.Major13: if (mappingSource == ChordNoteMappingSource.Chord) { scale = new Scale(new Interval[] { Interval.Four, Interval.Three, Interval.Two, Interval.Three }, rootNote); } else // dorian major scale with omitted 4th and 7th { scale = new Scale(new Interval[] { Interval.Two, Interval.Two, Interval.Three, Interval.Two, Interval.Three }, rootNote); } break; default: break; } // get actual notes and filter out results according to range constraints var result = from note in scale.GetNotes() where (int)note.NoteNumber >= (byte)minPitch && (int)note.NoteNumber <= (byte) maxPitch select(NotePitch)(int) note.NoteNumber; return(result); }