// // Copyright 1998-2000 by Craig Stuart Sapp, All Rights Reserved. // Programmer: Craig Stuart Sapp // Creation Date: Mon May 14 12:26:45 PDT 2001 // Last Modified: Tue May 15 11:23:21 PDT 2001 // Last Modified: Sun Mar 24 12:10:00 PST 2002 (small changes for visual c++) // Filename: ...sig/src/sigInfo/HumdrumFile-chord.cpp // Web Address: http://sig.sapp.org/src/sigInfo/HumdrumFile.cpp // Syntax: C++ // // Description: Chord analysis functions for the HumdrumFile class. // #include "HumdrumFile.h" #include "humdrumfileextras.h" #include "Convert.h" #include #include #include #include #include #ifndef OLDCPP #include #include using namespace std; #else #include #include #endif ////////////////////////////// // // HumdrumFile::measureChordRoot -- measures the chord root // of a region of music and returns the most likely root // and fills an array of scores for each possible root. // int HumdrumFile::measureChordRoot(Array& scores, Array& parameters, int startindex, int stopindex, int algorithmno, int debug) { NoteListArray notelist; generateNoteList(notelist, startindex, stopindex); if (debug) { cout << "START INDEX = " << startindex << "\tSTOP INDEX = " << stopindex << "\n"; for (int i=0; i& scores, Array& parameters, double startbeat, double stopbeat, int algorithmno, int debug) { int start = getStartIndex(startbeat); int stop = getStopIndex(stopbeat); // cout << "STARTBEAT = " << startbeat << "\tSTOPBEAT = " << stopbeat << endl; return measureChordRoot(scores, parameters, start, stop, algorithmno, debug); } ////////////////////////////// // // static HumdrumFile::measureChordRoot0 -- starting algorithm // int HumdrumFile::measureChordRoot0(Array& scores, Array& parameters, NoteListArray& notelist) { return measureChordRoot1(scores, parameters, notelist); } ////////////////////////////// // // static HumdrumFile::measureChordRoot1 -- switching sign in // algorithm 0 // int HumdrumFile::measureChordRoot1(Array& scores, Array& parameters, NoteListArray& notelist) { int vx[40] = {0, 7, 7, 1000, 4, 4, 4, 4, 4, 1000, 8, 1, 1, 8, 8, 5, 5, 5, 5, 5, 1000, 9, 2, 2, 2, 9, 1000, 6, 6, 6, 6, 6, 1000, 3, 3, 3, 3, 10, 7, 7}; int vy[40] = {0, -2, -4, 1000, 4, 2, 0, -2, -4, 1000, 3, 1, 1, -3, -5, 5, 3, 1, -1, -3, 1000, 4, 2, 0, -2, -4, 1000, 4, 2, 0, -2, -4, 1000, 3, 1, -1, -3, -5, 4, 2}; double& alpha = parameters[0]; double& delta = parameters[1]; double& lambda = parameters[2]; scores.setSize(40); scores.zero(); int i, j; int p; int count = notelist.getSize(); double asum, bsum; double I; int max = 0; // cout << "Notelist size is: " << notelist.getSize() << endl; // cout << "Scores size is: " << scores.getSize() << endl; for (i=0; i<40; i++) { asum = bsum = 0.0; for (j=0; j M3count) { // indicate minor key by putting up the tonic an octave. max = max + 40; } if (scores[max % 40] == 0.0) { return -1; } else { return max; } } ////////////////////////////// // // static HumdrumFile::measureChordRoot2 -- Mix duration // and metric level by addition // int HumdrumFile::measureChordRoot2(Array& scores, Array& parameters, NoteListArray& notelist) { int vx[40] = {0, 7, 7, 1000, 4, 4, 4, 4, 4, 1000, 8, 1, 1, 8, 8, 5, 5, 5, 5, 5, 1000, 9, 2, 2, 2, 9, 1000, 6, 6, 6, 6, 6, 1000, 3, 3, 3, 3, 10, 7, 7}; int vy[40] = {0, -2, -4, 1000, 4, 2, 0, -2, -4, 1000, 3, 1, 1, -3, -5, 5, 3, 1, -1, -3, 1000, 4, 2, 0, -2, -4, 1000, 4, 2, 0, -2, -4, 1000, 3, 1, -1, -3, -5, 4, 2}; double& alpha = parameters[0]; double& delta = parameters[1]; double& lambda = parameters[2]; scores.setSize(40); scores.zero(); int i, j; int p; int count = notelist.getSize(); double asum, bsum; double I; int max = 0; double offset = 0.0; double testv; for (i=0; i offset) { offset = testv; } testv = -log(notelist[i].getLevel())/log(2.0); if (testv > offset) { offset = testv; } } offset = offset * 2; // cout << "Notelist size is: " << notelist.getSize() << endl; // cout << "Scores size is: " << scores.getSize() << endl; for (i=0; i<40; i++) { asum = bsum = 0.0; for (j=0; j& scores, Array& parameters, NoteListArray& notelist) { return 0; } ////////////////////////////// // // static HumdrumFile::measureChordRoot4 -- // int HumdrumFile::measureChordRoot4(Array& scores, Array& parameters, NoteListArray& notelist) { return 0; } ////////////////////////////// // // static HumdrumFile::measureChordRoot5 -- // int HumdrumFile::measureChordRoot5(Array& scores, Array& parameters, NoteListArray& notelist) { return 0; } ////////////////////////////// // // static HumdrumFile::measureChordRoot6 -- // int HumdrumFile::measureChordRoot6(Array& scores, Array& parameters, NoteListArray& notelist) { return 0; } ////////////////////////////// // // static HumdrumFile::measureChordRoot7 -- // int HumdrumFile::measureChordRoot7(Array& scores, Array& parameters, NoteListArray& notelist) { return 0; } ////////////////////////////// // // static HumdrumFile::measureChordRoot8 -- // int HumdrumFile::measureChordRoot8(Array& scores, Array& parameters, NoteListArray& notelist) { return 0; } ////////////////////////////// // // static HumdrumFile::measureChordRoot9 -- // int HumdrumFile::measureChordRoot9(Array& scores, Array& parameters, NoteListArray& notelist) { return 0; } ////////////////////////////// // // HumdrumFile::generateNoteList -- // default values: startLine = 0; endline = 0; // void HumdrumFile::generateNoteList(NoteListArray& notelist, int startLine, int endLine) { HumdrumFile& score = *this; // cout << "start index: " << startLine << "\tstopindex: " << endLine << endl; // int z; // for (z=startLine; z<=endLine; z++) { // cout << "\t" << score[z] << endl; // } if (endLine <= 0) { endLine = score.getNumLines() - 1; } if (startLine > endLine) { int temp = endLine; endLine = startLine; startLine = temp; } // estimate the largest amount necessary: notelist.setSize(score.getNumLines() * score.getMaxTracks() * 10); notelist.setGrowth(score.getNumLines()); notelist.setSize(0); notelist.allowGrowth(1); NoteList currentlist; currentlist.clear(); Array scorelevels; score.analyzeMetricLevel(scorelevels); int firsttime = 1; int i, j, k; int ii, jj; int ccount; static char buffer[1024] = {0}; int pitch; int token; int spine; double beatvalue; double track; double duration; double firstdur; for (i=startLine; i<=endLine; i++) { if (score[i].getType() != E_humrec_data) { // ignore non-note data lines continue; } beatvalue = score.getAbsBeat(i); ii = i; for (j=0; j& coef, double startbeat, double stopbeat, Array& scorelevels, double empirical1, double empirical2, double sx, double sy) { HumdrumFile& score = *this; int start = 0; int stop = score.getNumLines() - 1; while (start < score.getNumLines()-1 && score[start].getAbsBeat() < startbeat) { start++; } while (stop > 0 && score[stop].getAbsBeat() > stopbeat) { stop--; } return -1; // return analyzeChordProbabilityDurNorm(coef, start, stop, scorelevels, // empirical1, empirical2, sx, sy); } ////////////////////////////// // // HumdrumFile::analyzeChordProbabilityDur -- gives start and stop // points in terms of absolute beats. // int HumdrumFile::analyzeChordProbabilityDur(Array& coef, double startbeat, double stopbeat, Array& scorelevels, double empirical1, double empirical2, double sx, double sy) { HumdrumFile& score = *this; int start = 0; int stop = score.getNumLines() - 1; while (start < score.getNumLines()-1 && score[start].getAbsBeat() < startbeat) { if (fabs(score[start].getAbsBeat() - startbeat) < 0.001) { break; } start++; } while (stop > 0 && score[stop].getAbsBeat() > stopbeat) { if (fabs(score[stop].getAbsBeat() - stopbeat) < 0.001) { break; } stop--; } // if subdividing a rhythm: if (stop < start) { start = stop; } // cout << "Start line: " << start+1 << "\tEnd line: " << stop+1 << endl; return analyzeChordProbability(coef, start, stop, scorelevels, empirical1, empirical2, sx, sy); } ////////////////////////////// // // HumdrumFile::analyzeChordProbability -- analyze a set of notes in // the score for the most likely chord that fits those notes // using Craig's thirds-space plus rhythmic information algorithm. // returns the Base-40 pitch class number of the most likely chord // possibility. The coef array size is set to 40 and the chord scorings // for each root are generated in the function. // // Default value: empirical1 = -3.0 // Default value: empirical2 = -3.0 // int HumdrumFile::analyzeChordProbability(Array& coef, int start, int stop, Array& scorelevels, double empirical1, double empirical2, double sx, double sy) { int vectorx[40] = { 0, // Cn 0 7, // Cs 1 7, // Css 2 1000, // x 3 4, // Dff 4 4, // Df 5 4, // Dn 6 4, // Ds 7 4, // Dss 8 1000, // x 9 8, // Eff 10 1, // Ef 11 1, // En 12 8, // Es 13 8, // Ess 14 5, // Fff 15 5, // Ff 16 5, // Fn 17 5, // Fs 18 5, // Fss 19 1000, // x 20 9, // Gff 21 2, // Gf 22 2, // Gn 23 2, // Gs 24 9, // Gss 25 1000, // x 26 6, // Aff 27 6, // Af 28 6, // An 29 6, // As 30 6, // Ass 31 1000, // x 32 3, // Bff 33 3, // Bf 34 3, // Bn 35 3, // Bs 36 10, // Bss 37 7, // Cff 38 7 // Cf 39 }; int vectory[40] = { 0, // Cn 0 -2, // Cs 1 -4, // Css 2 1000, // x 3 4, // Dff 4 2, // Df 5 0, // Dn 6 -2, // Ds 7 -4, // Dss 8 1000, // x 9 3, // Eff 10 1, // Ef 11 1, // En 12 -3, // Es 13 -5, // Ess 14 5, // Fff 15 3, // Ff 16 1, // Fn 17 -1, // Fs 18 -3, // Fss 19 1000, // x 20 4, // Gff 21 2, // Gf 22 0, // Gn 23 -2, // Gs 24 -4, // Gss 25 1000, // x 26 4, // Aff 27 2, // Af 28 0, // An 29 -2, // As 30 -4, // Ass 31 1000, // x 32 3, // Bff 33 1, // Bf 34 -1, // Bn 35 -3, // Bs 36 -5, // Bss 37 4, // Cff 38 2 // Cf 39 }; HumdrumFile& score = *this; if (scorelevels.getSize() != score.getNumLines()) { scorelevels.setSize(0); score.analyzeMetricLevel(scorelevels); } Array pitches; Array durs; Array levels; int linecount = stop - start + 1; pitches.setSize(linecount * 32); durs.setSize(linecount * 32); levels.setSize(linecount * 32); pitches.setSize(0); durs.setSize(0); levels.setSize(0); pitches.allowGrowth(); durs.allowGrowth(); levels.allowGrowth(); double pitch; double duration; double level; char buffer[128] = {0}; int i, ii; // line index int j, jj; // spine index int k; // chord note index int ccount; // chord note count int firsttime = 1; // collect tied note from previous point in score // first build array of notes used to calculate the chord statistics for (i=start; i<=stop; i++) { if (score[i].getType() != E_humrec_data) { // ignore non-note data lines continue; } ii = i; for (j=0; j= 40) { cout << "Error in pitch " <