// // Copyright 1998-2018 by Craig Stuart Sapp, All Rights Reserved. // Programmer: Craig Stuart Sapp // Creation Date: Mon May 18 13:52:59 PDT 1998 // Last Modified: Thu Jul 1 16:20:41 PDT 1999 // Last Modified: Thu Apr 13 18:34:28 PDT 2000 added generic interpretation // Last Modified: Fri May 5 13:12:21 PDT 2000 added sub-spine access // Last Modified: Fri Oct 13 12:45:45 PDT 2000 added spine tracing vars // Last Modified: Wed May 16 18:20:55 PDT 2001 added changeToken // Last Modified: Sun Mar 24 12:10:00 PST 2002 small changes for visual c++ // Last Modified: Wed Apr 3 08:13:29 PST 2002 allow DOS newline input // Last Modified: Mon May 17 12:46:36 PDT 2004 added getSpinePrediction // Last Modified: Wed Jun 2 15:50:13 PDT 2004 setSpineWidth adjusts interp // Last Modified: Tue Apr 21 10:02:00 PDT 2009 fixed comment prob. in setLine // Last Modified: Tue Apr 28 14:34:13 PDT 2009 added isTandem // Last Modified: Fri Jun 12 22:58:34 PDT 2009 renamed SigCollection class // Last Modified: Mon Jun 15 15:55:22 PDT 2009 fixed bug in getPrimaryTrack // Last Modified: Thu Jun 18 15:29:49 PDT 2009 modified getExInterp behavior // Last Modified: Thu Jun 18 15:57:53 PDT 2009 added hasSpines() // Last Modified: Mon Nov 23 14:30:35 PST 2009 fixed equalDataQ() // Last Modified: Sat May 22 10:29:39 PDT 2010 added RationalNumber // Last Modified: Sun Dec 26 12:18:34 PST 2010 added setToken // Last Modified: Mon Jul 30 16:10:45 PDT 2012 added setSize and setAllFields // Last Modified: Mon Dec 10 10:14:08 PST 2012 added Array getToken // Filename: ...sig/src/sigInfo/HumdrumRecord.cpp // Webpage: http://sig.sapp.org/src/sigInfo/HumdrumRecord.cpp // Syntax: C++ // // Description: Stores the data for one line in a HumdrumFile and // segments data into spines. // #include #include #include #include "Convert.h" #include "HumdrumRecord.h" #include "PerlRegularExpression.h" #include using namespace std; ////////////////////////////// // // HumdrumRecord::HumdrumRecord -- // HumdrumRecord::HumdrumRecord(void) { duration = 0.0; durationR.zero(); meterloc = 0.0; meterlocR.zero(); absloc = 0.0; abslocR.zero(); spinewidth = 0; type = E_unknown; recordString = new char[1]; recordString[0] = '\0'; modifiedQ = 0; lineno = -1; recordFields.allowGrowth(1); recordFields.setSize(32); recordFields.setGrowth(132); recordFields.setSize(0); interpretation.allowGrowth(1); interpretation.setSize(32); interpretation.setGrowth(132); interpretation.setSize(0); spineids.reserve(32); dotline.setSize(32); dotline.setGrowth(132); dotline.setSize(0); dotspine.setSize(32); dotspine.setGrowth(132); dotspine.setSize(0); } HumdrumRecord::HumdrumRecord(const char* aLine, int aLineNum) { duration = 0.0; durationR.zero(); meterloc = 0.0; meterlocR.zero(); absloc = 0.0; abslocR.zero(); spinewidth = 0; lineno = aLineNum; type = determineType(aLine); recordString = new char[1]; recordString[0] = '\0'; modifiedQ = 0; interpretation.allowGrowth(1); interpretation.setSize(32); interpretation.setGrowth(132); interpretation.setSize(0); recordFields.allowGrowth(1); recordFields.setSize(32); recordFields.setGrowth(132); recordFields.setSize(0); spineids.reserve(32); dotline.allowGrowth(1); dotline.setSize(0); dotline.setSize(32); dotline.setGrowth(132); dotspine.allowGrowth(1); dotspine.setSize(32); dotspine.setGrowth(132); dotspine.setSize(0); setLine(aLine); } HumdrumRecord::HumdrumRecord(const HumdrumRecord& aRecord) { duration = aRecord.duration; durationR= aRecord.durationR; meterloc = aRecord.meterloc; meterlocR= aRecord.meterlocR; absloc = aRecord.absloc; abslocR = aRecord.abslocR; spinewidth = aRecord.spinewidth; type = aRecord.type; lineno = aRecord.lineno; recordString = new char[strlen(aRecord.recordString)+1]; strcpy(recordString, aRecord.recordString); modifiedQ = aRecord.modifiedQ; interpretation.allowGrowth(); interpretation.setSize(aRecord.interpretation.getSize()); recordFields.allowGrowth(); recordFields.setSize(aRecord.recordFields.getSize()); spineids.resize(aRecord.spineids.size()); dotline.setSize(aRecord.dotline.getSize()); dotspine.setSize(aRecord.dotspine.getSize()); int i; for (i=0; i& info, int line) { int size = (int)info.size(); if (size != getFieldCount()) { cout << "Error: new spine information is not the right size" << endl; for (int i=0; i 0) { strncpy(buffer, recordFields[0]+3, maxsize); } else { strcpy(buffer, recordFields[0]+3); } int i; int length = strlen(buffer); for (i=0; i version // char* HumdrumRecord::getBibKey(Array& buffer) { if (!isBibliographic()) { buffer.setSize(1); buffer[0] = '\0'; return buffer.getBase(); } int length = strlen(recordFields[0]+3); buffer.setSize(length+1); int i; for (i=0; i=0; j++) { if (std::isspace(buffer[j])) { buffer[j] = '\0'; } else { break; } } return buffer; } } */ buffer[0] = '\0'; return buffer; } // // Array version // char* HumdrumRecord::getBibValue(Array& buffer) { if (!isBibliographic()) { buffer.setSize(1); buffer[0] = '\0'; return buffer.getBase(); } PerlRegularExpression pre; int length; if (pre.search(recordString, "^!!![^:]+:\\s*(.*)\\s*$", "")) { length = strlen(pre.getSubmatch(1)); buffer.setSize(length+1); strcpy(buffer.getBase(), pre.getSubmatch()); return buffer.getBase(); } buffer.setSize(1); buffer[0] = '\0'; return buffer.getBase(); } ////////////////////////////// // // HumdrumRecord::getAbsBeat -- returns the absolute beat location // in the file. This value is by default 0, but can be set // manally with the setAbsBeat() function, or by calling // HumdrumFile::analyzeRhythm(). abslocR() returns the rational // value of the absolute beat. // double HumdrumRecord::getAbsBeat(void) const { return abslocR.getFloat(); } RationalNumber HumdrumRecord::getAbsBeatR(void) const { return abslocR; } ////////////////////////////// // // HumdrumRecord::getDotLine -- return the line to which a "." // value is place holding. // int HumdrumRecord::getDotLine(int index) { return dotline[index]; } ////////////////////////////// // // HumdrumRecord::getDotSpine -- return the spine to which a "." // value is place holding. // int HumdrumRecord::getDotSpine(int index) { return dotspine[index]; } ////////////////////////////// // // HumdrumRecord::getBeat -- returns the metrical beat location // in the file. This value is by default 0, but can be set // manally with the setBeat() function, or by calling // HumdrumFile::analyzeRhythm(). // double HumdrumRecord::getBeat(void) const { return meterlocR.getFloat(); } RationalNumber HumdrumRecord::getBeatR(void) const { return meterlocR; } ////////////////////////////// // // HumdrumRecord::getMeasureDuration -- returns the duration of a measure in // terms of quarter notes. This value is by default 0, but can be set // manally with the setBeat() function, or by calling // HumdrumFile::analyzeRhythm(). Returns 0 if the HumdrumRecord is not // a barline. // double HumdrumRecord::getMeasureDuration(void) const { if (!isBarline()) { return 0; } return meterlocR.getFloat(); } RationalNumber HumdrumRecord::getMeasureDurationR(void) const { RationalNumber zero(0,1); if (!isBarline()) { return zero; } return meterlocR; } ////////////////////////////// // // HumdrumRecord::getDuration -- returns the duration of the current // HumdrumRecord line in a HumdrumFile. This value is by default 0, // but can be set manally with the setAbsBeat() function, or by // calling HumdrumFile::analyzeRhythm(). // double HumdrumRecord::getDuration(void) const { return durationR.getFloat(); } RationalNumber HumdrumRecord::getDurationR(void) const { return durationR; } ////////////////////////////// // // HumdrumRecord::getExInterpNum -- returns the exclusive interpretation // enumeration assigned to the given data field. // int HumdrumRecord::getExInterpNum(int index) const { if (index >= interpretation.getSize()) { cout << "Error: accessing too large a spine field number A: " << index << endl; exit(1); } return interpretation[index]; } ////////////////////////////// // // HumdrumRecord::getExInterp -- returns the exclusive interpretation // name assigned to the given data field, such as "**kern". // If you ask for the exclusive interpretation of a non-spine // data line, an empty string will be returned. // const char* HumdrumRecord::getExInterp(int index) const { if (index >= interpretation.getSize()) { if(interpretation.getSize() == 0) { // return "" for lines such as Global Comments which are // not spine specific. return ""; } else { cout << "Error: accessing too large a spine field number B: " << index << endl;; cout << "Size of interpretation list: " << interpretation.getSize() << endl; cout << "But you tried to access index: " << index << endl; if (recordString != NULL) { cout << "Line is: " << recordString << endl; } exit(1); } } return Convert::exint.getName(interpretation[index]); } ////////////////////////////// // // HumdrumRecord::getFieldCount -- returns the number of data // fields in the record. // int HumdrumRecord::getFieldCount(void) const { return recordFields.getSize(); } int HumdrumRecord::getFieldCount(const char* exinterp) const { return getFieldCount(Convert::exint.getValue(exinterp)); } int HumdrumRecord::getFieldCount(int exinterp) const { int i; int count = 0; for (i=0; i& fields, const char* exinterp) { HumdrumRecord& aRecord = *this; fields.setSize(aRecord.getFieldCount()); fields.setSize(0); int i; for (i=0; i& tracks, const char* exinterp) { HumdrumRecord& aRecord = *this; tracks.setSize(aRecord.getFieldCount()); tracks.setSize(0); int i; int track; for (i=0; i 1) { output = output - vcount + 1; } return output; } ////////////////////////////// // // HumdrumRecord::getTrack -- returns 0 if invalid, // otherwise starts indexing at 1. // double HumdrumRecord::getTrack(int spineNumber) { const string& info = getSpineInfo(spineNumber); int i = 0; while (info[i] != '\0' && !std::isdigit(info[i])) { i++; } double output; int inttrack; sscanf(&info[i], "%d", &inttrack); output = inttrack; i++; int subtrack = 0; if (i < (int)info.size()) { i++; if (std::isalpha(info[i])) { subtrack = std::tolower(info[i]) - 'a'; output += subtrack/1000.0; } } return output; } ////////////////////////////// // // HumdrumRecord::getTrackColumn -- Search for the first column which contains // the matches the given track. Return -1 if no matching track found. // int HumdrumRecord::getTrackColumn(int track) { int i; int primarytrack; for (i=0; i= getFieldCount()) { return 0; } const string& info = getSpineInfo(spineNumber); int i = 0; while (info[i] != '\0' && !std::isdigit(info[i])) { i++; } int track = 0; if (!sscanf(&info[i], "%d", &track)) { track = 0; } return track; } ////////////////////////////// // // HumdrumRecord::getSpineInfo -- // const string& HumdrumRecord::getSpineInfo(int index) const { return spineids[index]; } ////////////////////////////// // // HumdrumRecord::getSpineWidth -- returns the number of spines // in the data at the current point in a Humdrum File. // Useful to know if trying to generate data during a // global comment or bibliographic record. // int HumdrumRecord::getSpineWidth(void) { return spinewidth; } ////////////////////////////// // // changeToken -- // default value: separator = ' ' // void HumdrumRecord::changeToken(int spineIndex, int tokenIndex, const char* newtoken, char separator) { HumdrumRecord& record = *this; char separatorstr[2] = {0}; separatorstr[0] = separator; char *buff; buff = new char[strlen(record[spineIndex]) + strlen(newtoken) + 1]; buff[0] = '\0'; char* oldtoken = strtok((char*)record[spineIndex], separatorstr); int token = 0; while (oldtoken != NULL) { if (token == tokenIndex) { strcat(buff, newtoken); } else { strcat(buff, oldtoken); } token++; oldtoken = strtok(NULL, separatorstr); if (oldtoken != NULL) { strcat(buff, separatorstr); } } delete [] recordFields[spineIndex]; recordFields[spineIndex] = buff; modifiedQ = 1; } ////////////////////////////// // // HumdrumRecord::getTokenCount -- returns the number of // tokens in the particular spine (1 + the number of spaces) // Default value: separator = ' '. // int HumdrumRecord::getTokenCount(int fieldIndex, char separator) { if (globalCommentQ() || nullQ()) { return 0; } if (localCommentQ() || interpretationQ()) { return 1; } int count = 1; const char* string = (*this)[fieldIndex]; int index = 0; while (string[index] != '\0') { if (string[index] == separator) { count++; } index++; } return count; } ////////////////////////////// // // HumdrumRecord::getToken -- returns the filled buffer. // Puts the specified subtoken into buffer, or null if // subtoken is null. If buffersize is positive, then // do not add more than buffersize characters to buffer. // Default values: buffersize = -1, separator = ' '. // char* HumdrumRecord::getToken(char* buffer, int fieldIndex, int tokenIndex, int buffersize, char separator) { if (buffersize < 1) { buffersize = 0x7fffffff; } char sepstring[2]; sepstring[0] = separator; sepstring[1] = '\0'; int location = 0; const char* string = (*this)[fieldIndex]; // char temp[strlen(string) + 1]; // can't do in MS Visual C++ 6.0 static char temp[1024] = {0}; // doing this instead strcpy(temp, string); char *current = NULL; current = strtok(temp, sepstring); while (current != NULL && location < tokenIndex) { current = strtok(NULL, sepstring); location++; } if (current == NULL) { buffer[0] = '\0'; return buffer; } int length = strlen(current); if (length > buffersize) { length = buffersize - 1; } int i; for (i=0; i& buffer, int fieldIndex, int tokenIndex, int buffersize, char separator) { HumdrumRecord& arecord = *this; int len = strlen(arecord[fieldIndex]) + 1 + 4; buffer.setSize(len); arecord.getToken(buffer.getBase(), fieldIndex, tokenIndex, len, separator); len = strlen(buffer.getBase()) + 1; buffer.setSize(len); return buffer.getBase(); } string& HumdrumRecord::getToken(string& buffer, int fieldIndex, int tokenIndex, int buffersize, char separator) { buffer.clear(); Array buffer2; getToken(buffer2, fieldIndex, tokenIndex, buffersize, separator); for (int i=0; i >& tokens, int fieldIndex, char separator) { char sep[2] = {0}; HumdrumRecord& arecord = *this; sep[0] = separator; PerlRegularExpression pre; pre.getTokens(tokens, sep, arecord[fieldIndex]); } void HumdrumRecord::getTokens(vector& tokens, int fieldIndex, char separator) { Array > xtokens; HumdrumRecord::getTokens(xtokens, fieldIndex, separator); tokens.resize(0); string tok; for (int i=0; i > notes; pre.getTokens(notes, " ", (*this)[field]); int i; for (i=0; i\\[[^]]*\\]$" int HumdrumRecord::isLabelExpansion(int index) { HumdrumRecord& aRecord = *this; PerlRegularExpression pre; if (pre.search(aRecord[index], REGEX_ISLABELEXPANSION)) { return 1; } return 0; } int HumdrumRecord::isAllLabelExpansion(void) { return HumdrumRecord::isParticularType(REGEX_ISLABELEXPANSION, "**kern"); } ////////////////////////////// // // HumdrumRecord::isLabelVariant -- // #define REGEX_ISLABELVARIANT "^\\*>[^[]+\\[[^]]*\\]$" int HumdrumRecord::isLabelVariant(int index) { HumdrumRecord& aRecord = *this; PerlRegularExpression pre; if (pre.search(aRecord[index], REGEX_ISLABELVARIANT)) { return 1; } return 0; } int HumdrumRecord::isAllLabelVariant(void) { return HumdrumRecord::isParticularType(REGEX_ISLABELVARIANT, "**kern"); } ////////////////////////////// // // HumdrumRecord::isLabelMarker -- // #define REGEX_ISLABELMARKER "^\\*>[^[]+$" int HumdrumRecord::isLabelMarker(int index) { HumdrumRecord& aRecord = *this; PerlRegularExpression pre; if (pre.search(aRecord[index], REGEX_ISLABELMARKER)) { return 1; } return 0; } int HumdrumRecord::isAllLabelMarker(void) { return HumdrumRecord::isParticularType(REGEX_ISLABELMARKER, "**kern"); } ////////////////////////////// // // HumdrumRecord::isStaffNumber -- // #define REGEX_ISSTAFFNUMBER "^\\*staff\\d" int HumdrumRecord::isStaffNumber(int index) { HumdrumRecord& aRecord = *this; PerlRegularExpression pre; if (pre.search(aRecord[index], REGEX_ISSTAFFNUMBER)) { return 1; } return 0; } int HumdrumRecord::isAllStaffNumber(void) { return HumdrumRecord::isParticularType(REGEX_ISSTAFFNUMBER, "**kern"); } ////////////////////////////// // // HumdrumRecord::isSysStaffNumber -- Andreas's variant on staff numbering // which is local to a particular system on a specific page. // #define REGEX_ISSYSSTAFFNUMBER "^\\*staff:\\d" int HumdrumRecord::isSysStaffNumber(int index) { HumdrumRecord& aRecord = *this; PerlRegularExpression pre; if (pre.search(aRecord[index], REGEX_ISSYSSTAFFNUMBER)) { return 1; } return 0; } int HumdrumRecord::isAllSysStaffNumber(void) { return HumdrumRecord::isParticularType(REGEX_ISSYSSTAFFNUMBER, "**kern"); } ////////////////////////////// // // HumdrumRecord::isNull -- true if all fields are ".", "!", or "*". // int HumdrumRecord::isNull(void) { const char* target = ""; HumdrumRecord& aRecord = *this; if (aRecord.isData()) { target = "."; } else if (aRecord.isLocalComment()) { target = "!"; } else if (aRecord.isInterpretation()) { target = "*"; } if (strlen(target) == 0) { // Global comments like "!!" with nothing after them // might be good to call a NULL, but not for now. return 0; } int j; for (j=0; j=0; i--) { if (i >= index) { recordFields[i+1] = recordFields[i]; spineids[i+1] = spineids[i]; interpretation[i+1] = interpretation[i]; } else { break; } } // add the field interpretation[index] = anInterp; recordFields[index] = new char[strlen(aField)+1]; strcpy(recordFields[index], aField); spineids[index] = spinetrace; int dummy = -1; dotline.append(dummy); dotspine.append(dummy); modifiedQ = 1; } void HumdrumRecord::insertField(int index, const char* aField, const char* anInterp, const char* spinetrace) { int interptype = Convert::exint.getValue(anInterp); if (interptype == E_unknown || interptype == E_UNKNOWN_EXINT) { Convert::exint.add(anInterp); } interpretation[index] = Convert::exint.getValue(anInterp); insertField(index, aField, interptype, spinetrace); } ////////////////////////////// // // HumdrumRecord::operator= -- // HumdrumRecord& HumdrumRecord::operator=(const HumdrumRecord& aRecord) { // don't copy onto self if (&aRecord == this) { return *this; } duration = aRecord.duration; durationR= aRecord.durationR; meterloc = aRecord.meterloc; meterlocR= aRecord.meterlocR; absloc = aRecord.absloc; abslocR = aRecord.abslocR; int i; type = aRecord.type; if (recordString != NULL) { delete [] recordString; recordString = NULL; } if (aRecord.recordString != NULL) { recordString = new char[strlen(aRecord.recordString)+1]; strcpy(recordString, aRecord.recordString); } modifiedQ = aRecord.modifiedQ; interpretation.setSize(aRecord.interpretation.getSize()); for (i=0; i 0) { interpretation[i] = aRecord.interpretation[i]; } allocSize = strlen(aRecord.recordFields[i]) + 1; recordFields[i] = new char[allocSize]; strcpy(recordFields[i], aRecord.recordFields[i]); spineids[i] = aRecord.spineids[i]; } return *this; } HumdrumRecord& HumdrumRecord::operator=(const HumdrumRecord* aRecord) { *this = *aRecord; return *this; } HumdrumRecord& HumdrumRecord::operator=(const char* aLine) { duration = 0.0; durationR.zero(); meterloc = 0.0; meterlocR.zero(); absloc = 0.0; abslocR.zero(); setLine(aLine); return *this; } ////////////////////////////// // // HumdrumRecord::operator[] -- // const char* HumdrumRecord::operator[](int index) const { if (index > getFieldCount()) { cout << "Error trying to access invalid spine field: " << index << endl; exit(1); } return recordFields[index]; } ////////////////////////////// // // HumdrumRecord::setAbsBeat -- sets the absolute beat location // in the file. This value is by default 0, but can be set // manally with the setAbsBeat() function, or by calling // HumdrumFile::analyzeRhythm(). // void HumdrumRecord::setAbsBeat(double aValue) { cerr << "ERROR not allowed to use HumdrumRecord::setAbsBeat at the moment" << endl; absloc = (float)aValue; // this function cannot co-exists with the following one // and will have to be removed. } void HumdrumRecord::setAbsBeat(const RationalNumber& aValue) { abslocR = aValue; absloc = abslocR.getFloat(); } void HumdrumRecord::setAbsBeatR(const RationalNumber& aValue) { abslocR = aValue; absloc = abslocR.getFloat(); } void HumdrumRecord::setAbsBeatR(int top, int bottom) { abslocR.setValue(top, bottom); } void HumdrumRecord::setAbsBeat(int top, int bottom) { abslocR.setValue(top, bottom); } ////////////////////////////// // // HumdrumRecord::setBeat -- sets the metrical beat location // in the file. This value is by default 0, but can be set // manally with the setBeat() function, or by calling // HumdrumFile::analyzeRhythm(). // void HumdrumRecord::setBeat(double aValue) { cerr << "ERROR not allowed to use HumdrumRecord::setBeat at the moment" << endl; meterloc = (float)aValue; } void HumdrumRecord::setBeat(int top, int bottom) { meterlocR.setValue(top, bottom); } void HumdrumRecord::setBeatR(int top, int bottom) { meterlocR.setValue(top, bottom); } void HumdrumRecord::setBeat(const RationalNumber& aValue) { meterlocR = aValue; } void HumdrumRecord::setBeatR(const RationalNumber& aValue) { meterlocR = aValue; } ////////////////////////////// // // HumdrumRecord::setDotLine -- set place holding value line location. // void HumdrumRecord::setDotLine(int index, int value) { dotline[index] = value; } ////////////////////////////// // // HumdrumRecord::setDotSpine -- set place holding value spine location. // void HumdrumRecord::setDotSpine(int index, int value) { dotspine[index] = value; } ////////////////////////////// // // HumdrumRecord::setDuration -- sets the duration of the current // HumdrumRecord line in a HumdrumFile. This value is by default 0, // but can be set manally with the setAbsBeat() function, or by // calling HumdrumFile::analyzeRhythm(). // void HumdrumRecord::setDuration(double aValue) { cerr << "Error: not allowed to use HumdrumRecord::setDuration at the moment" << endl; duration = (float)aValue; } void HumdrumRecord::setDuration(int top, int bottom) { durationR.setValue(top, bottom); } void HumdrumRecord::setDuration(RationalNumber aValue) { durationR = aValue; } void HumdrumRecord::setDurationR(int top, int bottom) { durationR.setValue(top, bottom); } void HumdrumRecord::setDurationR(RationalNumber aValue) { durationR = aValue; } ////////////////////////////// // // HumdrumRecord::setExInterp -- assigns the exclusive interpretation // to the specified data field. // void HumdrumRecord::setExInterp(int index, int anInterpretation) { if (index >= interpretation.getSize()) { cout << "Error: accessing too large a field number A: " << index << " in line: " << getLine() << endl; cout << "Size of record: " << getFieldCount() << endl; cout << "Size of interpretation array: " << interpretation.getSize() << endl; exit(1); } interpretation[index] = anInterpretation; } void HumdrumRecord::setExInterp(int index, const char* interpString) { if (index >= interpretation.getSize()) { cout << "Error: accessing too large a field number B: " << index << " in line: " << getLine() << endl; cout << "Size of interpretation list: " << interpretation.getSize() << endl; cout << "But you tried to access index: " << index << endl; exit(1); } int interptype = Convert::exint.getValue(interpString); if (interptype == E_unknown || interptype == E_UNKNOWN_EXINT) { Convert::exint.add(interpString); } interpretation[index] = Convert::exint.getValue(interpString); } ////////////////////////////// // // HumdrumRecord::setToken -- // void HumdrumRecord::setToken(int index, const char* aString) { delete [] recordFields[index]; int len = strlen(aString); recordFields[index] = new char[len+1]; strcpy(recordFields[index], aString); modifiedQ = 1; } void HumdrumRecord::setToken(int index, const string& aString) { HumdrumRecord::setToken(index, aString.c_str()); } ////////////////////////////// // // HumdrumRecord::setLine -- sets the record to a (new) string // void HumdrumRecord::setLine(const char* aLine) { if (recordString != NULL) { delete [] recordString; recordString = NULL; } int length = strlen(aLine); recordString = new char[length+1]; strcpy(recordString, aLine); if (recordString[length-1] == 0x0d || recordString[length-1] == 0x0a) { recordString[length-1] = '\0'; } modifiedQ = 0; int i; if (recordFields.getSize() != 0) { for (i=0; i= 0) { int oldsize = spinewidth; spinewidth = aSize; interpretation.setSize(spinewidth); int i; if (oldsize > spinewidth) { for (i=oldsize; i temp; output = getBibliographicMeaning(temp, code.c_str()); return output; } const char* HumdrumRecord::getBibliographicMeaning(Array& output, const char* code) { int atcount = 0; char langbuf[128] = {0}; char keybuf[128] = {0}; // check for @ signs which indicate language of bibliographic value. int len = strlen(code); if (len > 100) { return "ERROR: Bibliographic key is too long."; } PerlRegularExpression pre; pre.search(code, "([a-z]+)(\\d*)(@*)([a-z]*)", "i"); strcpy(langbuf, pre.getSubmatch(4)); strcpy(keybuf, pre.getSubmatch(1)); atcount = strlen(pre.getSubmatch(3)); int numberfound = 0; float number = 2357911.131719; if (strlen(pre.getSubmatch(2)) > 0) { numberfound = 1; number = strtol(pre.getSubmatch(2), NULL, 10); } stringstream description; if (strcmp(keybuf, "ACO") == 0) { description << "Analytic collection"; } else if (strcmp(keybuf, "AFR") == 0) { description << "Form designation"; } else if (strcmp(keybuf, "AGN") == 0) { description << "Genre designation"; } else if (strcmp(keybuf, "AIN") == 0) { description << "Instrumentation"; } else if (strcmp(keybuf, "AMD") == 0) { description << "Mode designation"; } else if (strcmp(keybuf, "AMT") == 0) { description << "Metric classification"; } else if (strcmp(keybuf, "ARE") == 0) { description << "Geographical region"; } else if (strcmp(keybuf, "ARL") == 0) { description << "Geographical location of origin"; } else if (strcmp(keybuf, "AST") == 0) { description << "Style, period, or type of work designation"; } else if (strcmp(keybuf, "ASW") == 0) { description << "Associated work"; // C = Composer related codes } else if (strcmp(keybuf, "CDT") == 0) { description << "Composer's dates"; } else if (strcmp(keybuf, "CNT") == 0) { description << "Composer's nationality"; } else if (strcmp(keybuf, "COA") == 0) { description << "Attributed composer"; } else if (strcmp(keybuf, "COC") == 0) { description << "Composer's corporate name"; } else if (strcmp(keybuf, "COL") == 0) { description << "Stage name, alias"; } else if (strcmp(keybuf, "COM") == 0) { description << "Composer's name"; } else if (strcmp(keybuf, "COS") == 0) { description << "Suspected composer"; // E = Edition related codes } else if (strcmp(keybuf, "EED") == 0) { description << "Electronic editor"; } else if (strcmp(keybuf, "EEV") == 0) { description << "Electronic edition version"; } else if (strcmp(keybuf, "EFL") == 0) { description << "File number"; } else if (strcmp(keybuf, "EMD") == 0) { description << "Document modification description"; } else if (strcmp(keybuf, "ENC") == 0) { description << "Music encoder"; } else if (strcmp(keybuf, "END") == 0) { description << "Initial enc. date"; } else if (strcmp(keybuf, "EST") == 0) { description << "Encoding status"; // G = Group related codes } else if (strcmp(keybuf, "GCO") == 0) { description << "Collection designation"; } else if (strcmp(keybuf, "GNM") == 0) { description << "Group number"; } else if (strcmp(keybuf, "GTL") == 0) { description << "Group title"; } else if (strcmp(keybuf, "GAW") == 0) { description << "Associated work"; } else if (strcmp(keybuf, "HAO") == 0) { description << "Aural history"; } else if (strcmp(keybuf, "HTX") == 0) { description << "Translation of vocal text"; // L = Lyrics related codes } else if (strcmp(keybuf, "LAR") == 0) { description << "Arranger"; } else if (strcmp(keybuf, "LDT") == 0) { description << "Lyric Date"; } else if (strcmp(keybuf, "LIB") == 0) { description << "Librettist"; } else if (strcmp(keybuf, "LOR") == 0) { description << "Orchestrator"; } else if (strcmp(keybuf, "LYR") == 0) { description << "Lyricist"; // M = Performance related codes } else if (strcmp(keybuf, "MCN") == 0) { description << "Conductor's name"; } else if (strcmp(keybuf, "MLC") == 0) { description << "Performance location"; } else if (strcmp(keybuf, "MPD") == 0) { description << "Date of first performance"; } else if (strcmp(keybuf, "MPN") == 0) { description << "Performer's name"; } else if (strcmp(keybuf, "MPS") == 0) { description << "Suspected performer"; } else if (strcmp(keybuf, "MRD") == 0) { description << "Date of performance"; // O = Work (opus) related codes } else if (strcmp(keybuf, "OAC") == 0) { description << "Act number"; } else if (strcmp(keybuf, "OCL") == 0) { description << "Collector's name"; } else if (strcmp(keybuf, "OCO") == 0) { description << "Commission"; } else if (strcmp(keybuf, "OCY") == 0) { description << "Country of composition"; } else if (strcmp(keybuf, "ODE") == 0) { description << "Dedication"; } else if (strcmp(keybuf, "ODT") == 0) { description << "Date of composition"; } else if (strcmp(keybuf, "OKY") == 0) { description << "Key"; } else if (strcmp(keybuf, "OMD") == 0) { description << "Movement designation"; } else if (strcmp(keybuf, "OMV") == 0) { description << "Movement number"; } else if (strcmp(keybuf, "ONB") == 0) { description << "Free format note"; } else if (strcmp(keybuf, "ONM") == 0) { description << "Number"; } else if (strcmp(keybuf, "OPC") == 0) { description << "City of composition"; } else if (strcmp(keybuf, "OPR") == 0) { description << "Title of parent work"; } else if (strcmp(keybuf, "OPS") == 0) { description << "Opus number"; } else if (strcmp(keybuf, "OPT") == 0) { description << "Parent work"; } else if (strcmp(keybuf, "OSC") == 0) { description << "Scene number"; } else if (strcmp(keybuf, "OTA") == 0) { description << "Alternative title"; } else if (strcmp(keybuf, "OTL") == 0) { description << "Title"; } else if (strcmp(keybuf, "OTP") == 0) { description << "Popular title"; } else if (strcmp(keybuf, "OVM") == 0) { description << "Volume"; // P = Publisher related codes } else if (strcmp(keybuf, "PC#") == 0) { description << "Publisher's cat. num."; } else if (strcmp(keybuf, "PDT") == 0) { description << "Date first published"; } else if (strcmp(keybuf, "PPG") == 0) { description << "Page"; } else if (strcmp(keybuf, "PPG") == 0) { description << "Publication page"; } else if (strcmp(keybuf, "PPP") == 0) { description << "Place first published"; } else if (strcmp(keybuf, "PPR") == 0) { description << "First publisher"; } else if (strcmp(keybuf, "PUB") == 0) { description << "Publication status"; // R = User related codes } else if (strcmp(keybuf, "RC#") == 0) { description << "Recording company's catalog number"; } else if (strcmp(keybuf, "RDF") == 0) { description << "User-defined signifiers"; } else if (strcmp(keybuf, "RDT") == 0) { description << "Date of recording"; } else if (strcmp(keybuf, "RLC") == 0) { description << "Recording location"; } else if (strcmp(keybuf, "RLN") == 0) { description << "ASCII language setting"; } else if (strcmp(keybuf, "RMM") == 0) { description << "Manufacturer or sponsoring company"; } else if (strcmp(keybuf, "RNB") == 0) { description << "Encoding note"; } else if (strcmp(keybuf, "RNP") == 0) { description << "Name of the producer"; } else if (strcmp(keybuf, "RRD") == 0) { description << "Date of release"; } else if (strcmp(keybuf, "RTL") == 0) { description << "Title of album"; } else if (strcmp(keybuf, "RT#") == 0) { description << "Track number"; } else if (strcmp(keybuf, "RWG") == 0) { description << "Representation warning"; // S = Scholarly/source related codes } else if (strcmp(keybuf, "SCA") == 0) { description << "Full cat. name"; } else if (strcmp(keybuf, "SCT") == 0) { description << "Scholarly cat. num."; } else if (strcmp(keybuf, "SMA") == 0) { description << "Acknowledgment of manuscript access"; } else if (strcmp(keybuf, "SML") == 0) { description << "Manuscript location"; } else if (strcmp(keybuf, "SMS") == 0) { description << "Manuscript source name"; } else if (strcmp(keybuf, "TRN") == 0) { description << "Translator of text"; } else if (strcmp(keybuf, "TXL") == 0) { description << "Language of the encoded text"; } else if (strcmp(keybuf, "TXO") == 0) { description << "Orignal language of text"; } else if (strcmp(keybuf, "VTS") == 0) { description << "Checksum validation number"; // X = translation related codes } else if (strcmp(keybuf, "XDE") == 0) { description << "Translated title (in German)"; } else if (strcmp(keybuf, "XEN") == 0) { description << "Translated title (in English)"; } else if (strcmp(keybuf, "XFR") == 0) { description << "Translated title (in French)"; } else if (strcmp(keybuf, "XNI") == 0) { description << "Translated title (in Japanese)"; } else if (strcmp(keybuf, "XAL") == 0) { description << "translated title in Albanian"; } else if (strcmp(keybuf, "XAB") == 0) { description << "translated title in Arabic"; } else if (strcmp(keybuf, "XAM") == 0) { description << "translated title in Armenian"; } else if (strcmp(keybuf, "XAZ") == 0) { description << "translated title in Azeri"; } else if (strcmp(keybuf, "XBE") == 0) { description << "translated title in Bengali"; } else if (strcmp(keybuf, "XBU") == 0) { description << "translated title in Bulgarian"; } else if (strcmp(keybuf, "XCB") == 0) { description << "translated title in Cambodian"; } else if (strcmp(keybuf, "XCA") == 0) { description << "translated title in Cantonese"; } else if (strcmp(keybuf, "XHR") == 0) { description << "translated title in Croatian"; } else if (strcmp(keybuf, "XCE") == 0) { description << "translated title in Czech"; } else if (strcmp(keybuf, "XDA") == 0) { description << "translated title in Danish"; } else if (strcmp(keybuf, "XNE") == 0) { description << "translated title in Dutch"; } else if (strcmp(keybuf, "XET") == 0) { description << "translated title in Estonian"; } else if (strcmp(keybuf, "XSU") == 0) { description << "translated title in Finnish"; } else if (strcmp(keybuf, "XFL") == 0) { description << "translated title in Flemish"; } else if (strcmp(keybuf, "XGA") == 0) { description << "translated title in Gaelic"; } else if (strcmp(keybuf, "XGR") == 0) { description << "translated title in Greek"; } else if (strcmp(keybuf, "XHB") == 0) { description << "translated title in Hebrew"; } else if (strcmp(keybuf, "XHI") == 0) { description << "translated title in Hindi"; } else if (strcmp(keybuf, "XHU") == 0) { description << "translated title in Hungarian"; } else if (strcmp(keybuf, "XIC") == 0) { description << "translated title in Icelandic"; } else if (strcmp(keybuf, "XIT") == 0) { description << "translated title in Italian"; } else if (strcmp(keybuf, "XJV") == 0) { description << "translated title in Javanese"; } else if (strcmp(keybuf, "XKO") == 0) { description << "translated title in Korean"; } else if (strcmp(keybuf, "XLI") == 0) { description << "translated title in Lithuanian"; } else if (strcmp(keybuf, "XLA") == 0) { description << "translated title in Latin"; } else if (strcmp(keybuf, "XLV") == 0) { description << "translated title in Latvian"; } else if (strcmp(keybuf, "XMG") == 0) { description << "translated title in Malayalam"; } else if (strcmp(keybuf, "XMA") == 0) { description << "translated title in Mandarin"; } else if (strcmp(keybuf, "XMO") == 0) { description << "translated title in Mongolian"; } else if (strcmp(keybuf, "XNO") == 0) { description << "translated title in Norwegian"; } else if (strcmp(keybuf, "XPL") == 0) { description << "translated title in Polish"; } else if (strcmp(keybuf, "XPR") == 0) { description << "translated title in Portuguese"; } else if (strcmp(keybuf, "XRU") == 0) { description << "translated title in Russian"; } else if (strcmp(keybuf, "XSR") == 0) { description << "translated title in Serbian"; } else if (strcmp(keybuf, "XSK") == 0) { description << "translated title in Slovak"; } else if (strcmp(keybuf, "XSN") == 0) { description << "translated title in Slovenian"; } else if (strcmp(keybuf, "XES") == 0) { description << "translated title in Spanish"; } else if (strcmp(keybuf, "XSW") == 0) { description << "translated title in Swahili"; } else if (strcmp(keybuf, "XSV") == 0) { description << "translated title in Swedish"; } else if (strcmp(keybuf, "XTA") == 0) { description << "translated title in Tamil"; } else if (strcmp(keybuf, "XTH") == 0) { description << "translated title in Thai"; } else if (strcmp(keybuf, "XTU") == 0) { description << "translated title in Turkish"; } else if (strcmp(keybuf, "XUK") == 0) { description << "translated title in Ukranian"; } else if (strcmp(keybuf, "XUR") == 0) { description << "translated title in Urdu"; } else if (strcmp(keybuf, "XVN") == 0) { description << "translated title in Vietnamese"; } else if (strcmp(keybuf, "XWE") == 0) { description << "translated title in Welsh"; } else if (strcmp(keybuf, "XHO") == 0) { description << "translated title in Xhosa"; } else if (strcmp(keybuf, "XZU") == 0) { description << "translated title in Zulu"; // Y = copyright related codes } else if (strcmp(keybuf, "YEC") == 0) { description << "Copyright notice"; } else if (strcmp(keybuf, "YED") == 0) { description << "Last edited"; } else if (strcmp(keybuf, "YEM") == 0) { description << "Copyright message"; } else if (strcmp(keybuf, "YEN") == 0) { description << "Country of copyright"; } else if (strcmp(keybuf, "YEP") == 0) { description << "Publisher of electronic edition"; } else if (strcmp(keybuf, "YER") == 0) { description << "Date electronic edition released"; } else if (strcmp(keybuf, "YOE") == 0) { description << "Editor of printed source"; } else if (strcmp(keybuf, "YOO") == 0) { description << "Original document owner"; } else if (strcmp(keybuf, "YOR") == 0) { description << "Original document"; } else if (strcmp(keybuf, "YOY") == 0) { description << "Original copyright year"; // non-standard bibliographic codes } else if (strcmp(keybuf, "IMGURL") == 0) { description << "Image URL"; } else if (strcmp(keybuf, "URL") == 0) { description << "URL"; } else if (strcmp(keybuf, "id") == 0) { description << "Database catalog number"; } else if (strcmp(keybuf, "isbn") == 0) { description << "ISBN"; } else if (strcmp(keybuf, "title") == 0) { description << "Title expansion directive"; } else if (strcmp(keybuf, "hum2abc") == 0) { description << "Humdrum to ABC+ options"; } else if (strcmp(keybuf, "catalog") == 0) { description << "Catalog number"; } else if (strcmp(keybuf, "tune") == 0) { description << "Tuning"; } else if (strcmp(keybuf, "rism") == 0) { description << "RISM number"; } else if (strcmp(keybuf, "meter") == 0) { description << "Meter(s)"; } else if (strcmp(keybuf, "ref") == 0) { description << "Reference note"; } else if (strcmp(keybuf, "minrhy") == 0) { description << "Smallest rhythmic unit"; } else if (strcmp(keybuf, "bem") == 0) { description << "EsAC Remark"; } else if (strcmp(keybuf, "cut[^a-z]?") == 0) { description << "EsAC Incipit"; } else if (strcmp(keybuf, "fkt") == 0) { description << "EsAC Function/Genre"; } else if (strcmp(keybuf, "fnt") == 0) { description << "EsAC Display font"; } else if (strcmp(keybuf, "key") == 0) { description << "EsAC KEY[] field"; } else if (strcmp(keybuf, "kkd") == 0) { description << "EsAC Source concordance"; } else if (strcmp(keybuf, "trd") == 0) { description << "EsAC Source"; } if (atcount == 1) { description << "; translation language: "; description << HumdrumRecord::getLanguageName(langbuf); } else if (atcount == 2) { description << "; original language: "; description << HumdrumRecord::getLanguageName(langbuf); } if (numberfound) { description << " [" << number << "]"; } description << ends; len = strlen(description.str().c_str()); output.setSize(len+1); strcpy(output.getBase(), description.str().c_str()); return output.getBase(); } ////////////////////////////// // // HumdrumRecord::getLanguageName -- given an ISO 639-2 or 639-1 // code, return the name of the language that it represents. // const char* HumdrumRecord::getLanguageName(const char* code) { char string[8] = {0}; strncpy(string, code, 3); int len = strlen(string); int i; for (i=0; i 3) || (len < 2)) { // don't know what to do with a long code, since 2 or three letter // code is expected return ""; } int i; for (i=0; i