//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sat Jul 19 12:09:12 PDT 2003
// Last Modified: Tue Jul 22 21:01:22 PDT 2003
// Last Modified: Sun Sep 7 10:42:09 PDT 2003 (added multiple systems)
// Last Modified: Mon Dec 6 22:09:12 PST 2004 (minor improvements)
// Filename: ...sig/examples/all/chor2scor.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/score/chor2scor.cpp
// Syntax: C++; museinfo
//
// Description: Convert a Humdrum chorale file into a SCORE data file.
//
#include "humdrum.h"
#include <string.h>
#include <ctype.h>
#ifndef OLDCPP
#include <fstream>
using namespace std;
#else
#include <fstream.h>
#endif
// function declarations
void checkOptions(Options& opts, int argc, char* argv[]);
void recheckOptions(Options& opts, char* command, const char* string);
void example(void);
void usage(const char* command);
void convertToScore(ostream& output, HumdrumFile& infile, int segment,
Array<int>& breaks);
void printNote(ostream& output, const char* data, double hpos,
HumdrumFile& infile, int line, int staff,
int direction, int voice);
void printStaffInfo(ostream& output, HumdrumFile& infile, int segment);
int noteheadtype(double duration);
void printMeasure(ostream& output, HumdrumFile& infile, int line,
double hpos, int measurecount, int systemno);
void printHarm(ostream& output, const char* text, double hpos,
HumdrumFile& infile, int harmspine);
void printTrailer(ostream& output);
int getdots(double duration, int voice);
int getflags(double duration);
double makeaccidental(HumdrumFile& infile, int line, int voice,
Array<int>& lkey);
void resetkey(void);
int peekAccidental(HumdrumFile& infile, int line, int voice,
Array<int>& lkey);
double getHpos(HumdrumFile& infile, int line, double start = -1,
double ending = -1);
void generateBeams(ostream& output, HumdrumFile& infile, int voice,
int startline, int stopline);
void checkForBeam(ostream& output, HumdrumFile& infile, int voice,
Array<int>& index, int i);
double getBeamStart(double vpos1, double vpos2, int dir);
double getBeamEnd(double vpos1, double vpos2, int dir);
void fillnindex(HumdrumFile& infile, Array<Array<int> >& nindex);
void initoffset(Array<Array<double> >& offset,
Array<Array<int> >& nindex);
void storeoffset(double offset, int voice, int line);
double getoffset(const char* lower, const char* upper);
void printTitle(ostream& output, const char* title);
void printKeyInfo(ostream& output, const char* key, double hpos,
double vpos);
void calculateBreaks(Array<int>& breaks, HumdrumFile& infile, int lines);
void makeFilename(char* buffer, const char* zbasename, char* ext,
int total, int n);
int findHarmSpine(HumdrumFile& infile);
int findHarmSpine(HumdrumRecord& aRecord);
// global variables
Options options; // database for command-line arguments
int debugQ = 0; // used with --debug option
int quietQ = 0; // used with -q option
double scale = 0.6; // used with -s option
int readQ = 1; // used with -R option
int harmonyQ = 1; // used with -H option
int lines = 1; // used with -l option
char inputbase[1024] = {0}; // used with -o option (for %b expansion)
char zbasename[1024] = {0}; // used with -o option
char extension[1024] = {0}; // used with -o option
Array<double> tie(4); // for keeping track of ties
Array<int> key(7); // for keeping track of key
Array<Array<int> > vkey(4); // for keeping track of accidentals
Array<Array<double> > offsets(4); // for keeping track of beam offsets
Array<Array<int> > nindex(4); // for keeping track of beam offsets
Array<int> breaks; // for keeping track of line breaks
///////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
checkOptions(options, argc, argv);
HumdrumFile infile;
char* filenameIn = options.getArg(1);
infile.read(filenameIn);
infile.analyzeRhythm();
int i;
if (readQ) {
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].getType() == E_humrec_global_comment) {
if (strncmp(infile[i][0], "!!chor2scor:", 12) == 0) {
recheckOptions(options, (char*)argv[0], &infile[i][0][12]);
}
}
}
}
tie.setAll(0.0);
key.setAll(0);
for (i=0; i<3; i++) {
vkey[i].setSize(7);
vkey[i].setAll(0);
}
fillnindex(infile, nindex);
initoffset(offsets, nindex);
calculateBreaks(breaks, infile, lines);
ofstream* output;
char buffer[1024] = {0};
for (i=0; i<lines; i++) {
if (zbasename[0] != '\0') {
makeFilename(buffer, zbasename, extension, lines, i);
if (!quietQ) {
cout << "ZZZ Creating file " << buffer << "..." << endl;
}
output = new ofstream;
output->open(buffer);
convertToScore(*output, infile, i, breaks);
output->close();
delete output;
} else {
if (!quietQ) {
cout << "ZZZ System " << i+1 << "/" << lines
<< " ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" << endl;
}
convertToScore(cout, infile, i, breaks);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// makeFilename --
//
void makeFilename(char* buffer, const char* zbasename, char* ext, int total,
int n) {
if (total > 10 && n < 10) {
sprintf(buffer, "%s0%d.%s", zbasename, n+1, ext);
} else if (total > 100 && n < 10) {
sprintf(buffer, "%s00%d.%s", zbasename, n+1, ext);
} else if (total > 100 && n < 100) {
sprintf(buffer, "%s00%d.%s", zbasename, n+1, ext);
} else {
sprintf(buffer, "%s%d.%s", zbasename, n+1, ext);
}
}
///////////////////////////////
//
// calculateBreaks -- determine line breaks in the music
//
void calculateBreaks(Array& breaks, HumdrumFile& infile, int lines) {
Array<int> items;
items.setSize(infile.getNumLines());
items.setSize(0);
if (lines <= 1) {
return;
}
int temp;
Array<int> explicitbreaks;
explicitbreaks.setSize(infile.getNumLines());
explicitbreaks.setSize(0);
int i;
for (i=1; i<infile.getNumLines()-1; i++) {
if (infile[i].getType() == E_humrec_global_comment) {
if (strncmp(infile[i][0], "!!linebreak", 11) == 0) {
cout << "!!LINEBREAK FOUND ON LINE " << i + 1 << endl;
if (infile[i-1].getType() == E_humrec_data_measure) {
temp = i-1;
explicitbreaks.append(temp);
} else {
temp = i+1;
explicitbreaks.append(temp);
}
}
}
}
cout << "LINES = " << lines << " CHECK = " << explicitbreaks.getSize() + 1 << endl;
if (explicitbreaks.getSize() + 1 == lines) {
cout << "COPYING BREAKS " << endl;
breaks.setSize(explicitbreaks.getSize());
for (i=0; i<explicitbreaks.getSize(); i++) {
breaks[i] = explicitbreaks[i];
}
if (!quietQ) {
for (i=0; i<breaks.getSize(); i++) {
cout << "ZZZ Linebreak " << i+1 << " is on line "
<< breaks[i]+1 << endl;
}
}
return;
}
// get a list of the horizontal items (data and measures)
for (i=0; i<infile.getNumLines(); i++) {
switch (infile[i].getType()) {
case E_humrec_data:
if (infile[i].equalFieldsQ("**kern", ".") == 0) {
// ignoring null-token lines in **kern data
items.append(i);
}
break;
case E_humrec_data_measure:
if (strchr(infile[i][0], '-') == NULL) {
items.append(i);
}
break;
}
}
breaks.setSize(lines);
breaks.setSize(0);
int division = 0;
int j;
double duron = 0.0;
double durbefore = 0.0;
double durafter = 0.0;
int divbefore = 0;
int divafter = 0;
double dis1, dis2;
for (i=0; i<lines-1; i++) {
division = (int)(1.0 * items.getSize() / lines + 0.5);
duron = infile[items[division]].getAbsBeat();
durbefore = duron;
durafter = duron;
for (j=division; j<items.getSize(); j++) {
if (infile[items[j]].getType() == E_humrec_data_measure) {
durafter = infile[items[j]].getAbsBeat();
divafter = j;
break;
}
}
for (j=division; j>=0; j--) {
if (infile[items[j]].getType() == E_humrec_data_measure) {
durafter = infile[items[j]].getAbsBeat();
divbefore = j;
break;
}
}
dis1 = duron - durbefore;
dis2 = durafter - duron;
if (dis1 < dis2) {
breaks.append(items[divbefore]);
} else {
breaks.append(items[divafter]);
}
}
if (!quietQ) {
for (i=0; i<breaks.getSize(); i++) {
cout << "ZZZ Break " << i+1 << ": " << breaks[i]+1 << endl;
}
}
}
//////////////////////////////
//
// printTitle --
//
void printTitle(ostream& output, const char* title) {
int i;
int length = strlen(title);
for (i=0; i<length; i++) {
if ((title[i] == 'a') && (title[i+1] == 'e')) {
output << "%%a";
i++;
} else if ((title[i] == 'o') && (title[i+1] == 'e')) {
output << "%%o";
i++;
} else if ((title[i] == 'u') && (title[i+1] == 'e')) {
output << "%%u";
i++;
} else {
output << title[i];
}
}
}
//////////////////////////////
//
// initoffset --
//
void initoffset(Array >& offsets, Array >& nindex) {
int i;
offsets.setSize(4);
for (i=0; i<4; i++) {
offsets[i].setSize(nindex[i].getSize());
offsets[i].setAll(0.0);
}
}
//////////////////////////////
//
// fillnindex -- create an index of the notes in each voice
// for beam maintenance.
//
void fillnindex(HumdrumFile& infile, Array >& nindex) {
int i, j;
for (i=0; i<4; i++) {
nindex[i].setSize(infile.getNumLines());
nindex[i].setSize(0);
for (j=0; j<infile.getNumLines(); j++) {
if (infile[j].isData()) {
if (strcmp(infile[j][i], ".") == 0) {
continue;
}
if (strchr(infile[j][i], 'r') != NULL) {
continue;
}
nindex[i].append(j);
}
}
}
}
//////////////////////////////
//
// resetkey -- copy the global key into the temporary voice key for
// the measure.
//
void resetkey(void) {
int i;
int j;
for (i=0; i<4; i++) {
for (j=0; j<7; j++) {
vkey[i][j] = key[j];
}
}
}
//////////////////////////////
//
// setKey -- set the default key signature accidentals
//
void setKey(int keynum) {
if (keynum < 0) {
if (keynum <= -7) key[3] = -1; // F
if (keynum <= -6) key[0] = -1; // C
if (keynum <= -5) key[4] = -1; // G
if (keynum <= -4) key[1] = -1; // D
if (keynum <= -3) key[5] = -1; // A
if (keynum <= -2) key[2] = -1; // E
if (keynum <= -1) key[6] = -1; // B
} else if (keynum > 0) {
if (keynum >= 1) key[3] = 1; // F
if (keynum >= 2) key[0] = 1; // C
if (keynum >= 3) key[4] = 1; // G
if (keynum >= 4) key[1] = 1; // D
if (keynum >= 5) key[5] = 1; // A
if (keynum >= 6) key[2] = 1; // E
if (keynum >= 7) key[6] = 1; // B
}
}
//////////////////////////////
//
// printStaffInfo -- print staff, keysignature, Title, and meter
//
// 40% p4 = 2:-45 3:-67 4:-112
// 50% p4 = 2:-36 3:-48 4:-84
// 60% p4 = 2:-30 3:-37 4:-67
// 100% p4 = 2:-18 3:-12 4:-30
//
// staff 2 (tenor) vertical position calculated from this formula:
// p4 = -18/p5
// staff 3 (alto) vertical position calculated from this formula (approximate)
// p4 = -6*2/(p5*p5)
// staff 3 (soprano) vertical position calculated from this formula:
// p4 = -6*2/(p5*p5) - 18/p5
//
void printStaffInfo(ostream& output, HumdrumFile& infile, int segment) {
double trebleoffset = (int)(-6.0 * 2.0 / (scale*scale) + 0.5);
// fix approximation for 60% and 40% scalings:
if (scale == 0.6) {
trebleoffset = -37.0;
} else if (scale == 0.4) {
trebleoffset = -67.0;
}
// print bass staff:
output << "8 1 0 0 " << scale << " 200\n";
// print tenor staff:
output << "8 2 0 " << (-18.0/scale) << " " << scale << " 200\n";
// print alto staff:
output << "8 3 0 " << trebleoffset << " " << scale << " 200\n";
// print treble staff:
output << "8 4 0 " << (trebleoffset - 18.0/scale) << " " << scale << " 200\n";
// print bass clef:
output << "3 1 2 0 1\n";
// print bass clef:
output << "3 2 2 0 1\n";
// print treble clef:
output << "3 3 2 0 0\n";
// print treble clef:
output << "3 4 2 0 0\n";
// print opening barlines
output << "14 1 0 4 0\n";
output << "14 1 0 4 8\n";
// print key signatures
int i;
int keynum = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isInterpretation()) {
if (strncmp(infile[i][0], "*k[", 3) == 0) {
keynum = Convert::kernKeyToNumber(infile[i][0]);
}
}
}
setKey(keynum);
vkey[0] = key;
vkey[1] = key;
vkey[2] = key;
vkey[3] = key;
if (keynum != 0) {
// print bass key signature
output << "17 1 4 0 " << keynum << " 1\n";
// print bass key signature
output << "17 2 4 0 " << keynum << " 1\n";
// print treble key signature
output << "17 3 4 0 " << keynum << " 0\n";
// print treble key signature
output << "17 4 4 0 " << keynum << " 0\n";
}
// print time signatures if the first line of music
if (segment == 0) {
int top = 5;
int bottom = 5;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isInterpretation()) {
if (sscanf(infile[i][0], "*M%d/%d", &top, &bottom) == 2) {
break;
}
}
}
int metc = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isInterpretation()) {
if (strcmp(infile[i][0], "*met(C)") == 0) {
metc = 1;
break;
}
}
}
if (metc) {
// print the bass time signature
output << "18 1 7 0 " << 99 << " " << 1 << "\n";
// print the bass time signature
output << "18 2 7 0 " << 99 << " " << 1 << "\n";
// print the treble time signature
output << "18 3 7 0 " << 99 << " " << 1 << "\n";
// print the treble time signature
output << "18 4 7 0 " << 99 << " " << 1 << "\n";
} else {
// print the bass time signature
output << "18 1 7 0 " << top << " " << bottom << "\n";
// print the bass time signature
output << "18 2 7 0 " << top << " " << bottom << "\n";
// print the treble time signature
output << "18 3 7 0 " << top << " " << bottom << "\n";
// print the treble time signature
output << "18 4 7 0 " << top << " " << bottom << "\n";
}
}
if (segment == 0) {
// print title information
const char* title = "";
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isBibliographic()) {
if (strncmp(infile[i][0], "!!!OTL", 6) == 0) {
if (strchr(infile[i][0], ':') != NULL) {
title = strchr(infile[i][0], ':') + 1;
while (title[0] == ' ' || title[0] == '\n') {
if (title[0] == '\0') {
break;
}
title++;
}
break; // only get the first title in the file
}
}
}
}
int bhnum = 0;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].isBibliographic()) {
if (strncmp(infile[i][0], "!!!SCT: BH", 10) == 0) {
sscanf(infile[i][0], "!!!SCT: BH %d", &bhnum);
}
}
}
output << "t 4 0 20 0 1.5\n";
if (bhnum > 0) {
output << "_00" << bhnum << ". ";
printTitle(output, title);
output << "\n";
} else {
output << "_00";
printTitle(output, title);
output << "\n";
}
}
// // print final barline
// output << "14 1 200 4 2\n";
}
//////////////////////////////
//
// convertToScore -- convert humdrum data into a SCORE file
//
void convertToScore(ostream& output, HumdrumFile& infile, int segment,
Array<int>& breaks) {
int i;
double hpos = 0.0;
double lastharmhpos = 0.0;
const char* nextkey = NULL;
printStaffInfo(output, infile, segment);
int startline = 0;
int stopline = 0;
if (breaks.getSize() == 0) {
startline = 0;
stopline = infile.getNumLines() - 1;
} else {
if (segment == 0) {
startline = 0;
} else {
startline = breaks[segment-1];
}
if (segment == lines - 1) {
stopline = infile.getNumLines() - 1;
} else {
stopline = breaks[segment];
}
}
int measureitem = 0;
int harmspine = findHarmSpine(infile);
int staff = 0;
int direction = 0;
int voice = 0;
int length;
for (i=startline; i<=stopline; i++) {
hpos = getHpos(infile, i, infile[startline].getAbsBeat(),
infile[stopline].getAbsBeat());
if (infile[i].isInterpretation()) {
if (infile[i].isInterpretation()) {
length = strlen(infile[i][0]);
if ((infile[i][0][length-1] == ':') &&
(Convert::kernToBase40(infile[i][0]) > 0)) {
nextkey = infile[i][0];
}
}
} else if (infile[i].isMeasure()) {
printMeasure(output, infile, i, hpos, measureitem++, segment);
} else if (infile[i].isData()) {
// output << infile[i].getAbsBeat() << ":\t" << hpos << endl;
// check bass note
if (strcmp(infile[i][0], ".") != 0) {
staff = 1;
voice = 0;
direction = 20;
printNote(output, infile[i][0], hpos, infile, i,
staff, direction, voice);
}
// check tenor note
if (strcmp(infile[i][1], ".") != 0) {
staff = 2;
voice = 1;
direction = 10;
printNote(output, infile[i][1], hpos, infile, i,
staff, direction, voice);
}
// check alto note
if (strcmp(infile[i][2], ".") != 0) {
staff = 3;
voice = 2;
direction = 20;
printNote(output, infile[i][2], hpos, infile, i,
staff, direction, voice);
}
// check soprano note
if (strcmp(infile[i][3], ".") != 0) {
staff = 4;
voice = 3;
direction = 10;
printNote(output, infile[i][3], hpos, infile, i,
staff, direction, voice);
}
// print **harm data
harmspine = findHarmSpine(infile[i]);;
if ((harmspine >= 0) && (strcmp(infile[i][harmspine], ".") != 0)) {
if (nextkey != NULL) {
printKeyInfo(output, nextkey,
(hpos - lastharmhpos)/2.0+lastharmhpos+scale, -9);
nextkey = NULL;
}
printHarm(output, infile[i][harmspine], hpos, infile, harmspine);
lastharmhpos = hpos;
}
}
}
for (i=0; i<4; i++) {
generateBeams(output, infile, i, startline, stopline);
}
printTrailer(output);
}
//////////////////////////////
//
// findHarmSpine -- find the spine number for the **harm data
//
int findHarmSpine(HumdrumRecord& aRecord) {
int output = -1;
if (harmonyQ == 0) {
return output;
}
int i;
for (i=0; i<aRecord.getFieldCount(); i++) {
if (strcmp(aRecord.getExInterp(i), "**harm") == 0) {
output = i;
break;
}
}
return output;
}
int findHarmSpine(HumdrumFile& infile) {
int output = -1;
if (harmonyQ == 0) {
return output;
}
int i, j;
for (i=0; i<infile.getNumLines(); i++) {
if (infile[i].getType() != E_humrec_interpretation) {
continue;
}
for (j=0; j<infile[i].getFieldCount(); j++) {
if (strcmp(infile[i].getExInterp(j), "**harm") == 0) {
output = j;
return output;
}
}
}
return output;
}
//////////////////////////////
//
// printKeyInfo -- print the analysis key
//
void printKeyInfo(ostream& output, const char* key, double hpos,
double vpos) {
int i;
int length = strlen(key);
// double offset = length <= 3 ? -4 : -4.6;
// output << "t 1 " << hpos << " " << vpos << " 0 1.0 1.25 0 0 0 "
// << offset
// << "\n";
output << "t 1 " << hpos << " " << vpos << " 0 1.0 1.25\n";
output << "_01" ;
for (i=1; i<length-1; i++) {
if (key[i] == '-') {
output << "?1";
} else if (key[i] == '#') {
output << "?2";
} else {
output << key[i];
}
}
output << ":\n";
}
//////////////////////////////
//
// printTrailer --
//
void printTrailer(ostream& output) {
output <<
// "IF p1=6 and p7>19 and (p4<8 or p5<8) then p4=p4+0.5, p5=p5+0.5\n"
// "IF p1=6 and p7>19 and (p4<6 or p5<6) then p4=p4+0.5, p5=p5+0.5\n"
// "IF p1=6 and p7>19 and (p4<4 or p5<4) then p4=p4+0.5, p5=p5+0.5\n"
"AD 99\n"
"STM 99\n"
"LJ\n"
"1 4\n\n\n"
// These next lines fix extra low fermatas so that they do not collide
// with the harmonic analysis line. These commands have to go below the
// STM 99 command:
"IF p1=1 and p2=1 and p11=-14 and p4=2 then p8=-3\n"
"IF p1=1 and p2=1 and p11=-14 and p4=1 then p8=-3\n"
"IF p1=1 and p2=1 and p11=-14 and p4=0 then p8=-3, p14=0.5\n"
"IF p1=1 and p2=1 and p11=-14 and p4=-1 then p8=-3.75, p14=0.75\n"
;
}
//////////////////////////////
//
// printHarm -- print Harmonic analysis
//
void printHarm(ostream& output, const char* text, double hpos,
HumdrumFile& infile, int harmspine) {
if (strchr(text, 'r') != NULL) {
return;
}
output << "t 1 " << hpos << " -7 0 0 0 0 90\n";
output << "_29" ;
int i;
int length = strlen(text);
for (i=0; i<length; i++) {
if (text[i] == '/') {
output << '\\';
} else if (text[i] == ';') {
// don't print fermata
} else if (text[i] == '[') {
output << "?[";
} else if (text[i] == ']') {
output << "?]";
} else {
output << text[i];
}
}
output << "\n";
}
//////////////////////////////
//
// printMeasure --
//
void printMeasure(ostream& output, HumdrumFile& infile, int line, double hpos,
int measurecount, int systemno) {
int btype;
const char* data = infile[line][0];
if (strchr(data, '-') != NULL) {
return; // this is a non-printing barline
} else if (strncmp(data, "==", 2) == 0) { // final barline
btype = 2;
} else if (strstr(data, ":|!|:") != NULL) {
btype = 5;
} else if (strstr(data, ":!!:") != NULL) {
btype = 6;
} else if (strstr(data, ":|!") != NULL) {
btype = 3;
} else if (strstr(data, "!|:") != NULL) {
btype = 4;
} else if (strstr(data, "||") != NULL) {
btype = 1;
} else {
// plain measure
btype = 0;
}
// offset the position so that the first beat of the next
// measure does not collide with the measure
double hposition = hpos;
if (hposition < 199.80) {
// only shift the measure line back if not at the end of a line (200)
hposition -= 1.00;
}
if ((systemno > 0) && (measurecount == 0)) {
// don't draw the measure line if it is of type 0
switch (btype) {
case 0:
case 1:
case 3:
// do nothing -- supress printing of this barline
break;
case 6:
case 5:
btype = 4;
// no break;
case 4:
output << "14 1 " << hposition << " 4 " << btype << "\n";
break;
}
} else {
output << "14 1 " << hposition << " 4 " << btype << "\n";
}
int measureno = 0;
// print measure number, if it is there
if ((systemno > 0) && (measurecount == 0)) {
// print measure number at start of system before clefs
if (sscanf(data, "=%d", &measureno)) {
output << "10 4 " << 0 << " 13 " << measureno << " 0.8 1\n";
output << "I\nCM\n\n";
}
} else if (hposition < 199.8) {
if (sscanf(data, "=%d", &measureno)) {
output << "10 4 " << hposition << " 13 " << measureno << " 0.8 1\n";
output << "I\nCM\n\n";
}
}
resetkey();
}
//////////////////////////////
//
// getoffset -- return the note offset to avoid collisions due
// to closeness of two voices on the same staff.
//
double getoffset(const char* lower, const char* upper) {
if (strcmp(lower, ".") == 0) {
return 0;
}
if (strcmp(upper, ".") == 0) {
return 0;
}
int lowp = Convert::kernToBase40(lower);
int upp = Convert::kernToBase40(upper);
if ((upp - lowp > 0) && (upp - lowp < 10)) {
return 10;
}
int lowtype = noteheadtype(Convert::kernToDuration(lower));
int uptype = noteheadtype(Convert::kernToDuration(upper));
if ((upp - lowp >= 0) && (upp - lowp < 5)) {
if (lowtype != uptype) {
return 10;
}
}
return 0;
}
//////////////////////////////
//
// makeaccidental --
//
double makeaccidental(HumdrumFile& infile, int line, int voice,
Array<int>& lkey) {
int acc = 0;
int length = strlen(infile[line][voice]);
int i;
for (i=0; i<length; i++) {
if (infile[line][voice][i] == '-') {
acc += -1;
} else if (infile[line][voice][i] == '#') {
acc += 1;
}
}
int base40 = Convert::kernToBase40(infile[line][voice]);
int diatonic = Convert::base40ToDiatonic(base40) % 7;
// don't write an accidental which is in the current key set
if ((acc == lkey[diatonic]) &&
(strchr(infile[line][voice], 'n') == NULL) &&
(strchr(infile[line][voice], 'y') == NULL)
) {
return 0;
}
lkey[diatonic] = acc;
int output = 0;
if (strchr(infile[line][voice], 'n') != NULL) {
output = 3; // natural sign
} else {
switch (acc) {
case -2: output = 4; break; // double flat
case -1: output = 1; break; // flat
case 0: output = 3; break; // natural sign
case 1: output = 2; break; // sharp sign
case 2: output = 5; break; // double sharp sign
}
}
// check for moving the accidental if they will collide
double fraction = 0.0;
if ((voice == 1) || (voice == 3)) {
return output + fraction;
}
// check on bass and alto voices
int poutput = 0;
if (voice == 0) {
poutput = peekAccidental(infile, line, 1, vkey[1]); // look at tenor acc.
} else {
poutput = peekAccidental(infile, line, 3, vkey[3]); // look at sop. acc.
}
if (poutput == 0) {
return output + fraction;
}
int b40u = 0;
int b40d = 0;
if (voice == 0) {
b40u = Convert::kernToBase40(infile[line][1]);
b40d = Convert::kernToBase40(infile[line][0]);
} else {
b40u = Convert::kernToBase40(infile[line][3]);
b40d = Convert::kernToBase40(infile[line][2]);
}
// the function does not check properly if the voices are inverted
if ((b40u - b40d < 0) || (b40u - b40d >= 40)) {
return output + fraction;
}
int dup = Convert::base40ToDiatonic(b40u) % 7;
int ddn = Convert::base40ToDiatonic(b40d) % 7;
int dint = dup - ddn;
if (dint < 0) {
dint += 7;
}
// Here are the accidental offset separations by diatonic interval for
// sharps, flats and naturals (doubles to be done later, if ever)
//
// bot top 2 3 4 5 6 7
// b b 0.24 0.24 0.15 0.15 0.12 0.00
// b s 0.25 0.25 0.25 0.20 0.18 0.11
// b n 0.22 0.22 0.18 0.12 0.12 0.00
// s b 0.24 0.24 0.24 0.18 0.00 0.00
// s s 0.29 0.29 0.29 0.22 0.20 0.00
// s n 0.24 0.24 0.23 0.11 0.11 0.00
// n b 0.24 0.24 0.20 0.13 0.00 0.00
// n s 0.26 0.26 0.25 0.20 0.12 0.00
// n n 0.22 0.22 0.16 0.12 0.00 0.00
//
// ignoring spacing when dealing with double sharps or double flats
if ((poutput > 3) || (output > 3)) {
return output + fraction;
}
// ignoring spacing for unison accidentals:
if (dint == 0) {
return output + fraction;
}
switch (output * 10 + poutput) {
case 11:
// b b 0.24 0.24 0.15 0.15 0.12 0.00
switch (dint) {
case 1: case 2: fraction = 0.24; break;
case 3: case 4: fraction = 0.15; break;
case 5: fraction = 0.12; break;
case 6: fraction = 0.12; break;
}
break;
case 12:
// b s 0.25 0.25 0.25 0.20 0.18 0.11
switch (dint) {
case 1: case 2: case 3: fraction = 0.25; break;
case 4: fraction = 0.20; break;
case 5: fraction = 0.18; break;
case 6: fraction = 0.11; break;
}
break;
case 13:
// b n 0.22 0.22 0.18 0.12 0.12 0.00
switch (dint) {
case 1: case 2: fraction = 0.22; break;
case 3: fraction = 0.18; break;
case 4: case 5: fraction = 0.12; break;
}
break;
case 21:
// s b 0.24 0.24 0.24 0.18 0.00 0.00
switch (dint) {
case 1: case 2: case 3: fraction = 0.24; break;
case 4: fraction = 0.18; break;
}
break;
case 22:
// s s 0.29 0.29 0.29 0.22 0.20 0.00
switch (dint) {
case 1: case 2: case 3: fraction = 0.29; break;
case 4: fraction = 0.22; break;
case 5: fraction = 0.20; break;
}
break;
case 23:
// s n 0.24 0.24 0.23 0.11 0.11 0.00
switch (dint) {
case 1: case 2: fraction = 0.24; break;
case 3: fraction = 0.22; break;
case 4: case 5: fraction = 0.11; break;
}
break;
case 31:
// n b 0.24 0.24 0.20 0.13 0.00 0.00
switch (dint) {
case 1: case 2: fraction = 0.24; break;
case 3: fraction = 0.20; break;
case 4: fraction = 0.13; break;
}
break;
case 32:
// n s 0.26 0.26 0.25 0.20 0.12 0.00
switch (dint) {
case 1: case 2: fraction = 0.26; break;
case 3: fraction = 0.25; break;
case 4: fraction = 0.20; break;
case 5: fraction = 0.12; break;
}
break;
case 33:
// n n 0.22 0.22 0.16 0.12 0.00 0.00
switch (dint) {
case 1: case 2: fraction = 0.22; break;
case 3: fraction = 0.16; break;
case 4: fraction = 0.12; break;
}
break;
}
return output + fraction;
}
//////////////////////////////
//
// peekAccidental --
//
int peekAccidental(HumdrumFile& infile, int line, int voice,
Array<int>& lkey) {
if (strcmp(infile[line][voice], ".") == 0) {
return 0;
}
int acc = 0;
int length = strlen(infile[line][voice]);
int i;
for (i=0; i<length; i++) {
if (infile[line][voice][i] == '-') {
acc += -1;
} else if (infile[line][voice][i] == '#') {
acc += 1;
}
}
int base40 = Convert::kernToBase40(infile[line][voice]);
int diatonic = Convert::base40ToDiatonic(base40) % 7;
// don't write an accidental which is in the current key set
if ((acc == lkey[diatonic]) && (strchr(infile[line][voice], 'n') == NULL)) {
return 0;
}
int output = 0;
if (strchr(infile[line][voice], 'n') != NULL) {
output = 3; // natural sign
} else {
switch (acc) {
case -2: output = 4; break; // double flat
case -1: output = 1; break; // flat
case 0: output = 3; break; // natural sign
case 1: output = 2; break; // sharp sign
case 2: output = 5; break; // double sharp sign
}
}
return output;
}
//////////////////////////////
//
// printNote --
//
void printNote(ostream& output, const char* data, double hpos,
HumdrumFile& infile, int line, int staff, int direction, int voice) {
double duration = Convert::kernToDuration(data);
int pitch = Convert::kernToBase40(data);
int vpos = 0;
int clef = 0;
double offset = 0.0;
double accidental = 0.0;
switch (staff) {
case 1: clef = 1; break;
case 2: clef = 1; break;
case 3: clef = 0; break;
case 4: clef = 0; break;
}
double tiedir = 0;
switch (voice) {
case 0: tiedir = -1; break;
case 1: tiedir = 1; break;
case 2: tiedir = -1; break;
case 3: tiedir = 1; break;
}
if (strchr(data, 'r') != NULL) {
switch (voice) {
case 0: case 2:
output << "2 " << staff << " " << hpos << " -4 0 0 "
<< duration << endl;
break;
case 1: case 3:
output << "2 " << staff << " " << hpos << " 4 0 0 "
<< duration << endl;
break;
}
} else {
accidental = makeaccidental(infile, line, voice, vkey[voice]);
offset = 0.0;
if (voice == 2) {
offset = getoffset(infile[line][2], infile[line][3]);
if (offset != 0) {
storeoffset(offset, voice, line);
}
} else if (voice == 0) {
offset = getoffset(infile[line][0], infile[line][1]);
if (offset != 0) {
storeoffset(offset, voice, line);
}
} else if (voice == 1) {
// if the tenor is below the bass,
// then offset the tenor by a small amount so that note
// heads do not collide with the other voices stem.
if (Convert::kernToBase40(infile[line][1]) <
Convert::kernToBase40(infile[line][0])) {
offset = 0.9;
storeoffset(offset, voice, line);
}
} else if (voice == 3) {
// if the soprano is below the alto
// then offset the soprano by a small amount so that note
// heads do not collide with the other voices stem.
if (Convert::kernToBase40(infile[line][3]) <
Convert::kernToBase40(infile[line][2])) {
offset = 0.9;
storeoffset(offset, voice, line);
}
}
double stemadj = 0.0;
double fermataadj = 0.0;
vpos = Convert::base40ToScoreVPos(pitch, clef);
if ((strchr(data, ';') != NULL) && (voice == 0)) {
// these conditions don't really matter, because
// the stm 99 and ad 99 commands will erase this data.
// appended if statments to trailer to fix extra low fermatas
if (vpos < 2) {
stemadj = -3.5; // LJ erases this data anyway
}
if (vpos < 1) {
stemadj = -4.0; // LJ erases this data anyway
}
if (vpos < 1) {
fermataadj = 0.5;
}
if (vpos < 0) {
fermataadj = 1.0;
}
if (vpos < -1) {
fermataadj = 1.5;
}
}
output << "1 " << staff << " " << hpos << " " << vpos << " "
<< direction + accidental << " " << noteheadtype(duration) << " "
<< duration << " " << stemadj << " "
<< 10 * getdots(duration, voice) + getflags(duration)
<< " " << offset;
if (strchr(data, ';') != NULL) {
if (voice == 0) {
output << " -14";
if (fermataadj != 0.0) {
output << " " << fermataadj;
}
} else if (voice == 3) {
output << " 14";
} else if (voice == 1) {
if (strchr(infile[line][0], ';') == NULL) {
output << " 14";
}
} else if (voice == 2) {
if (strchr(infile[line][3], ';') == NULL) {
output << " -14";
}
}
}
output << "\n";
// check tie information
double voffset = 0.0;
if (voice == 0 || voice == 2) {
if (vpos % 2) {
voffset += -1;
} else {
voffset += -2;
}
} else {
if (vpos % 2) {
voffset += +1;
} else {
voffset += +2;
}
}
if (offset == 10) {
hpos += 1;
}
double roffset = 0.0;
if (voice == 1 || voice == 3) {
roffset = 0.25;
}
tiedir *= 0.8;
if (tiedir > 0) {
voffset += -0.5;
} else {
voffset += 0.5;
}
if ((tiedir > 0) && (vpos > 11) && (vpos % 2 == 0)) {
voffset += -1;
} else if ((tiedir > 0) && (vpos > 11) && (vpos % 2 == 1)) {
voffset += 0.5;
}
if ((tiedir < 0) && (vpos < 4) && (vpos % 2 == 0)) {
voffset += 0.5;
} else if ((tiedir < 0) && (vpos < 2) && (vpos % 2 == 1)) {
voffset -= 0.5;
}
if (strchr(data, '[') != NULL) {
tie[voice] = hpos;
} else if (strchr(data, '_') != NULL) {
output << "5 " << staff << " " << tie[voice] - 0.25 << " "
<< vpos+voffset << " " << vpos+voffset << " "
<< hpos + roffset << " " << tiedir << " -2 0 0 0 0 0.6\n";
if ((tiedir < 0) && (vpos <= 3)) {
output << "I\nCR\n\n";
}
tie[voice] = hpos;
} else if (strchr(data, ']') != NULL) {
output << "5 " << staff << " " << tie[voice] - 0.25 << " "
<< vpos+voffset << " " << vpos+voffset << " "
<< hpos + roffset << " " << tiedir << " -2 0 0 0 0 0.6\n";
if ((tiedir < 0) && (vpos <= 3)) {
output << "I\nCR\n\n";
}
tie[voice] = 0.0;
} else {
tie[voice] = 0.0;
}
}
}
//////////////////////////////
//
// storeoffset -- store the note offset so that the beams can be
// coordinated when they are written at a later stage.
//
void storeoffset(double offset, int voice, int line) {
int index = -1;
int i;
for (i=0; i<nindex[voice].getSize(); i++) {
if (nindex[voice][i] == line) {
index = i;
}
}
if (index >= 0) {
offsets[voice][index] = offset;
}
}
//////////////////////////////
//
// getflags --
//
int getflags(double duration) {
if (duration <= 1.0/128.0) { return 8; }
else if (duration < 1.0/64.0 ) { return 7; }
else if (duration < 1.0/32.0 ) { return 6; }
else if (duration < 1.0/16.0 ) { return 5; }
else if (duration < 1.0/8.0 ) { return 4; }
else if (duration < 1.0/4.0 ) { return 3; }
else if (duration < 1.0/2.0 ) { return 2; }
else if (duration < 1.0/1.0 ) { return 1; }
else { return 0; }
}
//////////////////////////////
//
// getdots -- return the number of rhythm augmentation dots
//
int getdots(double duration, int voice) {
char buffer[128] = {0};
Convert::durationToKernRhythm(buffer, duration);
int i = 0;
int count = 0;
while (buffer[i] != '\0') {
if (buffer[i] == '.') {
count++;
}
i++;
}
if ((count > 0) && (voice == 0 || voice == 2)) {
count += 10; // 10 multiplied later
}
return count;
}
//////////////////////////////
//
// noteheadtype --
//
int noteheadtype(double duration) {
if (duration < 1.9) { return 0; }
else if (duration < 3.9) { return 1; }
else if (duration < 7.9) { return 2; }
else { return 3; }
}
//////////////////////////////
//
// recheckOptions -- validate and process command-line options again
//
void recheckOptions(Options& opts, char* command, const char* string) {
char buffer[1024] = {0};
strncpy(buffer, string, 1000);
char* array[1024] = {0};
int argc = 0;
array[argc++] = command;
array[argc++] = strtok(buffer, " \t\n");
if (array[argc-1] != NULL) {
while ((array[argc++] = strtok(NULL, " \t\n")) != NULL) {
if (argc > 1000) {
break;
}
}
}
argc--;
opts.process(argc, array);
debugQ = opts.getBoolean("debug");
scale = opts.getDouble("scale");
lines = opts.getInteger("lines");
quietQ = opts.getBoolean("quiet");
readQ = !opts.getBoolean("do-not-read-file-options");
harmonyQ = !opts.getBoolean("no-harmony");
char buffer2[1024] = {0};
char* ptr;
if (options.getBoolean("output")) {
strcpy(buffer2, options.getString("output"));
if ((ptr = strrchr(buffer2, '.')) != NULL) {
strcpy(extension, ptr+1);
strcpy(zbasename, options.getString("output"));
ptr = strrchr(zbasename, '.');
ptr[0] = '\0';
} else {
strcpy(zbasename, options.getString("output"));
extension[0] = '\0';
}
}
if ((strcmp(zbasename, "%b") == 0) && (strlen(inputbase) > 0)) {
strcpy(zbasename, inputbase);
}
}
//////////////////////////////
//
// checkOptions -- validate and process command-line options.
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("debug=b", "trace input parsing");
opts.define("q|quiet=b", "do not print line parsing info");
opts.define("H|no-harmony=b", "do not print harmony under music");
opts.define("s|scale=d:0.6", "staff scaling");
opts.define("R|do-not-read-file-options=b","prevent reading opts in file");
opts.define("l|lines=i:1", "number of lines");
opts.define("o|output=s:file.pmx", "output file template");
opts.define("author=b", "author of the program");
opts.define("version=b", "compilation information");
opts.define("example=b", "example usage");
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, July 2003" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: September 2003" << 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);
}
debugQ = opts.getBoolean("debug");
scale = opts.getDouble("scale");
lines = opts.getInteger("lines");
quietQ = opts.getBoolean("quiet");
readQ = !opts.getBoolean("do-not-read-file-options");
char buffer[1024] = {0};
char* ptr;
if (options.getBoolean("output")) {
strcpy(buffer, options.getString("output"));
if ((ptr = strrchr(buffer, '.')) != NULL) {
strcpy(extension, ptr+1);
strcpy(zbasename, options.getString("output"));
ptr = strrchr(zbasename, '.');
ptr[0] = '\0';
} else {
strcpy(zbasename, options.getString("output"));
extension[0] = '\0';
}
}
char tbuffer[1024] = {0};
strcpy(tbuffer, options.getArg(1));
ptr = strrchr(tbuffer, '.');
if (ptr != NULL) {
ptr[0] = '\0';
}
ptr = strrchr(tbuffer, '/');
if (ptr != NULL) {
strcpy(inputbase, &ptr[1]);
} else {
strcpy(inputbase, tbuffer);
}
if ((strcmp(zbasename, "%b") == 0) &&(strlen(inputbase) > 0)) {
strcpy(zbasename, inputbase);
}
}
//////////////////////////////
//
// example -- example usage of the program
//
void example(void) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// usage -- gives the usage statement for the program
//
void usage(const char* command) {
cout <<
" \n"
<< endl;
}
//////////////////////////////
//
// generateBeams --
//
void generateBeams(ostream& output, HumdrumFile& infile, int voice,
int startline, int stopline) {
int i;
Array<int> index;
index.setSize(infile.getNumLines());
index.setSize(0);
// fix this for loop to prevent starting at 0
// for (i=startline; i<=stopline; i++) {
for (i=0; i<=stopline; i++) {
if (infile[i].isData()) {
if (strcmp(infile[i][voice], ".") == 0) {
continue;
}
if (strchr(infile[i][voice], 'r') != NULL) {
continue;
}
index.append(i);
}
}
for (i=0; i<index.getSize(); i++) {
if ((index[i]>=startline) && (index[i]<=stopline)) {
checkForBeam(output, infile, voice, index, i);
}
}
}
//////////////////////////////
//
// checkForBeam -- see if a beam is supposed to start here
//
void checkForBeam(ostream& output, HumdrumFile& infile, int voice,
Array<int>& index, int ind) {
int startbeat = 0;
int endbeat = 0;
// assume that there are no pickups less than a quarter note.
int beat = (int)(infile[index[ind]].getAbsBeat()+ 0.001);
double fraction = infile[index[ind]].getAbsBeat() - beat;
int tbeat = 0;
int j;
for (j=ind; j<index.getSize(); j++) {
tbeat = (int)(infile[index[j]].getAbsBeat()+ 0.001);
if (tbeat == beat) {
endbeat = j;
} else {
break;
}
}
for (j=ind; j>=0; j--) {
tbeat = (int)(infile[index[j]].getAbsBeat()+ 0.001);
if (tbeat == beat) {
startbeat = j;
} else {
break;
}
}
// don't beam quarter notes or larger
if (startbeat == endbeat) {
return;
}
// know that some beaming action necessary
Array<double> durs;
durs.setSize(0);
durs.setSize(endbeat-startbeat+1);
durs.setAll(0.0);
for (j=0; j<durs.getSize(); j++) {
durs[j] = Convert::kernToDuration(infile[index[j+startbeat]][voice]);
}
// beam on a case-by-case basis
double hpos1 = 0.0;
double hpos2 = 0.0;
double hpos3 = 0.0;
double vpos1 = 0.0;
double vpos2 = 0.0;
double vpos3 = 0.0;
//////////
int pitch1;
int pitch2;
int pitch3;
int dir = 0;
// beam two eighth notes together
if ((durs.getSize() == 2) && (durs[0] == 0.5) && (durs[1] == 0.5)
&& fraction < 0.001) {
hpos1 = getHpos(infile, index[startbeat]);
hpos2 = getHpos(infile, index[endbeat]);
pitch1 = Convert::kernToBase40(infile[index[startbeat]][voice]);
pitch2 = Convert::kernToBase40(infile[index[endbeat]][voice]);
switch (voice) {
case 0: case 2:
if (voice == 0) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 21;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 20)
<< " "
<< getBeamEnd(vpos1, vpos2, 20)
<< " " << hpos2 << " " << dir;
if (offsets[voice][startbeat] != 0.0) {
output << " 0 0 0 0 0 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] != 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] != 0.0) {
output << " 0 0 0 0 0 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
case 1: case 3:
if (voice == 1) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 11;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 10)
<< " "
<< getBeamEnd(vpos1, vpos2, 10)
<< " " << hpos2 << " " << dir;
if (offsets[voice][startbeat] != 0.0) {
output << " 0 0 0 0 0 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] != 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] != 0.0) {
output << " 0 0 0 0 0 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
}
}
//////////
// beam two sixteenth notes together on the half beat
else if ((durs.getSize() == 2) && (durs[0] == 0.25) && (durs[1] == 0.25)
&& fraction == 0.5) {
hpos1 = getHpos(infile, index[startbeat]);
hpos2 = getHpos(infile, index[endbeat]);
pitch1 = Convert::kernToBase40(infile[index[startbeat]][voice]);
pitch2 = Convert::kernToBase40(infile[index[endbeat]][voice]);
switch (voice) {
case 0: case 2:
if (voice == 0) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 22;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 20)
<< " "
<< getBeamEnd(vpos1, vpos2, 20)
<< " " << hpos2 << " " << dir;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 0 0 0 0 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 0 0 0 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
case 1: case 3:
if (voice == 1) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 12;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 10)
<< " "
<< getBeamEnd(vpos1, vpos2, 10)
<< " " << hpos2 << " " << dir;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 0 0 0 0 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 0 0 0 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
}
}
//////////
// beam two sixteenth notes starting on the beat (long note or rest
// on the second half of the beat
else if (((durs.getSize() == 2) && (durs[0] == 0.25) && (durs[1] == 0.25)
&& fraction == 0.0) ||
((durs.getSize() == 3) && (durs[0] == 0.25) && (durs[1] == 0.25)
&& (durs[2] >= 1.0) && fraction == 0.0)
) {
hpos1 = getHpos(infile, index[startbeat]);
hpos2 = getHpos(infile, index[startbeat+1]);
pitch1 = Convert::kernToBase40(infile[index[startbeat]][voice]);
pitch2 = Convert::kernToBase40(infile[index[startbeat+1]][voice]);
switch (voice) {
case 0: case 2:
if (voice == 0) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 22;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 20)
<< " "
<< getBeamEnd(vpos1, vpos2, 20)
<< " " << hpos2 << " " << dir;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 0 0 0 0 0 " << offsets[voice][startbeat];
if (offsets[voice][startbeat+1] > 0.0) {
output << " " << offsets[voice][startbeat+1];
}
} else if (offsets[voice][startbeat+1] > 0.0) {
output << " 0 0 0 0 0 0 0 " << offsets[voice][startbeat+1];
}
output << "\n";
break;
case 1: case 3:
if (voice == 1) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 12;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 10)
<< " "
<< getBeamEnd(vpos1, vpos2, 10)
<< " " << hpos2 << " " << dir;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 0 0 0 0 0 " << offsets[voice][startbeat];
if (offsets[voice][startbeat+1] > 0.0) {
output << " " << offsets[voice][startbeat+1];
}
} else if (offsets[voice][startbeat+1] > 0.0) {
output << " 0 0 0 0 0 0 0 " << offsets[voice][startbeat+1];
}
output << "\n";
break;
}
}
//////////
// beam one eighth and two sixteenth notes together
else if ((durs.getSize() == 3) && (durs[0] == 0.5) &&
(durs[1] == 0.25) && (durs[2] == 0.25) && fraction == 0.0) {
hpos1 = getHpos(infile, index[startbeat]);
hpos2 = getHpos(infile, index[startbeat+1]);
hpos3 = getHpos(infile, index[endbeat]);
pitch1 = Convert::kernToBase40(infile[index[startbeat]][voice]);
pitch2 = Convert::kernToBase40(infile[index[startbeat+1]][voice]);
pitch3 = Convert::kernToBase40(infile[index[endbeat]][voice]);
switch (voice) {
case 0: case 2:
if (voice == 0) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
vpos3 = Convert::base40ToScoreVPos(pitch3, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
vpos3 = Convert::base40ToScoreVPos(pitch3, 0);
}
dir = 21;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos3, 20)
<< " "
<< getBeamEnd(vpos1, vpos3, 20) - 0.5
<< " " << hpos3 << " " << dir
<< " 0 0 " << 11 << " " << hpos2 << " " << hpos3;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
case 1: case 3:
if (voice == 1) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
vpos3 = Convert::base40ToScoreVPos(pitch3, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
vpos3 = Convert::base40ToScoreVPos(pitch3, 0);
}
dir = 11;
if (vpos2 > vpos1 && vpos2 > vpos3) {
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamEnd(vpos1, vpos3, 10) + 0.5
<< " "
<< getBeamEnd(vpos1, vpos3, 10) + 0.5
<< " " << hpos3 << " " << dir
<< " 0 0 " << 11 << " " << hpos2 << " " << hpos3;
} else {
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos3, 10)
<< " "
<< getBeamEnd(vpos1, vpos3, 10) + 0.5
<< " " << hpos3 << " " << dir
<< " 0 0 " << 11 << " " << hpos2 << " " << hpos3;
}
if (offsets[voice][startbeat] > 0.0) {
output << " 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
}
}
//////////
// beam two sixteenths and one eighth note together
else if ((durs.getSize() == 3) && (durs[0] == 0.25) &&
(durs[1] == 0.25) && (durs[2] == 0.5) && fraction == 0.0) {
hpos1 = getHpos(infile, index[startbeat]);
hpos2 = getHpos(infile, index[startbeat+1]);
hpos3 = getHpos(infile, index[endbeat]);
pitch1 = Convert::kernToBase40(infile[index[startbeat]][voice]);
pitch2 = Convert::kernToBase40(infile[index[startbeat+1]][voice]);
pitch3 = Convert::kernToBase40(infile[index[endbeat]][voice]);
switch (voice) {
case 0: case 2:
if (voice == 0) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
vpos3 = Convert::base40ToScoreVPos(pitch3, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
vpos3 = Convert::base40ToScoreVPos(pitch3, 0);
}
dir = 21;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos3, 20)
<< " "
<< getBeamEnd(vpos1, vpos3, 20) - 0.5
<< " " << hpos3 << " " << dir
<< " 0 0 " << 11 << " " << hpos1 << " " << hpos2;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
case 1: case 3:
if (voice == 1) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
vpos3 = Convert::base40ToScoreVPos(pitch3, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
vpos3 = Convert::base40ToScoreVPos(pitch3, 0);
}
dir = 11;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos3, 10)
<< " "
<< getBeamEnd(vpos1, vpos3, 10) + 0.5
<< " " << hpos3 << " " << dir
<< " 0 0 " << 11 << " " << hpos1 << " " << hpos2;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
}
}
//////////
// beam dotted eight and sixteenth
else if ((durs.getSize() == 2) && (durs[0] == 0.75) && (durs[1] == 0.25)
&& fraction == 0.0) {
hpos1 = getHpos(infile, index[startbeat]);
hpos2 = getHpos(infile, index[endbeat]);
pitch1 = Convert::kernToBase40(infile[index[startbeat]][voice]);
pitch2 = Convert::kernToBase40(infile[index[endbeat]][voice]);
switch (voice) {
case 0: case 2:
if (voice == 0) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 21;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 20)
<< " "
<< getBeamEnd(vpos1, vpos2, 20)
<< " " << hpos2 << " " << dir << " 0 0 "
<< 11 << " 0 " << hpos2;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
case 1: case 3:
if (voice == 1) {
vpos1 = Convert::base40ToScoreVPos(pitch1, 1);
vpos2 = Convert::base40ToScoreVPos(pitch2, 1);
} else {
vpos1 = Convert::base40ToScoreVPos(pitch1, 0);
vpos2 = Convert::base40ToScoreVPos(pitch2, 0);
}
dir = 11;
output << "6 " << voice+1 << " " << hpos1 << " "
<< getBeamStart(vpos1, vpos2, 10)
<< " "
<< getBeamEnd(vpos1, vpos2, 10)
<< " " << hpos2 << " " << dir << " 0 0 "
<< 11 << " 0 " << hpos2;
if (offsets[voice][startbeat] > 0.0) {
output << " 0 " << offsets[voice][startbeat];
if (offsets[voice][endbeat] > 0.0) {
output << " " << offsets[voice][endbeat];
}
} else if (offsets[voice][endbeat] > 0.0) {
output << " 0 0 " << offsets[voice][endbeat];
}
output << "\n";
break;
}
}
}
//////////////////////////////
//
// getHpos -- return the horizontal postion of an item in the score
//
double getHpos(HumdrumFile& infile, int line, double start, double ending) {
static double startDur = -1;
static double endDur = -1;
if (startDur < 0) {
startDur = start;
}
if (endDur < 0) {
endDur = ending;
}
if (start >= 0.0) {
startDur = start;
}
if (ending >= 0.0) {
endDur = ending;
}
double beatwidth = endDur - startDur;
double output;
output = (infile[line].getAbsBeat() - startDur) / beatwidth * 190 + 10;
output = ((int)(output*100.0 + 0.5))/100.0;
return output;
// originally:
// output = infile[line].getAbsBeat() / infile.getTotalDuration() * 190 + 10;
// output = ((int)(output*100.0 + 0.5))/100.0;
}
//////////////////////////////
//
// getBeamStart --
//
double getBeamStart(double vpos1, double vpos2, int dir) {
double upbeam1[23][23] = {{0, 0, 0, 0, 0, 0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{0, 0, 0, 0, 0, 0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{0, 0, 0, 0, 0, 0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{0, 0, 0, 0, 0, 0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{1, 1, 1, 1, 1, 1, 1.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{2, 2, 2, 2, 2, 2, 2, 2.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{2, 2, 2, 2, 3, 3, 3, 3, 3.5, 3.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{3, 3, 3, 3, 3, 4, 4, 4, 4, 4.5, 4.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5.5, 5.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6.5, 6.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7.5, 7.5, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{7, 7, 7, 7, 7, 7, 7, 7, 7, 7.5, 7.5, 7.5, 7.5, 7.75, 7.75, 8.25, 9, 10, 11, 12, 13, 14, 15},
{8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8, 8, 8, 8, 8.25, 8.25, 9, 10, 11, 12, 13, 14, 15},
{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8.5, 8.5, 9, 8.5, 9, 9, 10, 11, 12, 13, 14, 15},
{9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 9.5, 10, 10, 11, 12, 13, 14, 15},
{10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 10.5, 11, 11, 12, 13, 14, 15},
{11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 11.5, 12, 12, 13, 14, 15},
{12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 12.5, 13, 13, 14, 15},
{13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 13.5, 14, 14, 15},
{14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 14.5, 15, 15},
{15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 15.5, 16},
{16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5, 16.5},
{17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5, 17.5}};
double downbeam1[23][23] = {{-1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5, -1.5},
{-0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5},
{0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5},
{1, 1, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5},
{1, 1.5, 1.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5},
{1, 1.5, 2.5, 2.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5},
{1, 1.5, 2.5, 3.5, 3.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5},
{1, 1.5, 2.5, 3.5, 4.5, 4.5, 5.5, 5, 5.5, 5.5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 5.5, 6, 6, 6, 6, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6, 6.5, 6.5, 6.5, 6.5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 6.5, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14},
{1, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 8, 9, 10, 11, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14}};
if (vpos1 < -3 || vpos2 < -3 || vpos1 > 22 || vpos2 > 22) {
return vpos1;
}
switch (dir) {
case 10: return upbeam1[(int)vpos1+3][(int)vpos2+3];
case 20: return downbeam1[(int)vpos1+3][(int)vpos2+3];
}
return vpos1;
}
//////////////////////////////
//
// getBeamEnd --
//
double getBeamEnd(double vpos1, double vpos2, int dir) {
double upbeam2[23][23] = {{0, 0, 0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{0, 0, 0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{0, 0, 0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{0, 0, 0, 0, 1, 2, 2, 3, 4, 5, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{0, 0, 0, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{0.5, 0.5, 0.5, 0.5, 1, 2, 3, 4, 4, 5, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{0.5, 0.5, 0.5, 0.5, 1.5, 2, 3, 4, 5, 5, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{1.5, 1.5, 1.5, 1.5, 1.5, 2.5, 3, 4, 5, 6, 6, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 3.5, 4, 5, 6, 7, 7, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 4.5, 5, 6, 7, 7.5, 8.5, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 5.5, 6, 7, 7.5, 8, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 6.5, 7, 7.5, 8, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 7.5, 7.5, 8, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.5, 7.75, 8, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{7.75, 7.75, 7.75, 7.75, 7.75, 7.75, 7.75, 7.75, 7.75, 7.75, 7.75, 7.75, 8.25, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 8.25, 9, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5},
{12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13.5, 14.5, 15.5, 16.5, 17.5},
{13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14.5, 15.5, 16.5, 17.5},
{14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15.5, 16.5, 17.5},
{15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16.5, 17.5}};
double downbeam2[23][23] = {{-1.5, -0.5, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{-1.5, -0.5, 0.5, 1, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5},
{-1.5, -0.5, 0.5, 1.5, 1.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5, 2.5},
{-1.5, -0.5, 0.5, 1.5, 2.5, 2.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5, 3.5},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 3.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5, 4.5},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 4.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5, 5.5},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 5.5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 6, 6, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5, 6.5},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 6.5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6, 6.5, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 6, 6.5, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 6.5, 7, 8, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 7, 8, 9, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 8, 9, 10, 11, 11, 12, 12, 12, 12, 12, 12, 12},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 9, 10, 11, 12, 12, 13, 13, 13, 13, 13, 13},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 10, 11, 12, 13, 13, 13, 13, 13, 13, 13},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 11, 11, 12, 13, 14, 14, 14, 14, 14, 14},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14},
{-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5, 5.5, 7, 8, 9, 10, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14}};
if (vpos1 < -3 || vpos2 < -3 || vpos1 > 22 || vpos2 > 22) {
return vpos2;
}
switch (dir) {
case 10: return upbeam2[(int)vpos1+3][(int)vpos2+3];
case 20: return downbeam2[(int)vpos1+3][(int)vpos2+3];
}
return vpos2;
}
// md5sum: a5f8f916b2b688fc8807fa3e79714787 chor2scor.cpp [20121112]