// // Programmer: Craig Stuart Sapp // Creation Date: Thu Apr 11 11:43:12 PDT 2002 // Last Modified: Fri Jun 12 22:58:34 PDT 2009 renamed SigCollection class // Last Modified: Mon Feb 21 08:29:14 PST 2011 added --match // Last Modified: Sun Feb 27 15:09:29 PST 2011 added fixed vocal colors // Filename: ...sig/examples/all/proll.cpp // Web Address: http://sig.sapp.org/examples/museinfo/humdrum/proll.cpp // Syntax: C++; museinfo // // Description: Generate piano roll plots. // #include "humdrum.h" #include "PerlRegularExpression.h" #include #include typedef SigCollection PixelRow; // function declarations void checkOptions (Options& opts, int argc, char* argv[]); void example (void); void usage (const char* command); void generateBackground (HumdrumFile& infile, int rfactor, Array& picturedata, Array& background); int generatePicture (HumdrumFile& infile, Array& picture, int style); void printPicture (Array& picturedata, Array& background, int rfactor, int cfactor, int minp, int maxp, HumdrumFile& infile); void placeNote (Array& picture, int pitch, double start, double duration, int min, PixelColor& color, double factor, int match); PixelColor makeColor (HumdrumFile& infile, int line, int spine, int style, Array& rhylev, int track); void getMarkChars (Array& marks, HumdrumFile& infile); int isMatch (Array& marks, const char* buffer); const char* getInstrument (HumdrumFile& infile, int spine); // global variables Options options; // database for command-line arguments int debugQ = 0; // used with --debug option int markQ = 0; // used with --mark option int maxwidth = 3000; // used with -w option int maxheight = 400; // used with -h option int rfactor = 1; int cfactor = 1; int gminpitch = 0; int gmaxpitch = 127; int maxfactor = 5; int measureQ = 1; // used with the -M option int keyboardQ = 1; // used with the -K option int style = 'H'; // used with the -s option const char* keyboardcolor = "151515"; // used with the -k option /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { checkOptions(options, argc, argv); Array picturedata; Array background; HumdrumFile infile; int numinputs = options.getArgCount(); if (numinputs > 0) { char* filenameIn = options.getArg(1); infile.read(filenameIn); } else { infile.read(cin); } int rfactor = generatePicture(infile, picturedata, style); generateBackground(infile, rfactor, picturedata, background); printPicture(picturedata, background, rfactor, cfactor, gminpitch, gmaxpitch, infile); return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // printPicture -- // void printPicture(Array& picturedata, Array& background, int rfactor, int cfactor, int minp, int maxp, HumdrumFile& infile) { if (minp > 0) { minp--; } if (maxp < 127) { maxp++; } int i, j; int m; int width = picturedata[0].getSize(); int height = (maxp - minp + 1); cfactor = (int)(maxheight / height); if (cfactor <= 0) { cfactor = 1; } if (cfactor > maxfactor) { cfactor = maxfactor; } PixelColor temp; PixelColor black(0,0,0); height = cfactor * height; cout << "P6\n" << width << " " << height << "\n255\n"; for (i=maxp; i>=minp; i--) { for (m=0; m 0) && (cfactor > 1) && (m == cfactor-1) && (picturedata[i-1][j] == picturedata[i][j])) { temp = picturedata[i][j] * 0.667; temp.writePpm6(cout); } else { picturedata[i][j].writePpm6(cout); } } } } } } ////////////////////////////// // // generatePicture -- create the picture. Returns the number of // pixel repetitions for each row's pixel. // int generatePicture(HumdrumFile& infile, Array& picture, int style) { Array marks; getMarkChars(marks, infile); PixelColor matchcolor(255,255,255); infile.analyzeRhythm("4"); int min = infile.getMinTimeBase(); double totaldur = infile.getTotalDuration(); int columns = (int)(totaldur * min / 4.0 + 0.5) + 5; if (columns > 50000) { cout << "Error: picture will be too big to generate" << endl; exit(1); } int factor = (int)(maxwidth / columns); if (factor <= 0) { factor = 1; } if (factor > maxfactor) { factor = maxfactor; } // set picture to black first. Black regions will be filled in // with the background later. picture.setSize(128); int i, j, k; for (i=0; irhylev; infile.analyzeMetricLevel(rhylev); for (i=0; i maxpitch) { maxpitch = pitch; } if (isMatch(marks, buffer)) { placeNote(picture, pitch, start, duration, min, color, factor, 1); } else { placeNote(picture, pitch, start, duration, min, color, factor, 0); } } } } } gmaxpitch = maxpitch; gminpitch = minpitch; return factor; } ////////////////////////////// // // isMatch -- returns true if the string has a match character in it // int isMatch(Array& marks, const char* buffer) { int i; for (i=0; i& rhylev, int track) { PixelColor output; int trackCount; PerlRegularExpression pre; const char* instrument = ""; PixelColor purple (225, 121, 255); PixelColor yellowgreen(150, 200, 0); switch (toupper(style)) { case 'M': // color by metric position if (rhylev[line] >= 2) { output.setColor("red"); } else if (rhylev[line] == 1) { output.setColor("lightorange"); } else if (rhylev[line] == 0) { output.setColor("yellow"); } else if (rhylev[line] == -1) { output.setColor("green"); } else if (rhylev[line] == -2) { output.setColor("blue"); } else if (rhylev[line] <= -3) { output.setColor("violet"); } else { output.setColor("silver"); } break; case 'V': // color spines by voice instrument = getInstrument(infile, track); if (pre.search(instrument, "Bassus", "i")) { output.setColor("red"); } else if (pre.search(instrument, "Contra", "i")) { output.setColor("darkorange"); } else if (pre.search(instrument, "Tenor", "i")) { output.setColor("blue"); } else if (pre.search(instrument, "Altus", "i")) { output = purple; } else if (pre.search(instrument, "Superius", "i")) { output.setColor("limegreen"); } else if (pre.search(instrument, "Discantus", "i")) { output = yellowgreen; } else { output.setColor("black"); } break; case 'H': // color spines by hue default: trackCount = infile.getMaxTracks(); output.setHue(((int)infile[line].getTrack(spine))/(double)trackCount); } return output; } ////////////////////////////// // // getInstrument -- // const char* getInstrument(HumdrumFile& infile, int track) { int i, j; for (i=0; i& picture, int pitch, double start, double duration, int min, PixelColor& color, double factor, int match) { int startindex = (int)(start * min / 4.0 * factor); int endindex = (int)((start + duration) * min / 4.0 * factor) - 1; PixelColor zcolor = color; if (match) { zcolor.Red = (zcolor.Red + 4*255)/5; zcolor.Green = (zcolor.Green + 4*255)/5; zcolor.Blue = (zcolor.Blue + 4*255)/5; } PixelColor black(0,0,0); if (startindex-1 >= 0) { if (picture[pitch][startindex-1] == color) { picture[pitch][startindex-1] *= 0.667; } } for (int i=startindex; i<=endindex; i++) { if (picture[pitch][i] == black) { picture[pitch][i] = zcolor; } else { if (match) { picture[pitch][i].Red = (2*zcolor.Red + picture[pitch][i].Red)/3; picture[pitch][i].Green = (2*zcolor.Green + picture[pitch][i].Green)/3; picture[pitch][i].Blue = (2*zcolor.Blue + picture[pitch][i].Blue)/3; } else { picture[pitch][i].Red = (color.Red + picture[pitch][i].Red)/2; picture[pitch][i].Green = (color.Green + picture[pitch][i].Green)/2; picture[pitch][i].Blue = (color.Blue + picture[pitch][i].Blue)/2; } } } } ////////////////////////////// // // generateBackground -- create the picture. // void generateBackground(HumdrumFile& infile, int rfactor, Array& picturedata, Array& background) { background.setSize(picturedata.getSize()); int i, j; for (i=0; i& marks, HumdrumFile& infile) { PerlRegularExpression pre; Array& colorchar = marks; colorchar.setSize(0); char value; int i; for (i=0; i