Skip to content

Commit

Permalink
Supported flats in chord progressions to parse
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed Dec 24, 2023
1 parent 0aa80dd commit 16c1e1a
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public sealed class ChordProgressionTests
[TestCase("I-II-IV", "C major", new[] { "C", "D", "F" })]
[TestCase("I-II-iv", "C major", new[] { "C", "D", "F" })]
[TestCase("Im-ii7-v", "C major", new[] { "Cm", "D7", "G" })]
[TestCase("i - bVI - III - bVII", "C major", new[] { "C", "G#", "E", "A#" })]
public void Parse(string input, string scaleString, string[] expectedChords)
{
var chordProgression = ChordProgression.Parse(input, Scale.Parse(scaleString));
Expand Down
14 changes: 12 additions & 2 deletions DryWetMidi/MusicTheory/ChordProgression/ChordProgressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ internal static class ChordProgressionParser
private const char PartsDelimiter = '-';

private const string ScaleDegreeGroupName = "sd";
private const string AccidentalGroupName = "ac";

private static readonly string AccidentalGroup = $"(?<{AccidentalGroupName}>b)";
private static readonly string ScaleDegreeGroup = $"(?<{ScaleDegreeGroupName}>(?i:M{{0,4}}(CM|CD|D?C{{0,3}})(XC|XL|L?X{{0,3}})(IX|IV|V?I{{0,3}})))";

private static readonly string[] Patterns = new[]
{
$@"{ScaleDegreeGroup}\s*{ChordParser.ChordCharacteristicsGroup}"
$@"{AccidentalGroup}?\s*{ScaleDegreeGroup}\s*{ChordParser.ChordCharacteristicsGroup}"
};

private static readonly Dictionary<char, int> RomanMap = new Dictionary<char, int>
Expand Down Expand Up @@ -57,11 +59,19 @@ internal static ParsingResult TryParse(string input, Scale scale, out ChordProgr
var degree = RomanToInteger(degreeRoman);
var rootNoteName = scale.GetStep(degree - 1);

var accidentalGroup = match.Groups[AccidentalGroupName];
if (accidentalGroup.Success)
{
var accidental = accidentalGroup.Value;
if (accidental == "b")
rootNoteName = (NoteName)(((int)rootNoteName + Octave.OctaveSize - 1) % Octave.OctaveSize);
}

var fullString = match.Value;
var matchIndex = match.Index;
var degreeGroupIndex = degreeGroup.Index;
var chordString =
fullString.Substring(0, degreeGroupIndex - matchIndex) +
fullString.Substring(0, degreeGroupIndex - matchIndex - (accidentalGroup.Success ? accidentalGroup.Length : 0)) +
rootNoteName +
fullString.Substring(degreeGroupIndex - matchIndex + degreeGroup.Length);

Expand Down

0 comments on commit 16c1e1a

Please sign in to comment.