// // Copyright 2002 by Craig Stuart Sapp, All Rights Reserved. // Programmer: Craig Stuart Sapp // Creation Date: Tue Dec 24 18:25:42 PST 2002 // Last Modified: Tue Dec 24 18:25:44 PST 2002 // Filename: ...sig/include/sigInfo/RootSpectrum.cpp // Web Address: http://sig.sapp.org/include/sigInfo/RootSpectrum.cpp // Syntax: C++ // // Description: Store and calculate chord root calculations. // #include "RootSpectrum.h" #include "PlotFigure.h" #include "Convert.h" #include #include #ifndef OLDCPP using namespace std; #endif ////////////////////////////// // // RootSpectrum::RootSpectrum -- // RootSpectrum::RootSpectrum(void) { values.setSize(40); values.allowGrowth(0); values.setAll(100000.0); power = 1.0; rhythmOn(); melodyOn(); rhythmLinear(); setMeterBias(3.0); setDurationBias(4.0); setMelodyScaleFactor(1.0); setResolutionFactor(1.0); setDurationWeight(0.25); setMetricLevelWeight(0.25); } ////////////////////////////// // // RootSpectrum::~RootSpectrum -- // RootSpectrum::~RootSpectrum() { values.setSize(0); } ////////////////////////////// // // RootSpectrum::bestIndex -- return the index // int RootSpectrum::bestIndex(void) { int output = 0; for (int i=1; i {labels, yaxis}, \n" " AspectRatio -> 1/2]\n" "]\n" "\n" "RootPlotContour[array_?ListQ, repeat_?IntegerQ:2, options___] := Module[\n" " {\n" " x, i, newarray, labels, longpitches = {},\n" " pitches = {\"C\", \"E\", \"G\", \"B\", \"D\", \"F\", \"A\"},\n" " yaxis = {{1,\"bb\"}, {2,\"b\"}, {3,\"nat.\"}, {4,\"#\"}, {5,\"##\"}}\n" " },\n" " labels = Table[x, {x, 1, 7 * repeat , 1}];\n" " For[i=0, i {labels, yaxis}, \n" " AspectRatio -> 1/2, Contours -> 12, \n" " DefaultFont -> {\"Times-Roman\", 14}, PlotRange -> All]\n" "]\n" "\n" "(* Display root spectra in 3-D: \n" " * Show[SurfaceGraphics[rspec" << label << "], ViewPoint -> {1, 0, 0}];\n" " *)\n"; } out.setf(ios::fixed); out << "\nrspec" << label << " = {\n"; out << "\t\t{"; // C if (normQ) { out << getNormInvScore(38) << "," << getNormInvScore(39) << "," << getNormInvScore(0) << "," << getNormInvScore(1) << "," << getNormInvScore(2) << "}, (* C *)\n" << "\t\t{" // E << getNormInvScore(10) << "," << getNormInvScore(11) << "," << getNormInvScore(12) << "," << getNormInvScore(13) << "," << getNormInvScore(14) << "}, (* E *)\n" << "\t\t{"; // G out << getNormInvScore(21) << "," << getNormInvScore(22) << ","; out << getNormInvScore(23) << "," << getNormInvScore(24) << ","; out << getNormInvScore(25) << "}, (* G *)\n"; out << "\t\t{"; // B out << getNormInvScore(33) << "," << getNormInvScore(34) << ","; out << getNormInvScore(35) << "," << getNormInvScore(36) << ","; out << getNormInvScore(37) << "}, (* B *)\n"; out << "\t\t{"; // D out << getNormInvScore(4) << "," << getNormInvScore(5) << ","; out << getNormInvScore(6) << "," << getNormInvScore(7) << ","; out << getNormInvScore(8) << "}, (* D *)\n"; out << "\t\t{"; // F out << getNormInvScore(15) << "," << getNormInvScore(16) << ","; out << getNormInvScore(17) << "," << getNormInvScore(18) << ","; out << getNormInvScore(19) << "}, (* F *)\n"; out << "\t\t{"; // A out << getNormInvScore(27) << "," << getNormInvScore(28) << ","; out << getNormInvScore(29) << "," << getNormInvScore(30) << ","; out << getNormInvScore(31) << "}}; (* A *)\n"; out << endl; } else { out << getInvScore(38) << "," << getInvScore(39) << ","; out << getInvScore(0) << "," << getInvScore(1) << ","; out << getInvScore(2) << "}, (* C *)\n"; out << "\t\t{"; // E out << getInvScore(10) << "," << getInvScore(11) << ","; out << getInvScore(12) << "," << getInvScore(13) << ","; out << getInvScore(14) << "}, (* E *)\n"; out << "\t\t{"; // G out << getInvScore(21) << "," << getInvScore(22) << ","; out << getInvScore(23) << "," << getInvScore(24) << ","; out << getInvScore(25) << "}, (* G *)\n"; out << "\t\t{"; // B out << getInvScore(33) << "," << getInvScore(34) << ","; out << getInvScore(35) << "," << getInvScore(36) << ","; out << getInvScore(37) << "}, (* B *)\n"; out << "\t\t{"; // D out << getInvScore(4) << "," << getInvScore(5) << ","; out << getInvScore(6) << "," << getInvScore(7) << ","; out << getInvScore(8) << "}, (* D *)\n"; out << "\t\t{"; // F out << getInvScore(15) << "," << getInvScore(16) << ","; out << getInvScore(17) << "," << getInvScore(18) << ","; out << getInvScore(19) << "}, (* F *)\n"; out << "\t\t{"; // A out << getInvScore(27) << "," << getInvScore(28) << ","; out << getInvScore(29) << "," << getInvScore(30) << ","; out << getInvScore(31) << "}}; (* A *)\n"; out << endl; } return out; } ////////////////////////////// // // RootSpectrum::printHumdrum -- // default value out = cout, type = DISPLAY_DIATONIC, invQ = 1, normQ = 0 // ostream& RootSpectrum::printHumdrum(ostream& out, int type, int invQ, int normQ) { int i; double value = 0.0; int findex; char buffer[64] = {0}; Array bestorder; getBestOrdering(bestorder); if (durationQ) { out << "!! duration weighting: " << getDurationWeight() << "\n"; } if (levelQ) { out << "!! metric weighting: " << getMetricLevelWeight() << "\n"; } out << "**kern\t**rootscore\n"; for (i=0; i<40; i++) { switch (type) { case DISPLAY_CHROMATIC: findex = (15 + i * 23) % 40; break; case DISPLAY_BEST: findex = bestorder[i]; break; case DISPLAY_DIATONIC: default: findex = (i-2+40)%40; } Convert::base40ToKern(buffer, (findex+2)%40+4*40); if (buffer[0] == '\0') { continue; } if (normQ && invQ) { value = getNormInvScore(findex); } else if (invQ) { value = getInvScore(findex); } else { value = values[findex]; } if (value > 0.0001) { out << buffer << "\t" << value << "\n"; } else { out.setf(ios::fixed); out << buffer << "\t" << value << "\n"; out.unsetf(ios::fixed); } } out << "*-\t*-\n"; return out; } ////////////////////////////// // // RootSpectrum::getBestOrdering -- returns the ordering // of the root scores from best to worst. // class _index_value { public: double value; int index; }; void RootSpectrum::getBestOrdering(Array& bestordering) { Array<_index_value> iv(40); int i; for (i=0; i B.value) { return +1; } else { return 0; } } ////////////////////////////// // // RootSpectrum::printXfig -- print spectrum in xfig format // default value: out = cout, type = 0 (diatonic) // title: "Root Spectrum" 1 (by fifths) // 2 (best first) // ostream& RootSpectrum::printXfig(ostream& out, const char* title, int type) { PlotFigure figure; PlotData data; figure.allocatePoints(40); int i; double yvalue; double angle = 90.0 * 3.14159624/180.0; double max = getInvScore(bestIndex()); double pointsize = 0.007 * max; int justify = -1; // left Array bestorder; getBestOrdering(bestorder); int count = 0; double fontsize = 14.0; char buffer[64] = {0}; int nextindex = -1; int lastindex = -1; int findex = -1; for (i=0; i<40; i++) { lastindex = findex; switch (type) { case DISPLAY_CHROMATIC: findex = (15 + i * 23) % 40; if (i+1<40) { nextindex = (15 + (i+1) * 23) % 40; } else { nextindex = -1; } break; case DISPLAY_BEST: findex = bestorder[i]; if (i+1 < 40) { nextindex = bestorder[i+1]; } else { nextindex = -1; } break; case DISPLAY_DIATONIC: default: findex = (i-2+40)%40; if (i+1<40) { nextindex = (i+1-2+40)%40; } else { nextindex = -1; } } Convert::base40ToKern(buffer, ((findex+2)%40) + 4*40); if (buffer[0] == '\0') { continue; } yvalue = getInvScore(findex); figure.addText(buffer, count+0.2, -0.080 * max, fontsize, angle, justify); if (i > 0 && i < 39 && lastindex >=0 && lastindex < 40 && nextindex >= 0 && nextindex < 40) { if (type == DISPLAY_CHROMATIC && (strcmp(buffer, "b##") == 0)) { // do not display B## as a peak } else if ((values[findex] < values[lastindex]) && (values[findex] < values[nextindex]) ) { figure.addText(buffer, count, 0.02 * max + yvalue, fontsize - fontsize/8.0, 0, 0); } } figure.addPoint(count, yvalue, pointsize); data.addPoint(count, yvalue); count++; } figure.setYMin(0.0); figure.setXRangeAutoOff(); figure.setXMin(-0.5); figure.setXMax(34.5); figure.addPlot(data); figure.setYLabel("Inverse Score"); figure.setXLabel("Root Pitch"); figure.setTitle(title); figure.yTicksOn(); figure.setYTicksDelta(0.1); return figure.printXfig(out); } ////////////////////////////// // // RootSpectrum::printPlot -- print spectrum in pre xfig plot format // default value: out = cout, type = DISPLAY_DIATONIC // ostream& RootSpectrum::printPlot(ostream& out, int type) { // not implemented yet, just output xfig code instead return printXfig(out); } ///////////////////////////////////////////////////////////////////////////// // // Analysis Functions // ////////////////////////////// // // RootSpectrum::calculate -- returns the best root found for chord data. // default value: debugQ = 0 // int RootSpectrum::calculate(IntervalWeight& distances, HumdrumFile& infile, int startline, int stopline, int debugQ) { int i; int j; Array& rootscores = values; double chordstartbeat = infile[startline].getAbsBeat(); double chordendbeat = infile[stopline].getAbsBeat(); // extract note data Array absbeat; Array pitches; Array durations; Array levels; Array > lastpitches; // pitches which approach note Array > nextpitches; // pitches which leave note char buffer[64] = {0}; if (!melodyQ) { infile.getNoteArray(absbeat, pitches, durations, levels, startline, stopline); if (debugQ) { cout << "!! Note information from line " << startline + 1 << " to line " << stopline + 1 << "\n" << "!! **dur = duration of the note in quarter note units.\n" << "!! **absbeat = absolute beat position of note from start (beat 0)\n" << "!! **level = metric level of the note on linear scale\n"; cout << "**kern\t**dur\t**level\t**absbeat\n"; for (i=0; i& lastpitches, Array& nextpitches, IntervalWeight& distances, double absbeat, double chordstartbeat, double chordendbeat, double duration) { if (!melodyQ) { return 1.0; } double scalefactor = getMelodyScaleFactor(); if (lastpitches.getSize() == 0 && nextpitches.getSize() == 0) { // check to see if the note is non-harmonic with respect to root if (nonchordtoneQ(root, note)) { return nonresolutionscaling; } else { return 1.0; } } int i; int testchordn; int testnonharmn; // check to see if there is a non-harmonic candidate in lastpitches. for (i=0; i chordendbeat)) { return 1; } else { return 0; } } ////////////////////////////// // // RootSpectrum::durationLinear -- set the duration calculation // to be linear. // void RootSpectrum::durationLinear(void) { durlinear = 1; } ////////////////////////////// // // RootSpectrum::durationLog -- set the duration calculation // to be logarithmic. // void RootSpectrum::durationLog(void) { durlinear = 0; } ////////////////////////////// // // RootSpectrum::meterLinear -- set the metric calculation // to be linear. // void RootSpectrum::meterLinear(void) { metlinear = 1; } ////////////////////////////// // // RootSpectrum::meterLog -- set the metric calculation // to be linear. // void RootSpectrum::meterLog(void) { metlinear = 0; } ////////////////////////////// // // RootSpectrum::rhythmLinear -- set the rhythmic calculations // to be linear. // void RootSpectrum::rhythmLinear(void) { durationLinear(); meterLinear(); } ////////////////////////////// // // RootSpectrum::rhythmLog -- set the rhythmic calculations // to be logarithmic. // void RootSpectrum::rhythmLog(void) { durationLog(); meterLog(); } ////////////////////////////// // // RootSpectrum::setMeterBias -- set the bias for metric log calculations // void RootSpectrum::setMeterBias(double aBias) { meterBias = aBias; } ////////////////////////////// // // RootSpectrum::setDurationBias -- set the bias for duration log calculations // void RootSpectrum::setDurationBias(double aBias) { durationBias = aBias; } ////////////////////////////// // // RootSpectrum::getDurationBias -- get the current logarithmic // duration bias. // double RootSpectrum::getDurationBias(void) { return durationBias; } ////////////////////////////// // // RootSpectrum::getMeterBias -- get the current logarithmic // meter bias. // double RootSpectrum::getMeterBias(void) { return meterBias; } ////////////////////////////// // // RootSpectrum::durationscaling -- scaling factor for duration of note. // double RootSpectrum::durationscaling(double duration) { if (durationQ == 0) { return 1.0; } if (durlinear) { return pow(duration, getDurationWeight()); } else { return durationBias + log(duration); } } ////////////////////////////// // // RootSpectrum::metricscaling -- scaling factor for metric level of note. // double RootSpectrum::metricscaling(double level) { if (levelQ == 0) { return 1.0; } if (metlinear) { return pow(level, getMetricLevelWeight()); } else { return meterBias + log(level); } } ////////////////////////////// // // RootSpectrum::setResolutionFactor -- set the scaling factor for notes // which appear to be non-harmonic tones for a given root, but which // do not resolve to a chord-tone. // void RootSpectrum::setResolutionFactor(double aFactor) { nonresolutionscaling = aFactor; } ////////////////////////////// // // RootSpectrum::getResolutionFactor -- // double RootSpectrum::getResolutionFactor(void) { return nonresolutionscaling; } // md5sum: 4fdb177212e4320f83b3e2f5b8bf9a2f RootSpectrum.cpp [20050403]