// // Programmer: Craig Stuart Sapp // Creation Date: Wed May 22 19:58:17 PDT 2002 // Last Modified: Wed May 22 19:58:22 PDT 2002 // Filename: ...sig/examples/all/tetra.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/tetra.cpp // Syntax: C++; museinfo // // Description: Identify melodic ascending/decending tetrachords in // each spine. // Repeated internal note in a tetrachord are not // considered as creating a tetrachord. // will only look at the first note of a chord. // #include "humdrum.h" #include #include #include ////////////////////////////////////////////////////////////////////////// class TetraUnit { public: TetraUnit(void) { clear(); }; void clear(void) { pitch = spine = line = type = direction = position = 0; }; int type; // M=major; R=minor; N=natural; H=harmonic int direction; // 1=ascending, -1=decending int position; // 1=first note of tetrachord, etc. int line; // line number in file for data. int spine; // spine to which analysis belongs. int pitch; // pitch for the particular note }; ostream& operator<<(ostream& out, TetraUnit& tetra) { if (tetra.direction == 1) { out << (char)tetra.type << tetra.position; } else { out << (char)tolower(tetra.type) << tetra.position; } return out; } typedef Array TetraArray; typedef Array ArrayTetraArray; typedef Array ArrayInt; ////////////////////////////////////////////////////////////////////////// // function declarations: void checkOptions (Options& opts, int argc, char** argv); void example (void); void usage (const char* command); void generateAnalysis (HumdrumFile& infile, Array& tetraAnalysis, Array& primaryTracks); void printAnalysis (HumdrumFile& infile, Array& tetraAnalysis, Array& primaryTracks); void getPitchArray (HumdrumFile& infile, Array& pitches, Array& lines, Array& spines, Array& primaryTracks); int convertTrackToIndex (int track, Array& primaryTracks); void findTetraChords (Array& tetras, Array& pitches, Array& lines, Array& spines); void identifyTetraChord (Array& tetras, Array& lines, Array& spines, int currline, Array& pitches, int note1, int note2, int note3, int note4); int intcompare (const void* a, const void* b); // User interface variables: Options options; int debugQ = 0; // used with --debug option int rawQ = 0; // used with -r option int binaryQ = 0; // used with -b option int appendQ = 0; // used with -a option int pitchQ = 0;; // used with -p option ////////////////////////////////////////////////////////////////////////// int main(int argc, char** argv) { // process the command-line options checkOptions(options, argc, argv); HumdrumFile infile; infile.read(options.getArg(1)); Array tetraAnalysis; Array primaryTracks; generateAnalysis(infile, tetraAnalysis, primaryTracks); printAnalysis(infile, tetraAnalysis, primaryTracks); return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // generateAnalysis -- // void generateAnalysis(HumdrumFile& infile, Array& tetraAnalysis, Array& primaryTracks) { Array pitches; Array lines; Array spines; getPitchArray(infile, pitches, lines, spines, primaryTracks); int i; int j; if (pitchQ) { for (i=0; i& tetras, Array& pitches, Array& lines, Array& spines) { int i; tetras.setSize(pitches.getSize()); for (i=0; i base12; base12.setSize(pitches.getSize()); for (i=0; i 0) { base12[i] = Convert::base40ToMidiNoteNumber(pitches[i]); } else { base12[i] = -1; // rest } } for (i=0; i& tetras, Array& lines, Array& spines, int currline, Array& pitches, int note1, int note2, int note3, int note4) { TetraUnit tetra; int n[4]; n[0] = note1; n[1] = note2; n[2] = note3; n[3] = note4; qsort(n, 4, sizeof(int), intcompare); // min to max must be a perfect fourth: if (n[3]-n[0] != 5) { return; } // no duplicate numbers allowed: if (n[1] == n[0] || n[2] == n[1] || n[3] == n[2]) { return; } int type = 'X'; if (n[1] - n[0] == 2 && n[2] - n[1] == 2) type = 'M'; else if (n[1] - n[0] == 2 && n[2] - n[1] == 1) type = 'R'; else if (n[1] - n[0] == 1 && n[2] - n[1] == 2) type = 'N'; else if (n[1] - n[0] == 1 && n[2] - n[1] == 3) type = 'H'; int mapping[4] = {0}; if (note1 == n[0]) mapping[0] = 1; else if (note1 == n[1]) mapping[0] = 2; else if (note1 == n[2]) mapping[0] = 3; else if (note1 == n[3]) mapping[0] = 4; if (note2 == n[0]) mapping[1] = 1; else if (note2 == n[1]) mapping[1] = 2; else if (note2 == n[2]) mapping[1] = 3; else if (note2 == n[3]) mapping[1] = 4; if (note3 == n[0]) mapping[2] = 1; else if (note3 == n[1]) mapping[2] = 2; else if (note3 == n[2]) mapping[2] = 3; else if (note3 == n[3]) mapping[2] = 4; if (note4 == n[0]) mapping[3] = 1; else if (note4 == n[1]) mapping[3] = 2; else if (note4 == n[2]) mapping[3] = 3; else if (note4 == n[3]) mapping[3] = 4; int direction = 0; if (mapping[0] < mapping[3]) { direction = +1; } else { direction = -1; } // type; // M=major; R=minor; N=natural; H=harmonic // direction; // 1=ascending, -1=decending // position; // 1=first note of tetrachord, etc. // line; // line number in file for data. // spine; // spine to which analysis belongs. // pitch; // pitch for the particular note int j; for (j=0; j<4; j++) { tetra.clear(); tetra.direction = direction; tetra.type = type; tetra.position = mapping[j]; tetra.line = lines[currline+j]; tetra.spine = spines[currline+j]; tetra.pitch = pitches[currline+j]; tetras[currline+j].append(tetra); } } ////////////////////////////// // // getPitchArray -- // void getPitchArray(HumdrumFile& infile, Array& pitches, Array& lines, Array& spines, Array& primaryTracks) { int index; int pitch; int track; primaryTracks.setSize(0); int i; int j; for (i=0; i& primaryTracks) { int output = -1; int i; for (i=0; i& tetraAnalysis, Array& primaryTracks) { int i; int j; int k; int count; int index; Array currentline; currentline.setSize(tetraAnalysis.getSize()); currentline.setAll(0); for (i=0; i= tetraAnalysis[index].getSize()) { count = 0; } else { count = tetraAnalysis[index][currentline[index]].getSize(); } if ((count > 0) && (tetraAnalysis[index][currentline[index]][0].line > i)) { cout << "."; } else if ((count > 0) && (tetraAnalysis[index][currentline[index]][0].line==i)){ if (binaryQ) { cout << "x"; } else { for (k=0; k currentline; currentline.setSize(tetraAnalysis.getSize()); currentlines.setAll(0); */ break; case E_humrec_none: case E_humrec_empty: case E_humrec_global_comment: case E_humrec_bibliography: default: cout << infile[i] << "\n"; break; } } /* for (i=0; i *((int*)b)) { return 1; } else { return 0; } } // md5sum: 20330de0941ed63052d95017938858f3 tetra.cpp [20160320]