//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Mon Mar 23 12:48:50 PST 2009
// Last Modified: Tue Mar 24 18:57:09 PST 2009
// Last Modified: Mon Sep 3 09:27:57 PDT 2012 Copied from noteheadtime.cpp
// Filename: ...sig/examples/all/noteheadtime-webern.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/noteheadtime-webern.cpp
// Syntax: C++; museinfo
//
// Description: print performance data as noteheads outputting SCORE data.
//
//
#include <math.h>
#include "humdrum.h"
#include "ScorePageBase.h"
#include "PerlRegularExpression.h"
#ifndef OLDCPP
#include <iostream>
#else
#include <iostream.h>
#endif
// function declarations:
void checkOptions(Options& opts, int argc, char** argv);
void example(void);
void usage(const char* command);
void processInput(ScorePageBase& scorepage, HumdrumFile& infile,
SigCollection<HumdrumFile>& marksfiles);
void printPage(ScorePageBase& scorepage, int page, double maxtime,
double mintime, Array<double>& times,
Array<double>& dyns, Array<int>& pitches,
Array<int>& pstaff, Array<int>& measures,
SigCollection<HumdrumFile>& marks);
void printSystem(ScorePageBase& scorepage, int basestaff,
Array<double>& times, Array<double>& dyns,
Array<int>& pitches, Array<int>& pstaff,
Array<int>& measures, double minsystime,
double maxsystime, int finalBarlineQ);
void normalizeDyns(Array<double>& dyns, double maxdyn,
double mindyn);
void getPitchInfo(const char* string, int& p1, int& p2);
void getBetterPitchInfo(const char* string, int& p1, int& p2,
int auxdata);
double printTicks(ScorePageBase& scorepage, int staff, int vpos,
int direction, double starttime,
double stoptime, double leftmar,
double rightmar, double majdur,
int secticks, int terticks,
double majticklen, double secticklen,
double terticklen);
void drawtick(ScorePageBase& scorepage, int staff, double hpos,
double vpos, int direction, double len);
void printMarks(ScorePageBase& scorepage, int basestaff,
Array<double>& marktimes,
Array<int>& markmeter, double starttime,
double stoptime, double leftmar,
double rightmar, double markcolor,
double markdashsize, double markspacesize,
double markstyle, double markthick);
void printPreMarks(ScorePageBase& scorepage, int basestaff,
Array<double>& marktimes,
Array<int>& markmeter, double starttime,
double stoptime, double leftmar,
double rightmar, double markcolor,
double markdashsize, double markspacesize,
double markstyle, double markthick);
void getMarkInfo(HumdrumFile& marks, Array<double>& marktimes,
Array<int>& markmeter);
void printTitle(ScorePageBase& scorepage, int basestaff,
HumdrumFile& infile);
void printFooter(ScorePageBase& scorepage, int basestaff,
HumdrumFile& infile, double footerscale);
void printComment(ScorePageBase& scorepage, int basestaff,
const char* string, double hpos, double scale);
char* createHexColor(char* hexcolor, double value);
// User interface variables:
Options options;
int verboseQ = 0;
double timewidth = 5.0;
int systemsperpage = 6;
int page = 1;
int pagecountQ = 0;
int systemZ = 1;
int systemQ = 0;
int systemcountQ = 0;
int svgQ = 1;
double staffscale = 0.75;
double leftmargin = 10;
double rightmargin = 195;
double quietnote = 0.9;
double loudnote = 0.0;
int scorever = 6; // 6 = winscore and p26val used for color
const char* ofile = "";
// timeline variables
int tickDisplayQ = 1;
double majortickdur = 1.0;
int secondaryticks = 2;
int tertiaryticks = 10;
double majorticklen = 1.5;
double secticklen = 1.0;
double terticklen = 0.5;
#define STYLE_LEFT 1
int ticklabelstyle = STYLE_LEFT;
int printstartmeasureQ = 1;
// additional information for correct pitch spelling
int auxQ = 0;
const char* auxfile = "";
int accidentalQ = 0; // used with --accidental option
// marks options
const char* marksfile = "";
double markdashsize = 0.0;
double markspacesize = 0.0;
//double markstyle = 7.0; // dashed line
double markstyle = 0.0; // solid line
int marksonlyQ = 0;
double markcolor = 997777; // red by default
double markthick = 7.0;
// secondary marks options
const char* marksfile2 = "";
double markdashsize2 = 0.0;
double markspacesize2 = 0.0;
//double markstyle2 = 7.0; // dashed line
double markstyle2 = 0.0; // solid line
double markcolor2 = 777799; // blue by default
double markthick2 = 0.0;
// tertiary marks options
const char* marksfile3 = "";
double markdashsize3 = 0.0;
double markspacesize3 = 0.0;
double markstyle3 = 7.0; // dashed line
double markcolor3 = 779977; // green by default
double markthick3 = 4.5;
// title printing on first page, and footers for rest of pages
int titleQ = 1;
int footerQ = 1;
// display of timing numbers
int notenumbersQ = 0;
double notenumbercolor = -1;
double notenumbersize = 1.0;
// comment string for bottom right of page
const char* commentstring = ""; // used with --comment
double commenthpos = 180.0; // used with --cp
//////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
// process the command-line options
checkOptions(options, argc, argv);
HumdrumFile infile;
if (options.getArgCount() < 1) {
infile.read(cin);
} else {
infile.read(options.getArg(1));
}
SigCollection<HumdrumFile> marks;
marks.setSize(1);
if (strcmp(marksfile, "") != 0) {
marks[0].read(marksfile);
}
if (strcmp(marksfile2, "") != 0) {
marks.setSize(2);
marks[1].read(marksfile2);
}
if (strcmp(marksfile3, "") != 0) {
marks.setSize(3);
marks[2].read(marksfile3);
}
ScorePageBase scorepage;
processInput(scorepage, infile, marks);
if (options.getBoolean("output")) {
scorepage.writeBinary(ofile);
} else {
scorepage.printAscii(cout);
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// processInput --
//
void processInput(ScorePageBase& scorepage, HumdrumFile& infile,
SigCollection<HumdrumFile>& marks) {
Array<double> times;
times.setSize(infile.getNumLines());
times.setSize(0);
Array<double> dyns;
dyns.setSize(infile.getNumLines());
dyns.setSize(0);
Array<int> pitches;
pitches.setSize(infile.getNumLines());
pitches.setSize(0);
Array<int> pstaff;
pstaff.setSize(infile.getNumLines());
pstaff.setSize(0);
Array<int> measures;
measures.setSize(infile.getNumLines());
measures.setSize(0);
double mintime = 10000000;
double maxtime = -10000000;
double mindyn = 10000000;
double maxdyn = -10000000;
int i;
double value;
int intvalue;
int p1, p2;
Array<int> auxacci;
auxacci.setSize(0);
int pindex = 0;
if (auxQ) {
HumdrumFile auxhum;
auxhum.read(auxfile);
auxacci.setSize(auxhum.getNumLines());
auxacci.setSize(0);
for (i=0; i<auxhum.getNumLines(); i++) {
if (auxhum[i].getType() != E_humrec_data) {
continue;
}
// 8th column must be extra accidental information (saccid)
sscanf(auxhum[i][7], "%d", &intvalue);
auxacci.append(intvalue);
}
}
for (i=0; i<infile.getNumLines(); i++) {
switch(infile[i].getType()) {
case E_humrec_data:
value = 0;
sscanf(infile[i][0], "%lf", &value);
if (value < mintime) {
mintime = value;
}
if (value > maxtime) {
maxtime = value;
}
times.append(value);
value = 0;
sscanf(infile[i][1], "%lf", &value);
if (value < mindyn) {
mindyn = value;
}
if (value > maxdyn) {
maxdyn = value;
}
dyns.append(value);
value = 0;
if (auxQ) {
getBetterPitchInfo(infile[i][2], p1, p2, auxacci[pindex++]);
} else {
getPitchInfo(infile[i][2], p1, p2);
}
pitches.append(p1);
pstaff.append(p2);
sscanf(infile[i][4], "%d", &intvalue);
measures.append(intvalue);
break;
case E_humrec_none:
case E_humrec_empty:
case E_humrec_global_comment:
case E_humrec_bibliography:
case E_humrec_data_comment:
case E_humrec_data_kern_measure:
case E_humrec_interpretation:
default:
break;
}
}
if (auxQ && (times.getSize() != auxacci.getSize())) {
// something went wrong: number of notes in primary
// and auxiliary file do not match, so throw away
// any auxiliary data since it will be invalid.
auxQ = 0;
auxacci.setSize(0);
cerr << "ERROR IN AUXILIARY FILE. GIVING UP" << endl;
exit(1);
}
times.allowGrowth(0);
dyns.allowGrowth(0);
normalizeDyns(dyns, maxdyn, mindyn);
int systems = int((maxtime - mintime) / timewidth + 0.99999);
if (systemQ) {
systemsperpage = 1;
page = systemZ;
}
int pages = int((double)systems / systemsperpage + 0.99999);
if (systems > 1000) {
// reduce page count if time is in milliseconds
maxtime = maxtime / 1000.0;
mintime = mintime / 1000.0;
for (i=0; i<times.getSize(); i++) {
times[i] = times[i] / 1000.0;
}
systems = int((maxtime - mintime) / timewidth + 0.99999);
pages = int((double)systems / systemsperpage + 0.99999);
}
if (verboseQ) {
cout << "@@Mintime: " << mintime << endl;
cout << "@@Maxtime: " << maxtime << endl;
cout << "@@Systems: " << systems << endl;
cout << "@@Pages: " << pages << endl;
cout << "@@PageToPrint: " << page << endl;
}
if (pagecountQ) {
cout << pages << endl;
exit(0);
} else if (systemcountQ) {
cout << systems << endl;
exit(0);
} else {
if ((page == 1) && titleQ) {
printTitle(scorepage, systemsperpage*2, infile);
}
if ((page > 1) && footerQ) {
double footerscale = 0.75;
if (page == pages) {
if (systems % systemsperpage != 0) {
// have to shrink footer if there is no
// staff present at the bottom of the page:
footerscale *= staffscale;
}
}
printFooter(scorepage, 1, infile, footerscale);
}
if (strcmp(commentstring, "") != 0) {
double footerscale = 0.75;
if (page == pages) {
if (systems % systemsperpage != 0) {
// have to shrink footer if there is no
// staff present at the bottom of the page:
footerscale *= staffscale;
}
}
printComment(scorepage, 1, commentstring, commenthpos, footerscale);
}
printPage(scorepage, page, maxtime, mintime, times,
dyns, pitches, pstaff, measures, marks);
}
}
//////////////////////////////
//
// printComment --
//
void printComment(ScorePageBase& scorepage, int basestaff, const char* comment,
double hpos, double scale) {
ScoreRecord srecord;
srecord.setPValue(1, P1_Text);
srecord.setPValue(2, basestaff);
srecord.setPValue(3, hpos);
srecord.setPValue(4, -8.0);
srecord.setPValue(6, scale);
srecord.setTextData(comment);
srecord.setTextFont("_00");
scorepage.addItem(srecord);
}
//////////////////////////////
//
// printFooter --
//
void printFooter(ScorePageBase& scorepage, int basestaff, HumdrumFile& infile,
double footerscale) {
char buffer[1024] = {0};
char buffer2[1024] = {0};
ScoreRecord srecord;
int i;
for (i=0; i<infile.getNumLines(); i++) {
if (!infile[i].isBibliographic()) {
continue;
}
infile[i].getBibKey(buffer);
if (strcmp(buffer, "performance-id") != 0) {
continue;
}
infile[i].getBibValue(buffer);
strcat(buffer, ", page");
sprintf(buffer2, "%d", page);
strcat(buffer, buffer2);
srecord.setPValue(1, P1_Text);
srecord.setPValue(2, basestaff);
srecord.setPValue(3, 0);
srecord.setPValue(4, -8.0);
srecord.setPValue(6, footerscale);
srecord.setTextData(buffer);
srecord.setTextFont("_00");
scorepage.addItem(srecord);
break;
}
}
//////////////////////////////
//
// printTitle --
//
void printTitle(ScorePageBase& scorepage, int basestaff, HumdrumFile& infile) {
int i;
char performer[1024] = {0};
char mazurkaname[1024] = {0};
char pidstring[1024] = {0};
char buffer[1024] = {0};
for (i=0; i<infile.getNumLines(); i++) {
if (!infile[i].isBibliographic()) {
continue;
}
infile[i].getBibKey(buffer);
if (strcmp(buffer, "performer") == 0) {
infile[i].getBibValue(performer);
} else if (strcmp(buffer, "title") == 0) {
infile[i].getBibValue(mazurkaname);
} else if (strcmp(buffer, "performance-id") == 0) {
infile[i].getBibValue(pidstring);
}
}
ScoreRecord srecord;
srecord.setPValue(1, P1_Text);
srecord.setPValue(2, basestaff);
srecord.setPValue(3, 10);
srecord.setTextFont("_00");
if (strcmp(performer, "") != 0) {
srecord.setPValue(4, 31);
srecord.setPValue(6, 1.377);
srecord.setTextData(performer);
scorepage.addItem(srecord);
}
if (strcmp(mazurkaname, "") != 0) {
srecord.setPValue(4, 25.5);
srecord.setPValue(6, 1.377);
srecord.setTextData(mazurkaname);
scorepage.addItem(srecord);
}
if (strcmp(pidstring, "") != 0) {
srecord.setPValue(4, 21);
srecord.setPValue(6, 0.00);
srecord.setTextData(pidstring);
scorepage.addItem(srecord);
}
}
//////////////////////////////
//
// getBetterPitchInfo --
// p1 = base-40 number for pitch
// p2 = who knows what that was for
//
void getBetterPitchInfo(const char* string, int& p1, int& p2, int auxdata) {
if (islower(string[0])) {
p2 = 1;
} else {
p2 = 0;
}
int diatonic = 0;
int accidental = 0;
int octave = 0;
char ch;
int length = strlen(string);
int i;
for (i=0; i<length; i++) {
ch = tolower(string[i]);
switch (ch) {
case 'c': diatonic = 2; break;
case 'd': diatonic = 8; break;
case 'e': diatonic = 14; break;
case 'f': diatonic = 19; break;
case 'g': diatonic = 25; break;
case 'a': diatonic = 31; break;
case 'b': diatonic = 37; break;
case '#': accidental++; break;
case '-': accidental--; break;
}
if (isdigit(ch)) {
sscanf(string+i, "%d", &octave);
break;
}
}
int base = diatonic + 400 + accidental;
base = base % 40;
p1 = base + octave * 40;
// new stuff
int newacci = auxdata;
newacci = newacci % 10; // remove higher order information
switch (newacci - accidental) {
case 0: return; // accidental is correctly encoded
case -2: // accidental is listed as # but should be -
p1 = p1 + 4; // on next higher diatonic note
break;
case +2: // accidental is listed as - but should be #
p1 = p1 - 4; // on next lower diatonic note
break;
case -1: // such as E should be F-flat
p1 = p1 + 4;
break;
case +1: // such as F should be E-sharp
p1 = p1 - 4;
break;
// deal with double sharp problems here later
}
}
//////////////////////////////
//
// getPitchInfo --
//
void getPitchInfo(const char* string, int& p1, int& p2) {
PerlRegularExpression pre;
if (!pre.search(string, "\\d")) {
p1 = Convert::kernToBase40(string);
if (p1 < 160) {
p2=0;
} else {
p2=1;
}
return;
}
if (islower(string[0])) {
p2 = 1;
} else {
p2 = 0;
}
int diatonic = 0;
int accidental = 0;
int octave = 0;
char ch;
int length = strlen(string);
int i;
for (i=0; i<length; i++) {
ch = tolower(string[i]);
switch (ch) {
case 'c': diatonic = 2; break;
case 'd': diatonic = 8; break;
case 'e': diatonic = 14; break;
case 'f': diatonic = 19; break;
case 'g': diatonic = 25; break;
case 'a': diatonic = 31; break;
case 'b': diatonic = 37; break;
case '#': accidental++; break;
case '-': accidental--; break;
}
if (isdigit(ch)) {
sscanf(string+i, "%d", &octave);
break;
}
}
int base = diatonic + 400 + accidental;
base = base % 40;
p1 = base + octave * 40;
}
//////////////////////////////
//
// normalizeDyns --
//
void normalizeDyns(Array& dyns, double maxdyn, double mindyn) {
int i;
double diff = maxdyn - mindyn;
for (i=0; i<dyns.getSize(); i++) {
dyns[i] = (dyns[i] - mindyn) / diff;
}
}
//////////////////////////////
//
// printPage --
//
void printPage(ScorePageBase& scorepage, int page, double maxtime, double mintime,
Array<double>& times, Array<double>& dyns, Array<int>& pitches,
Array<int>& pstaff, Array<int>& measures,
SigCollection<HumdrumFile>& marks) {
int systems = int((maxtime - mintime) / timewidth + 0.99999);
int pages = int((double)systems / systemsperpage + 0.99999);
if (page > pages || page < 0) {
exit(0);
}
if (page < pages) {
systems = systemsperpage;
} else {
systems = systems - systemsperpage * (pages-1);
}
int i;
Array<Array<double> > marktimes;
Array<Array<int> > markmeter;
int maxmarks = 10;
marktimes.setSize(maxmarks);
marktimes.allowGrowth(0);
markmeter.setSize(maxmarks);
markmeter.allowGrowth(0);
for (i=0; i<maxmarks; i++) {
marktimes[i].setSize(0);
markmeter[i].setSize(0);
}
for (i=0; (i<maxmarks) && (i<marks.getSize()); i++) {
getMarkInfo(marks[i], marktimes[i], markmeter[i]);
}
double minsystime;
double maxsystime;
int systembase = (page - 1) * systemsperpage;
int basestaff;
if ((page == 1) && (marktimes.getSize() > 0)) {
minsystime = mintime + systembase * timewidth;
maxsystime = minsystime + timewidth;
// print any marks before the start of the music
if (marktimes.getSize() > 0) {
if (marktimes[0].getSize() > 0) {
printPreMarks(scorepage, systemsperpage * 2 - 1, marktimes[0],
markmeter[0], minsystime, maxsystime, leftmargin,
rightmargin, markcolor, markdashsize, markspacesize,
markstyle, markthick);
}
}
if (marktimes.getSize() > 1) {
if (marktimes[1].getSize() > 0) {
printPreMarks(scorepage, systemsperpage * 2 - 1, marktimes[1],
markmeter[1], minsystime, maxsystime, leftmargin,
rightmargin, markcolor2, markdashsize2, markspacesize2,
markstyle2, markthick2);
}
}
if (marktimes.getSize() > 2) {
if (marktimes[2].getSize() > 0) {
printPreMarks(scorepage, systemsperpage * 2 - 1, marktimes[2],
markmeter[2], minsystime, maxsystime, leftmargin,
rightmargin, markcolor3, markdashsize3, markspacesize3,
markstyle3, markthick3);
}
}
}
int lastsystem = 0;
for (i=0; i<systems; i++) {
minsystime = mintime + (systembase + i) * timewidth;
maxsystime = minsystime + timewidth;
basestaff = (systemsperpage - i) * 2 - 1;
if ((i == systems-1) && (page == pages)) {
lastsystem = 1;
}
if (marktimes.getSize() > 0) {
if (marktimes[0].getSize() > 0) {
printMarks(scorepage, basestaff, marktimes[0], markmeter[0],
minsystime, maxsystime, leftmargin, rightmargin, markcolor,
markdashsize, markspacesize, markstyle, markthick);
}
}
if (marktimes.getSize() > 1) {
if (marktimes[1].getSize() > 0) {
printMarks(scorepage, basestaff, marktimes[1], markmeter[1],
minsystime, maxsystime, leftmargin, rightmargin, markcolor2,
markdashsize2, markspacesize2, markstyle2, markthick2);
}
}
if (marktimes.getSize() > 2) {
if (marktimes[2].getSize() > 0) {
printMarks(scorepage, basestaff, marktimes[2], markmeter[2],
minsystime, maxsystime, leftmargin, rightmargin, markcolor3,
markdashsize3, markspacesize3, markstyle3, markthick3);
}
}
if (!marksonlyQ) {
printSystem(scorepage, basestaff, times, dyns, pitches, pstaff,
measures, minsystime, maxsystime, lastsystem);
}
}
}
//////////////////////////////
//
// getMarkInfo --
//
void getMarkInfo(HumdrumFile& marks, Array<double>& marktimes,
Array<int>& markmeter) {
if (marks.getNumLines() <= 0) {
marktimes.setSize(0);
markmeter.setSize(0);
return;
}
marktimes.setSize(marks.getNumLines());
marktimes.setSize(0);
markmeter.setSize(marks.getNumLines());
markmeter.setSize(0);
double value;
int intval, intval2;
int i;
for (i=0; i<marks.getNumLines(); i++) {
if (marks.getType(i) == E_humrec_data) {
value = 0;
sscanf(marks[i][0], "%lf", &value);
marktimes.append(value);
if (marks[i].getFieldCount() > 1) {
intval = 0;
if (strchr(marks[i][1], ':') != NULL) {
sscanf(marks[i][1], "%d:%d", &intval2, &intval);
} else if (strchr(marks[i][1], '.') != NULL) {
sscanf(marks[i][1], "%d.%d", &intval2, &intval);
}
markmeter.append(intval);
} else {
intval = 0;
markmeter.append(intval);
}
}
}
}
//////////////////////////////
//
// printPreMarks --
//
void printPreMarks(ScorePageBase& scorepage, int basestaff,
Array<double>& marktimes, Array<int>& markmeter, double starttime,
double stoptime, double leftmar, double rightmar, double markcolor,
double markdashsize, double markspacesize, double markstyle,
double markthick) {
double sysdur = stoptime - starttime;
double hpos;
ScoreRecord srecord;
int i;
for (i=0; i<marktimes.getSize(); i++) {
if ((marktimes[i] < starttime)) {
hpos = (marktimes[i] - starttime) / sysdur;
hpos = hpos * (rightmar - leftmar) + leftmar;
srecord.clear();
srecord.setPValue(1, P1_Barline);
srecord.setPValue(2, basestaff);
srecord.setPValue(3, hpos);
srecord.setPValue(4, 2.0);
srecord.setPValue(5, markstyle);
if (markmeter[i] == 1) {
srecord.setPValue(6, markthick); // make first beat thicker
}
if (markstyle == 7.0) {
srecord.setPValue(8, markdashsize);
srecord.setPValue(9, markspacesize);
}
srecord.setPValue(10, 11.0);
srecord.setPValue(11, 3.0);
srecord.setPValue(26, markcolor);
scorepage.addItem(srecord);
}
}
}
//////////////////////////////
//
// printMarks --
//
void printMarks(ScorePageBase& scorepage, int basestaff,
Array<double>& marktimes, Array<int>& markmeter, double starttime,
double stoptime, double leftmar, double rightmar, double markcolor,
double markdashsize, double markspacesize, double markstyle,
double markthick) {
double sysdur = stoptime - starttime;
double hpos;
ScoreRecord srecord;
int i;
for (i=0; i<marktimes.getSize(); i++) {
if (marktimes[i] >= stoptime) {
break;
}
if (marktimes[i] < starttime) {
continue;
}
hpos = (marktimes[i] - starttime) / sysdur;
hpos = hpos * (rightmar - leftmar) + leftmar;
if (hpos < 0.0) {
continue;
}
srecord.clear();
srecord.setPValue(1, P1_Barline);
srecord.setPValue(2, basestaff);
srecord.setPValue(3, hpos);
srecord.setPValue(4, 2.0);
srecord.setPValue(5, markstyle);
if (markmeter[i] == 1) {
srecord.setPValue(6, markthick); // make first beat of measure thicker
}
if (markstyle == 7.0) {
srecord.setPValue(8, markdashsize);
srecord.setPValue(9, markspacesize);
}
srecord.setPValue(10, 11.0);
srecord.setPValue(11, 3.0);
srecord.setPValue(26, markcolor);
scorepage.addItem(srecord);
}
}
//////////////////////////////
//
// printTicks --
//
double printTicks(ScorePageBase& scorepage, int staff, int vpos, int direction,
double starttime, double stoptime, double leftmar, double rightmar,
double majdur, int secticks, int terticks, double majticklen,
double secticklen, double terticklen) {
double sysdur = stoptime - starttime;
Array<double> secticktimes;
secticktimes.setSize(secticks*2);
secticktimes.setSize(0);
int i, j;
int secfound;
double sectime, tertime;
// print major ticks:
double temp = starttime/majdur;
double startmajor;
if (temp - int(temp) == 0.0) {
startmajor = starttime;
} else {
startmajor = int(temp+1.0) * majdur;
}
double output = startmajor;
// draw secondary ticks which occur befor the first major tick
double hpos = 0;
secticktimes.setSize(0);
for (i=1; i<secticks; i++) {
sectime = startmajor - i * majdur/secticks;
if (sectime >= starttime) {
secticktimes.append(sectime);
hpos = (sectime - starttime) / sysdur;
hpos = hpos * (rightmar - leftmar) + leftmar;
drawtick(scorepage, staff, hpos, vpos, direction, secticklen);
}
}
for (i=1; i<terticks; i++) {
tertime = startmajor - i * majdur/terticks;
secfound = 0;
for (j=0; j<secticktimes.getSize(); j++) {
if (fabs(tertime - secticktimes[j]) < 0.0001) {
secfound = 1;
}
}
if ((secfound == 0) && (tertime >= starttime)) {
hpos = (tertime - starttime) / sysdur;
hpos = hpos * (rightmar - leftmar) + leftmar;
drawtick(scorepage, staff, hpos, vpos, direction, terticklen);
}
}
// draw major ticks, secondary ticks and tertiary ticks starting
// at the first major tick
while (startmajor <= stoptime) {
hpos = (startmajor - starttime) / sysdur;
hpos = hpos * (rightmar - leftmar) + leftmar;
drawtick(scorepage, staff, hpos, vpos, direction, majticklen);
secticktimes.setSize(0);
for (i=1; i<secticks; i++) {
sectime = startmajor + i * majdur/secticks;
secticktimes.append(sectime);
if (sectime <= stoptime) {
hpos = (sectime - starttime) / sysdur;
hpos = hpos * (rightmar - leftmar) + leftmar;
drawtick(scorepage, staff, hpos, vpos, direction, secticklen);
}
}
for (i=1; i<terticks; i++) {
tertime = startmajor + i * majdur/terticks;
secfound = 0;
for (j=0; j<secticktimes.getSize(); j++) {
if (fabs(tertime - secticktimes[j]) < 0.0001) {
secfound = 1;
}
}
if ((secfound == 0) && (tertime <= stoptime)) {
hpos = (tertime - starttime) / sysdur;
hpos = hpos * (rightmar - leftmar) + leftmar;
drawtick(scorepage, staff, hpos, vpos, direction, terticklen);
}
}
startmajor += majdur;
}
return output;
}
//////////////////////////////
//
// drawtick --
//
void drawtick(ScorePageBase& scorepage, int staff, double hpos, double vpos,
int direction, double len) {
ScoreRecord srecord;
srecord.setPValue(1, P1_Line);
srecord.setPValue(2, staff);
srecord.setPValue(3, hpos);
srecord.setPValue(4, vpos);
srecord.setPValue(5, vpos);
srecord.setPValue(6, hpos+len);
srecord.setPValue(13, -1 * direction * 90.0);
scorepage.addItem(srecord);
}
//////////////////////////////
//
// printSystem --
//
void printSystem(ScorePageBase& scorepage, int basestaff, Array<double>& times,
Array<double>& dyns, Array<int>& pitches, Array<int>& pstaff,
Array<int>& measures, double minsystime, double maxsystime,
int finalbarlineQ) {
if (verboseQ) {
cout << "@minsystime:\t" << minsystime << endl;
cout << "@maxsystime:\t" << maxsystime << endl;
cout << "@basestaff:\t" << basestaff << endl;
}
ScoreRecord srecord;
double startmajortick = -1000;
if (tickDisplayQ) {
startmajortick = printTicks(scorepage, basestaff, 3, -1, minsystime,
maxsystime, leftmargin, rightmargin, majortickdur, secondaryticks,
tertiaryticks, majorticklen, secticklen, terticklen);
// print above treble staff
printTicks(scorepage, basestaff+1, 11, 1, minsystime, maxsystime,
leftmargin, rightmargin, majortickdur, secondaryticks, tertiaryticks,
majorticklen, secticklen, terticklen);
if (ticklabelstyle == STYLE_LEFT) {
srecord.setPValue(1, P1_Number);
srecord.setPValue(2, basestaff);
srecord.setPValue(3, 0.0);
srecord.setPValue(4, -0.5);
srecord.setPValue(5, startmajortick);
srecord.setPValue(6, 0.5);
scorepage.addItem(srecord);
srecord.clear();
}
}
srecord.setPValue(1, P1_Staff);
srecord.setPValue(2, basestaff);
if (staffscale != 1.0) {
srecord.setPValue(5, staffscale);
}
scorepage.appendItem(srecord);
srecord.setPValue(2, basestaff+1);
// needs to be adjusted when more than one system on a page:
srecord.setPValue(4, -5);
scorepage.appendItem(srecord);
srecord.clear();
srecord.setPValue(1, P1_Clef);
srecord.setPValue(2, basestaff+1);
srecord.setPValue(3, 1.5);
scorepage.appendItem(srecord);
srecord.setPValue(2, basestaff);
srecord.setPValue(5, 1); // bass cleff
scorepage.appendItem(srecord);
srecord.clear();
// add basic measure lines
srecord.setPValue(1, P1_Barline);
srecord.setPValue(2, basestaff);
srecord.setPValue(4, 2.0);
srecord.setPValue(3, 0.0);
scorepage.appendItem(srecord); // barline at start of system
srecord.setPValue(5, 8.0);
scorepage.appendItem(srecord); // curly-brace at start of system
srecord.setPValue(3, 200.0);
if (finalbarlineQ) {
srecord.setPValue(5, 2.0); // add final barline
} else {
srecord.setPValue(5, 0.0);
}
scorepage.appendItem(srecord); // right-side barline
srecord.clear();
// notes have to be placed on page so that those
// with more ledger lines are printed before those
// with fewer ledger lines; otherwise, the ledger lines
// of the ones with more will over write those with less.
SigCollection<SigCollection<ScoreRecord> > notelayers;
notelayers.setSize(50);
int i;
for (i=0; i<notelayers.getSize(); i++) {
notelayers[i].setSize(100);
notelayers[i].setGrowth(1000);
notelayers[i].setSize(0);
}
int layer;
int closeSvg = 0;
double p2val, p3val, p4val, p26val = 0;
double p32val = 0.0;
int foundfirstnote = 0;
ScoreRecord prefix;
ScoreRecord postfix;
char buffer[1024] = {0};
char hexcolor[1024] = {0};
for (i=0; i<times.getSize(); i++) {
if (times[i] < minsystime) {
continue;
}
if (times[i] > maxsystime) {
continue;
}
if (foundfirstnote == 0) {
// place the measure number of the first note on the system
// on the top-left side of the system:
srecord.clear();
srecord.setPValue(1, P1_Number);
srecord.setPValue(2, basestaff+1);
srecord.setPValue(3, 0.0);
srecord.setPValue(4, 15.0);
srecord.setPValue(5, measures[i]);
srecord.setPValue(7, 1.0);
scorepage.addItem(srecord);
foundfirstnote = 1;
}
// cout << times[i] << "\t" << dyns[i]
// << "\t" << pitches[i]
// << "\t" << pstaff[i] << endl;
srecord.clear();
srecord.setPValue(1, P1_Note);
p2val = basestaff + pstaff[i];
srecord.setPValue(2, p2val);
p3val = (times[i] - minsystime) / (maxsystime - minsystime);
p3val = (rightmargin - leftmargin) * p3val + leftmargin;
srecord.setPValue(3, p3val);
p4val = Convert::base40ToScoreVPos(pitches[i], !pstaff[i]);
srecord.setPValue(4, p4val);
if (!svgQ) {
srecord.setPValue(25, 100 - fabs(p4val)); // drawing layers:
// outer-most notes first
}
// have to use the following system because P25 system
// does not work very well:
layer = abs(int(p4val+0.999));
if (layer >= 50) {
layer = 49;
}
if (accidentalQ) {
int accval = Convert::base40ToAccidental(pitches[i]);
switch (accval) {
case 0: break; // natural: no accidental
case 1: // sharp
srecord.setPValue(5, 2); // sharp
break;
case -1: // flat
srecord.setPValue(5, 1); // flat
break;
case 2: // double-sharp
srecord.setPValue(5, 5); // double-sharp
break;
case -2: // double-flat
srecord.setPValue(5, 4); // double-flat
break;
}
if (accval != 0) {
srecord.setPValue(29, 0.5); // make accidental 50% than normal
}
}
if (scorever >= 6) {
// WinScore version
p26val = dyns[i] * (quietnote - loudnote) + loudnote;
p26val = int(p26val * 100.0 + 0.5)/100.0;
p26val = 1.0 - p26val*0.9 - 0.1;
if (p26val < 0.0) { p26val = 0.0; }
if (p26val > 1.0) { p26val = 1.0; }
if (!svgQ) {
srecord.setPValue(26, p26val);
} else {
prefix.clear();
prefix.setPValue(1, 16);
prefix.setPValue(2, 1);
prefix.setPValue(3, 1);
createHexColor(hexcolor, p26val);
sprintf(buffer, "_99%%svg%%<g color=\"%s\" stroke=\"%s\">",
hexcolor, hexcolor);
prefix.setText(buffer);
notelayers[layer].append(prefix);
closeSvg++;
}
} else {
// for SCORE 5 (color)
p32val = int(100.0 * dyns[i] * (quietnote - loudnote) + loudnote + 0.5);
p32val = 100.0 - p32val;
if (p32val > 99) { p32val = 99; }
if (p32val < 1) { p32val = 1; }
p32val = p32val/100.0;
if (!svgQ) {
srecord.setPValue(32, p32val);
} else {
prefix.clear();
prefix.setPValue(1, 16);
prefix.setPValue(2, 1);
prefix.setPValue(3, 1);
prefix.setText("_99%svg%<g color=\"red\" stroke=\"red\">");
notelayers[layer].append(prefix);
closeSvg++;
}
}
notelayers[layer].append(srecord); // store note for later adding to page
while (closeSvg > 0) {
closeSvg--;
postfix.clear();
postfix.setPValue(1, 16);
postfix.setPValue(2, 1);
postfix.setPValue(3, 1);
postfix.setText("_99%svg%<\\g>");
notelayers[layer].append(postfix);
}
if (notenumbersQ) {
int notenumber = int(times[i] * 1000.0 + 0.5) % 100;
srecord.clear();
srecord.setPValue(1, P1_Text);
srecord.setPValue(2, p2val);
srecord.setPValue(3, p32val);
if ((int(p4val)+100) % 2 == 0) {
// note occurs on a space
srecord.setPValue(4, p4val+0.25-1); // place on space after note
} else {
// note occurs on a line
srecord.setPValue(4, p4val+0.25); // place on space above note
}
char tempbuff[128] = {0};
if (notenumber < 10) {
sprintf(tempbuff, "0%d", notenumber);
} else {
sprintf(tempbuff, "%d", notenumber);
}
srecord.setTextData(tempbuff);
srecord.setTextFont("_08"); // Helvetica-Narrow
srecord.setPValue(6, 0.5 * notenumbersize);
srecord.setPValue(11, 2.2); // horizontal offset
srecord.setPValue(5, 0.9); // squeeze digits together
if (notenumbercolor < 0) {
double color = p26val; // match color of notehead with a minimum
if (color > 0.75) {
color = 0.75;
}
srecord.setPValue(16, color);
} else {
srecord.setPValue(16, notenumbercolor);
}
srecord.setPValue(14, -1); // needed for colored text
// consider adding a printing layer here (P15 for text)
notelayers[layer].append(srecord); // store timing number
}
}
for (i=notelayers.getSize()-1; i>=0; i--) {
scorepage.addItem(notelayers[i]); // add notes to page in proper ordering
}
}
//////////////////////////////
//
// createHexColor -- convert a number in the range from 0.0 to 1.0 into
// a 3 byte hex color code.
//
char* createHexColor(char* hexcolor, double value) {
int value2 = int(value * 255 + 0.5);
if (value2 < 0) {
value2 = 0;
}
if (value2 > 255) {
value2 = 255;
}
sprintf(hexcolor, "#%2x%2x%2x", value2, value2, value2);
return hexcolor;
}
//////////////////////////////
//
// checkOptions --
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("c|count|page-count=b","list the number of pages input data produces");
opts.define("system-count=b","list the number of system input data produces");
opts.define("comment=s", "comment string for bottom right of page");
opts.define("cp|comment-position=d:180.0", "horz. position of comment");
opts.define("page=i:1", "output data for specified page");
opts.define("sys|system=i:1", "output data for specified system");
opts.define("s|scale|staff-scale=d:0.75", "staff size factor");
opts.define("l|left|left-margin=d:10.0", "left margin for data");
opts.define("timewidth|tw=d:5", "time width of system");
opts.define("r|right|right-margin=d:195.0", "right margin for data");
opts.define("v|verbose=b", "verbose information for debugging");
opts.define("p|piano=d:0.9", "grayscale for soft notes");
opts.define("f|forte=d:0.0", "grayscale for soft notes");
opts.define("o|output=s", "output file name for binary data");
opts.define("m|marks=s", "auxiliary vertical line data");
opts.define("2|m2|marks2=s", "auxiliary vertical lines (blue color)");
opts.define("3|m3|marks3=s", "auxiliary vertical lines (green color)");
opts.define("markcolor=d:997777", "color for marks");
opts.define("nns|note-number-size=d:1.0", "size of numbers for notes");
opts.define("nnc|note-number-color=d:-1.0", "note number color");
opts.define("aux=s", "auxiliary notes files with accidental info");
opts.define("accidental|acci=b", "display accidental marks");
opts.define("svg|SVG=b", "Use SVG extensions");
opts.define("author=b", "author of program");
opts.define("version=b", "compilation info");
opts.define("example=b", "example usages");
opts.define("help=b", "short description");
opts.process(argc, argv);
// handle basic options:
if (opts.getBoolean("author")) {
cout << "Written by Craig Stuart Sapp, "
<< "craig@ccrma.stanford.edu, Mar 2009" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 9 Mar 2009" << endl;
cout << "compiled: " << __DATE__ << endl;
cout << MUSEINFO_VERSION << endl;
exit(0);
} else if (opts.getBoolean("help")) {
usage(opts.getCommand());
exit(0);
} else if (opts.getBoolean("example")) {
example();
exit(0);
}
verboseQ = opts.getBoolean("verbose");
pagecountQ = opts.getBoolean("page-count");
systemcountQ = opts.getBoolean("system-count");
page = opts.getInteger("page");
systemZ = opts.getInteger("system");
systemQ = opts.getBoolean("system");
staffscale = opts.getDouble("staff-scale");
leftmargin = opts.getDouble("left-margin");
rightmargin = opts.getDouble("right-margin");
quietnote = opts.getDouble("piano");
loudnote = opts.getDouble("forte");
if (opts.getBoolean("output")) {
ofile = opts.getString("output");
}
svgQ = opts.getBoolean("svg");
marksfile = opts.getString("marks");
marksfile2 = opts.getString("marks2");
marksfile3 = opts.getString("marks3");
markcolor = opts.getDouble("markcolor");
auxfile = opts.getString("aux");
auxQ = opts.getBoolean("aux");
accidentalQ = opts.getBoolean("accidental");
timewidth = opts.getDouble("timewidth");
notenumbersize = opts.getDouble("note-number-size");
notenumbercolor = opts.getDouble("note-number-color");
commentstring = opts.getString("comment");
commenthpos = opts.getDouble("comment-position");
}
//////////////////////////////
//
// example --
//
void example(void) {
}
//////////////////////////////
//
// usage --
//
void usage(const char* command) {
}
// md5sum: 16f80a1b3bc2573fe650e13ae0b4ac48 noteheadtime-webern.cpp [20120910]