Skip to content

Commit

Permalink
Tweaked chord prediction
Browse files Browse the repository at this point in the history
  • Loading branch information
Seank23 committed Feb 6, 2021
1 parent 6944ffb commit 3af3ba9
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 315 deletions.
142 changes: 69 additions & 73 deletions MusicAnalyser/App/Analysis/Analyser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,58 @@ public bool FindChordsNotes()
if (aggregateNotes.Count == 0)
return false;

int[,] tempNoteOccurences = new int[12, 2];
// UNUSED
//List<Note>[] notesByName = new List<Note>[12];
//for (int i = 0; i < 12; i++)
// notesByName[i] = new List<Note>();
//Dictionary<string, double> noteDistributionDict = new Dictionary<string, double>();

//for(int i = 0; i < aggregateNotes.Count; i++)
//{
// string noteName = aggregateNotes[i].Name;
// double noteMag = aggregateNotes[i].Magnitude;
// int index = aggregateNotes[i].NoteIndex;
// notesByName[index].Add(aggregateNotes[i]);
// if (noteDistributionDict.ContainsKey(noteName))
// noteDistributionDict[noteName] += noteMag;
// else
// noteDistributionDict.Add(noteName, noteMag);
//}
//string[] keys = noteDistributionDict.Keys.ToArray();
//foreach (string key in keys)
// noteDistributionDict[key] /= Prefs.CHORD_DETECTION_INTERVAL;

//noteDistributionDict = noteDistributionDict.OrderByDescending(x => x.Value).Take(4).ToDictionary(x => x.Key, x => x.Value);

//chordNotes = new List<Note>[noteDistributionDict.Count];
//keys = noteDistributionDict.Keys.ToArray();
//for (int i = 0; i < chordNotes.Length; i++)
//{
// chordNotes[i] = new List<Note>();
// List<int> octaves = new List<int>();
// int noteIndex = Music.GetNoteIndex(keys[i] + "0");
// for (int j = 0; j < notesByName[noteIndex].Count; j++)
// {
// if (!octaves.Contains(notesByName[noteIndex][j].Octave)) // Stores each prominent note in collected notes only once
// {
// chordNotes[i].Add(notesByName[noteIndex][j]);
// octaves.Add(notesByName[noteIndex][j].Octave);
// }
// }
// chordNotes[i] = chordNotes[i].OrderBy(x => x.Frequency).ToList(); // Order: Frequency - low to high
//}
//aggregateNotes.Clear();
//return true;

int[,] tempNoteOccurences = new int[12, 2]; // Note index, timestamp
List<Note>[] notesByName = new List<Note>[12];
for (int i = 0; i < 12; i++)
notesByName[i] = new List<Note>();

int initialTimeStamp = aggregateNotes[0].TimeStamp;
int timeStampOffset = 0;

for(int i = 0; i < aggregateNotes.Count; i++)
for (int i = 0; i < aggregateNotes.Count; i++)
{
int index = aggregateNotes[i].NoteIndex;
notesByName[index].Add(aggregateNotes[i]);
Expand All @@ -198,68 +241,28 @@ public bool FindChordsNotes()
}
aggregateNotes.Clear();

int numChordNotes = 0;
List<int> chordNoteIndexes = new List<int>();
for(int i = 0; i < tempNoteOccurences.Length / 2; i++)
for (int i = 0; i < tempNoteOccurences.Length / 2; i++)
{
if(tempNoteOccurences[i, 0] >= Prefs.CHORD_NOTE_OCCURENCE_OFFSET)
{
numChordNotes++;
if (tempNoteOccurences[i, 0] >= Prefs.CHORD_NOTE_OCCURENCE_OFFSET) // Prunes spurious notes
chordNoteIndexes.Add(i);
}
}

chordNotes = new List<Note>[numChordNotes];
for(int i = 0; i < numChordNotes; i++)
chordNotes = new List<Note>[chordNoteIndexes.Count];
for (int i = 0; i < chordNotes.Length; i++)
{
chordNotes[i] = new List<Note>();
List<int> octaves = new List<int>();
for(int j = 0; j < notesByName[chordNoteIndexes[i]].Count; j++)
for (int j = 0; j < notesByName[chordNoteIndexes[i]].Count; j++)
{
if (!octaves.Contains(notesByName[chordNoteIndexes[i]][j].Octave))
if (!octaves.Contains(notesByName[chordNoteIndexes[i]][j].Octave)) // Stores each prominent note in collected notes only once
{
chordNotes[i].Add(notesByName[chordNoteIndexes[i]][j]);
octaves.Add(notesByName[chordNoteIndexes[i]][j].Octave);
}
}
chordNotes[i] = chordNotes[i].OrderBy(x => x.Frequency).ToList(); // Order: Frequency - low to high
}

int removed = 0;
for(int i = 0; i < chordNotes.Length; i++)
{
if(chordNotes[i].Count == 1 && chordNotes[i][0].Octave > 4)
{
chordNotes[i].Clear();
removed++;
continue;
}

int lowestOctave = chordNotes[i][0].Octave;
for(int j = 1; j < chordNotes[i].Count; j++)
{
if (chordNotes[i][j].Octave < lowestOctave)
lowestOctave = chordNotes[i][j].Octave;
}

if (lowestOctave > 4)
{
chordNotes[i].Clear();
removed++;
}
}

