Пример #1
0
        private static IDictionary <NoteName, int> GetExtensionNotes(
            Quality?quality,
            NoteName rootNoteName,
            int extensionIntervalNumber,
            IntervalQuality?extensionIntervalQuality)
        {
            var result = new Dictionary <NoteName, int>();

            var intervalQualities = Enumerable
                                    .Range(0, extensionIntervalNumber + 1)
                                    .Select(i => i > 2 && Interval.IsPerfect(i) ? IntervalQuality.Perfect : IntervalQuality.Major)
                                    .ToArray();

            if (extensionIntervalNumber >= 7)
            {
                if (extensionIntervalQuality == null && quality == null)
                {
                    intervalQualities[7] = IntervalQuality.Minor;
                }
                else if (extensionIntervalQuality != null)
                {
                    intervalQualities[7] = extensionIntervalQuality.Value;
                    intervalQualities[extensionIntervalNumber] = extensionIntervalQuality.Value;
                }
                else
                {
                    intervalQualities[7] = quality == Quality.HalfDiminished || quality == Quality.Dominant || quality == Quality.Augmented
                        ? IntervalQuality.Minor
                        : ChordToIntervalQualities[quality.Value];
                }

                for (var i = 7; i <= extensionIntervalNumber; i += 2)
                {
                    result.Add(rootNoteName.Transpose(Interval.Get(intervalQualities[i], i)), i);
                }
            }
            else
            {
                if (extensionIntervalQuality != null)
                {
                    intervalQualities[extensionIntervalNumber] = extensionIntervalQuality.Value;
                }

                result.Add(
                    rootNoteName.Transpose(Interval.Get(intervalQualities[extensionIntervalNumber], extensionIntervalNumber)),
                    extensionIntervalNumber);
            }

            return(result);
        }
Пример #2
0
        public void Transpose(NoteName noteName, int halfSteps, NoteName expectedNoteName)
        {
            var interval       = Interval.FromHalfSteps(halfSteps);
            var actualNoteName = noteName.Transpose(interval);

            Assert.AreEqual(expectedNoteName, actualNoteName, "Transposed note name is invalid.");
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="Chord"/> with the specified root note name and
        /// intervals from root one.
        /// </summary>
        /// <param name="rootNoteName">The root note's name.</param>
        /// <param name="intervalsFromRoot">Intervals from root note.</param>
        /// <exception cref="InvalidEnumArgumentException"><paramref name="rootNoteName"/> specified an invalid value.</exception>
        /// <exception cref="ArgumentNullException"><paramref name="intervalsFromRoot"/> is <c>null</c>.</exception>
        public Chord(NoteName rootNoteName, IEnumerable <Interval> intervalsFromRoot)
        {
            ThrowIfArgument.IsInvalidEnumValue(nameof(rootNoteName), rootNoteName);
            ThrowIfArgument.IsNull(nameof(intervalsFromRoot), intervalsFromRoot);

            NotesNames = new[] { Interval.Zero }.Concat(intervalsFromRoot)
            .Where(i => i != null)
            .OrderBy(i => i.HalfSteps)
            .Select(i => rootNoteName.Transpose(i))
            .ToArray();
        }
        public static NoteName[] GetChordNotesNames(NoteName rootNoteName, string chordCharacteristic, NoteName?bassNoteName)
        {
            var notesNames = new List <NoteName>();

            if (bassNoteName != null)
            {
                notesNames.Add(bassNoteName.Value);
            }

            var definition = NamesDefinitions.FirstOrDefault(d => d.Names.Contains(chordCharacteristic.Replace(" ", string.Empty)));

            if (definition != null)
            {
                notesNames.AddRange(definition.Intervals.First().Select(i => rootNoteName.Transpose(Interval.FromHalfSteps(i))));
            }

            return(notesNames.ToArray());
        }
Пример #5
0
        internal static ParsingResult TryParseChordName(Match match, NoteName rootNoteName, out Chord chord)
        {
            chord = null;

            //

            Quality?quality = null;

            var qualityGroup = match.Groups[ChordQualityGroupName];

            if (qualityGroup.Success)
            {
                quality = GroupsQualities.FirstOrDefault(gq => match.Groups[gq.Key].Success).Value;
            }

            //

            var             extensionIntervalNumber  = -1;
            IntervalQuality?extensionIntervalQuality = null;

            var extensionGroup = match.Groups[ExtensionGroupName];

            if (extensionGroup.Success && !string.IsNullOrWhiteSpace(extensionGroup.Value))
            {
                if (match.Groups[ExtensionQualityGroupName].Success)
                {
                    extensionIntervalQuality = GroupsExtensionQualities.FirstOrDefault(gq => match.Groups[gq.Key].Success).Value;
                }

                if (!ParsingUtilities.ParseInt(match, ExtensionNumberGroupName, -1, out extensionIntervalNumber) ||
                    extensionIntervalNumber < 5)
                {
                    return(ParsingResult.Error(ExtensionNumberIsOutOfRange));
                }
            }

            if (quality == Quality.HalfDiminished || quality == Quality.Dominant)
            {
                if (extensionIntervalNumber >= 0 && extensionIntervalNumber != 7)
                {
                    return(ParsingResult.Error(HalfDiminishedOrDominantIsNotSeventh));
                }

                if (extensionIntervalNumber < 0)
                {
                    extensionIntervalNumber = 7;
                }
            }

            var extensionNotes   = new List <NoteName>();
            var extensionNumbers = new List <int>();

            if (extensionIntervalNumber >= 0)
            {
                var extensionNotesDictionary = GetExtensionNotes(quality, rootNoteName, extensionIntervalNumber, extensionIntervalQuality);
                extensionNotes.AddRange(extensionNotesDictionary.Keys);
                extensionNumbers.AddRange(extensionNotesDictionary.Values);
            }

            if (quality == Quality.HalfDiminished)
            {
                quality = Quality.Diminished;
            }
            else if (quality == Quality.Dominant)
            {
                quality = Quality.Major;
            }

            if (quality == null)
            {
                quality = Quality.Major;
            }

            //

            var notes = new List <NoteName>(Chord.GetByTriad(rootNoteName, ChordQualities[quality.Value]).NotesNames);

            notes.AddRange(extensionNotes);
            extensionNumbers.InsertRange(0, new[] { 1, 3, 5 });
            if (extensionIntervalNumber == 5)
            {
                notes.Clear();
                notes.AddRange(new[] { rootNoteName, extensionNotes.First() });

                extensionNumbers.Clear();
                extensionNumbers.AddRange(new[] { 1, 5 });
            }

            //

            var alteredToneGroup = match.Groups[AlteredToneGroupName];

            if (alteredToneGroup.Success)
            {
                int alteredToneNumber;
                if (!ParsingUtilities.ParseInt(match, AlteredToneNumberGroupName, -1, out alteredToneNumber))
                {
                    return(ParsingResult.Error(AlteredToneNumberIsOutOfRange));
                }

                var transposeBy = 0;

                var accidental = match.Groups[AlteredToneAccidentalGroupName].Value;
                switch (accidental)
                {
                case "#":
                case "+":
                    transposeBy = 1;
                    break;

                case "b":
                case "-":
                    transposeBy = -1;
                    break;
                }

                var maxExtensionNumber = extensionNumbers.Max();
                if (maxExtensionNumber < alteredToneNumber)
                {
                    var extensionNotesDictionary = GetExtensionNotes(quality, rootNoteName, alteredToneNumber, null)
                                                   .Where(kv => kv.Value > maxExtensionNumber);

                    notes.AddRange(extensionNotesDictionary.Select(kv => kv.Key));
                    extensionNumbers.AddRange(extensionNotesDictionary.Select(kv => kv.Value));
                }

                var index = extensionNumbers.IndexOf(alteredToneNumber);
                if (index >= 0)
                {
                    notes[index] = notes[index].Transpose(Interval.FromHalfSteps(transposeBy));
                }
            }

            //

            var suspendedGroup = match.Groups[SuspendedGroupName];

            if (suspendedGroup.Success)
            {
                int suspensionNumber;
                if (!ParsingUtilities.ParseInt(match, SuspendedNumberGroupName, -1, out suspensionNumber) ||
                    suspensionNumber != 2 && suspensionNumber != 4)
                {
                    return(ParsingResult.Error(SuspensionNumberIsOutOfRange));
                }

                var interval = suspensionNumber == 2
                    ? Interval.Get(IntervalQuality.Major, 2)
                    : Interval.Get(IntervalQuality.Perfect, 4);
                notes[1] = rootNoteName.Transpose(interval);
            }

            //

            var addedToneGroup = match.Groups[AddedToneGroupName];

            if (addedToneGroup.Success)
            {
                int addedToneNumber;
                if (!ParsingUtilities.ParseInt(match, AddedToneNumberGroupName, -1, out addedToneNumber))
                {
                    return(ParsingResult.Error(AddedToneNumberIsOutOfRange));
                }

                var interval = Interval.IsPerfect(addedToneNumber)
                    ? Interval.Get(IntervalQuality.Perfect, addedToneNumber)
                    : Interval.Get(IntervalQuality.Major, addedToneNumber);
                notes.Add(rootNoteName.Transpose(interval));
            }

            //

            var bassNoteNameGroup = match.Groups[BassNoteNameGroupName];

            if (bassNoteNameGroup.Success)
            {
                NoteName bassNoteName;
                var      bassNoteNameParsingResult = NoteNameParser.TryParse(bassNoteNameGroup.Value, out bassNoteName);
                if (bassNoteNameParsingResult.Status != ParsingStatus.Parsed)
                {
                    return(bassNoteNameParsingResult);
                }

                notes.Insert(0, bassNoteName);
            }

            //

            chord = new Chord(notes);
            return(ParsingResult.Parsed);
        }