List<Note>[] chordTemp = new List<Note>[chordNotes.Length - removed];
int tempIndex = 0;
for(int i = 0; i < chordNotes.Length; i++)
{
if (chordNotes[i].Count != 0)
{
chordTemp[tempIndex] = chordNotes[i];
tempIndex++;
}
}
chordNotes = chordTemp;
return true;
}

Expand Down Expand Up @@ -293,9 +296,9 @@ public void FindChords()
noteDifference = 12 + noteDifference;
intervals.Add(noteDifference);
}
string chordQuality = Music.GetChordQuality(intervals); // Determines chord quality from intervals
if(chordQuality != "N/A")
chords.Add(CreateChord(myChordNotes[0].Name, chordQuality, myChordNotes));
string chordQuality = Music.GetChordQuality(intervals, out int fifthOmitted); // Determines chord quality from intervals
if (chordQuality != "N/A")
chords.Add(CreateChord(myChordNotes[0].Name, chordQuality, myChordNotes, fifthOmitted));

myChordNotes = NextChord(myChordNotes); // Iterates chord root note
}
Expand All @@ -305,7 +308,7 @@ public void FindChords()
prevChord = chords[0];
}

private Chord CreateChord(string root, string quality, List<Note> notes)
private Chord CreateChord(string root, string quality, List<Note> notes, int fifthOmitted)
{
Note[] tempNotes = new Note[notes.Count];
Array.Copy(notes.ToArray(), tempNotes, notes.Count);
Expand All @@ -321,7 +324,8 @@ private Chord CreateChord(string root, string quality, List<Note> notes)
Root = root,
Quality = quality,
Notes = tempNotes.ToList(),
NumExtensions = numExtensions
NumExtensions = numExtensions,
FifthOmitted = fifthOmitted
};
return myChord;
}
Expand Down Expand Up @@ -352,44 +356,36 @@ private void AdjustChordProbabilities()
rootFreq[i] = chords[i].Notes[0].Frequency;
double avgFreq = rootFreq.Average();
for (int i = 0; i < rootFreq.Length; i++)
rootFreq[i] -= avgFreq;
rootFreq[i] = avgFreq - rootFreq[i];
rootFreq = Normalise(rootFreq);

double[] chordExtensions = new double[chords.Count];
for (int i = 0; i < chords.Count; i++)
chordExtensions[i] = chords[i].NumExtensions;
double avgExtensions = chordExtensions.Average();
for (int i = 0; i < chordExtensions.Length; i++)
chordExtensions[i] -= avgExtensions;
chordExtensions[i] = avgExtensions - chordExtensions[i];
chordExtensions = Normalise(chordExtensions);

double[] fifthOmitted = new double[chords.Count];
for (int i = 0; i < chords.Count; i++)
fifthOmitted[i] = chords[i].FifthOmitted;
fifthOmitted = Normalise(fifthOmitted);

double[] chordPredictedBefore = new double[chords.Count];
if (prevChord != null)
{
for(int i = 0; i < chords.Count; i++)
{
if (chords[i].Root == prevChord.Root)
chordPredictedBefore[i] += 1;
}
}

double[] rootInKey = new double[chords.Count];
if (majorKeyRoot != "N/A")
{
string[] scale = new string[7];
Array.Copy(Music.Scales, Music.GetNoteIndex(majorKeyRoot + "0") * 7, scale, 0, scale.Length);
for (int i = 0; i < chords.Count; i++)
{
if (scale.Contains(chords[i].Root))
rootInKey[i] += 1;
else
rootInKey[i] -= 1;
if (chords[i].Root == prevChord.Root)
chordPredictedBefore[i] += 1;
}
}

double[] overallProb = new double[chords.Count];
for(int i = 0; i < chords.Count; i++)
overallProb[i] = rootMagnitudes[i] + rootOccurences[i] - 2 * rootFreq[i] - chordExtensions[i] + 1.5 * chordPredictedBefore[i] + rootInKey[i];
for (int i = 0; i < chords.Count; i++)
//overallProb[i] = 1.0 * rootMagnitudes[i] + 1.0 * rootOccurences[i] + 1.0 * chordExtensions[i] + 2 * rootFreq[i] + 1.0 * fifthOmitted[i] + 1.5 * chordPredictedBefore[i];
overallProb[i] = 1.1*rootMagnitudes[i] + 1.0*rootOccurences[i] + 2.3*chordExtensions[i] + 1.8*rootFreq[i] + 1.0*fifthOmitted[i] + 0.7*chordPredictedBefore[i];
overallProb = Normalise(overallProb);
double probSum = overallProb[0] + 1;
for (int i = 1; i < chords.Count; i++)
Expand Down
1 change: 1 addition & 0 deletions MusicAnalyser/App/Analysis/Chord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Chord
public string Quality { get; set; }
public List<Note> Notes { get; set; }
public int NumExtensions { get; set; }
public int FifthOmitted { get; set; }
public double Probability { get; set; }
}
}
4 changes: 2 additions & 2 deletions MusicAnalyser/App/Analysis/Music.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,9 @@ public static string GetMode(double[] percent, string majorRoot, string minorRoo
return "";
}

public static string GetChordQuality(List<int> intervals)
public static string GetChordQuality(List<int> intervals, out int fifthOmitted)
{
int fifthOmitted = 0;
fifthOmitted = 0;
while (fifthOmitted <= 1)
{
if (intervals.Contains(4) && intervals.Contains(7)) // Major chords
Expand Down
Loading

0 comments on commit 3af3ba9

Please sign in to comment.