// // Copyright 2002 by Craig Stuart Sapp, All Rights Reserved. // Programmer: Craig Stuart Sapp // Creation Date: Thu Feb 14 23:40:51 PST 2002 // Last Modified: Sun Mar 24 22:27:25 PST 2002 Changed reading of trailer // Last Modified: Tue Mar 26 00:52:54 PST 2002 Added staff access data // Last Modified: Tue Mar 31 16:14:05 PST 2009 Updates for winscore version // Last Modified: Fri Jun 12 22:58:34 PDT 2009 Renamed SigCollection class // Last Modified: Sun Aug 26 00:55:11 PDT 2012 Renovated // Filename: ...sig/src/sigInfo/ScorePageBase.h // Web Address: http://sig.sapp.org/include/sigInfo/ScorePageBase.h // Syntax: C++ // // Description: Base class for ScorePage. This class handles reading/writing // of a ScorePage, and handles all of the data variables for // a ScorePage (the main storage array and lots of analysis // arrays). // #include "ScorePageBase.h" #include #include #ifndef OLDCPP #include #include #include using namespace std; #else #include #include #include #endif typedef long TEMP64BITFIX; // Static class variables: double ScorePageBase::Lbuffer = 0.025; double ScorePageBase::Bbuffer = 0.0625; double ScorePageBase::StaffLen = 7.5; ////////////////////////////// // // ScorePageBase::ScorePageBase -- Constructors. // ScorePageBase::ScorePageBase(void) { // Initialize space for the main data array, set the allocation // size to 10,000 and the regrowth size to +100,000 if it exceeds // the initial allocation size. data.setSize(10000); data.setGrowth(100000); data.setSize(0); // clear all other variables clearAll(); } ScorePageBase::ScorePageBase(ScorePageBase& aPage) { data.setSize(10000); data.setGrowth(100000); data.setSize(0); ScorePageBase& thispage = *this; thispage = aPage; } ////////////////////////////// // // ScorePageBase::~ScorePageBase -- Destructor. // ScorePageBase::~ScorePageBase() { clearAll(); } ////////////////////////////// // // ScorePageBase::operator= -- Copying data from another ScorePageBase.. // ScorePageBase& ScorePageBase::operator=(ScorePageBase &aPage) { int i, j; if (this == &aPage) { return *this; // don't copy self } clear(); // (1) Main data storage: data.setSize(aPage.data.getSize()*2); // allocate extra for growing data.setSize(aPage.data.getSize()); data.setGrowth(1000000); for (i=0; i 0.0) { cout << "# Error in number parameter count: " << number << endl; exit(1); } } readcount += (int)number; data[data.getSize()]->readBinary(infile, (int)number); } } if (verboseQ) { cout << "#Elements: " << data.getSize() << endl; cout << "#READING Trailer: " << endl; } while (number != -9999.0 && !infile.eof()) { number = readLittleFloat(infile); trailer.append(number); if (verboseQ) { cout << "#TRAILER NUMBER: " << number << endl; } readcount++; } if (readcount != numbercount) { cerr << "#Warning: expecting " << numbercount << " number in file " << " but read " << readcount << endl; } } ////////////////////////////// // // ScorePageBase::readLittleShort -- read a short int in little endian form. // Number is read as an unsigned short int. // int ScorePageBase::readLittleShort(istream& input) { unsigned char byteinfo[2]; input.read((char*)byteinfo, 2); int output = 0; output = byteinfo[1]; output = (output << 8) | byteinfo[0]; return output; } ////////////////////////////// // // ScorePageBase::readLittleFloat -- Read a 4-byte float in little-endian // format. // float ScorePageBase::readLittleFloat(istream& instream) { unsigned char byteinfo[4]; instream.read((char*)byteinfo, 4); union { float f; unsigned int i; } num; num.i = 0; num.i = byteinfo[3]; num.i = (num.i << 8) | byteinfo[2]; num.i = (num.i << 8) | byteinfo[1]; num.i = (num.i << 8) | byteinfo[0]; return num.f; } ////////////////////////////// // // ScorePageBase::writeBinary -- Write SCORE data to a binary files. // void ScorePageBase::writeBinary(const char* filename) { #ifndef OLDCPP #ifdef VISUAL fstream outfile(filename, ios::out | ios::binary); #else fstream outfile(filename, ios::out); #endif #else #ifdef VISUAL fstream outfile(filename, ios::out | ios::noreplace | ios::binary); #else fstream outfile(filename, ios::out | ios::noreplace); #endif #endif if (!outfile.is_open()) { cerr << "Error: cannot write file: " << filename << endl; exit(1); } writeBinary(outfile); outfile.close(); } ////////////////////////////// // // ScorePageBase::writeBinary -- Write SCORE data to a binary output stream. // This function should be changed to write out in the print order // rather than the data order. // ostream& ScorePageBase::writeBinary(ostream& outfile) { float version = getVersion(); // first write the number of numbers in the data file. // use a dummy value of 0 for now char dummy[4] = {0}; if (version < 6) { outfile.write(dummy, 2); } else { outfile.write(dummy, 4); } int writecount = 0; // number of numbers which have been read int i; for (i=0; iwriteBinary(outfile); } // write the trailer for (i=trailer.getSize()-1; i>=0; i--) { writeLittleFloat(outfile, trailer[i]); writecount++; } // write the size of the trailer (plus one more for this field) writeLittleFloat(outfile, trailer.getSize() + 1); writecount++; // write the end of file marker writeLittleFloat(outfile, -9999.0); writecount++; if ((version < 6) && (writecount > 0x7fff)) { cerr << "Warning: data count (" << writecount << ") exceeds safe level" << endl; } // go back to the start of the file and fill in the number of numbers outfile.seekp(0); if (version < 6) { // write two byte counter unsigned char blo = writecount & 0xff; unsigned char bhi = (writecount >> 8) & 0xff; outfile.write((char*)&blo, 1); outfile.write((char*)&bhi, 1); } else { // write four-byte counter unsigned char bloest = writecount & 0xff; unsigned char bloer = (writecount >> 8) & 0xff; unsigned char bhier = (writecount >> 16) & 0xff; unsigned char bhiest = (writecount >> 24) & 0xff; outfile.write((char*)&bloest, 1); outfile.write((char*)&bloer, 1); outfile.write((char*)&bhier, 1); outfile.write((char*)&bhiest, 1); } return outfile; } ////////////////////////////// // // ScorePageBase::writeBinary2Byte -- Write a binary file using a 2-byte // number counter at the start of the file (the default method). // void ScorePageBase::writeBinary2Byte(const char* filename) { setVersion(3.0); writeBinary(filename); } ////////////////////////////// // // ScorePageBase::writeBinary4Byte -- Write a binary file using a 4-byte // number counter at the start of the file. This can be read by // WinScore (later versions of SCORE). It must be used if there are // more than 0xffff numbers (and 4-byte character chunks). // void ScorePageBase::writeBinary4Byte(const char* filename) { setVersion(6.0); writeBinary(filename); } ////////////////////////////// // // ScorePageBase::writeLittleFloat -- Write a 4-byte float in little-endian // format. // void ScorePageBase::writeLittleFloat(ostream& out, float number) { union { float f; unsigned int i; } num; num.f = number; char byteinfo[4]; byteinfo[0] = (char)( num.i & 0xff); byteinfo[1] = (char)((num.i >> 8) & 0xff); byteinfo[2] = (char)((num.i >> 16) & 0xff); byteinfo[3] = (char)((num.i >> 24) & 0xff); out.write(byteinfo, 4); } ////////////////////////////// // // ScorePageBase::printAscii -- Print data in PMX format for readable text. // default value: roundQ = 0 // default value: verboseQ = 0 // void ScorePageBase::printAscii(ostream& out, int roundQ, int verboseQ) { int i, j; if (verboseQ) { cout << "# OBJECTS TO WRITE: " << data.getSize() << endl; } Array > buffers; buffers.setSize(data.getSize() * 2); buffers.setSize(0); char buffer1[10000] = {0}; char buffer2[10000] = {0}; int index; Array spaces; spaces.setSize(10000); spaces.setAll(1); int length; for (i=0; iprintAscii(out, verboseQ); data[i]->printAscii(buffer1, buffer2, 10000, roundQ, verboseQ); index = buffers.getSize(); buffers.setSize(buffers.getSize()+1); length = strlen(buffer1); buffers[index].setSize(length+1); strcpy(buffers[index].getBase(), buffer1); for (j=0; j 0) { index = buffers.getSize(); buffers.setSize(buffers.getSize()+1); buffers[index].setSize(length+1); strcpy(buffers[index].getBase(), buffer2); } // out << '\n'; } for (i=0; i0) && (strchr(buffers[i-1].getBase(), 't') != NULL)) { out << buffers[i].getBase(); } else { for (j=0; j > buffers; buffers.setSize(data.getSize() * 2); buffers.setSize(0); Array bufferindex(data.getSize() * 2); bufferindex.setSize(0); char buffer1[10000] = {0}; char buffer2[10000] = {0}; int index; Array spaces; spaces.setSize(10000); spaces.setAll(1); int length; for (i=0; iprintAscii(buffer1, buffer2, 10000, roundQ, verboseQ); index = buffers.getSize(); buffers.setSize(buffers.getSize()+1); length = strlen(buffer1); bufferindex.append(i); buffers[index].setSize(length+1); strcpy(buffers[index].getBase(), buffer1); for (j=0; j 0) { index = buffers.getSize(); bufferindex.append(i); buffers.setSize(buffers.getSize()+1); buffers[index].setSize(length+1); strcpy(buffers[index].getBase(), buffer2); } // out << '\n'; } for (i=0; i0) && (strncmp(buffers[i-1].getBase(), "t", 1) == 0)) { out << buffers[i].getBase(); out << "\n"; data[bufferindex[i]]->printAsciiExtraParameters(out, roundQ, verboseQ); } else { for (j=0; jprintAsciiExtraParameters(out, roundQ, verboseQ); } } } out << flush; } // // Reading and Writing functions. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // // data accessor functions. // ////////////////////////////// // // ScorePageBase::getSize -- Returns the number of objects on the page. // This returns the size of the data array, or equivalently, the // printOrder array. // int ScorePageBase::getSize(void) { return data.getSize(); } ////////////////////////////// // // ScorePageBase::operator[] -- Accesses an object on the page in the order // in which it was read from a file (usually considered the printing order // for SCORE version 3 and less). // ScoreRecord& ScorePageBase::operator[](int index) { return *(data[index]); } ////////////////////////////// // // ScorePageBase::appendItem -- Add an item to the end of the main data array. // void ScorePageBase::appendItem(ScoreRecord& aRecord) { invalidateAnalyses(); data.increase(1); data.last() = new ScoreRecord; *(data.last()) = aRecord; } void ScorePageBase::appendItem(ScorePageBase& aPage) { int i; for (i=0; i& recs) { int i; for (i=0; i& recs) { int i; for (i=0; ishrink(); } } // // data accessor functions. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // // Trailer accessor functions. // ////////////////////////////// // // setVersion -- Set the SCORE version for writing in binary SCORE file. // void ScorePageBase::setVersion(float value) { trailer[trailer.getSize()-1-3] = value; } ////////////////////////////// // // ScorePageBase::setVersionWinScore -- set version to WinScore. // void ScorePageBase::setVersionWinScore(void) { trailer[trailer.getSize()-1-3] = 6.0; } ////////////////////////////// // // getVersion -- Get the SCORE version that was read from a binary SCORE file. // float ScorePageBase::getVersion(void) { return trailer[trailer.getSize()-1-3]; } ////////////////////////////// // // setSerial -- Set the SCORE serial number for writing in binary SCORE file. // void ScorePageBase::setSerial(long value) { union { long i; float f; } u; u.i = value; trailer[trailer.getSize()-1-4] = u.f; } ////////////////////////////// // // getSerial -- Get the SCORE serial number that was red from a binary SCORE // file. This value may be 0.0 if SCORE version 3 or less. // long ScorePageBase::getSerial(void) { union { long i; float f; } u; u.f = trailer[trailer.getSize()-1-4]; return u.i; } // // Trailer accessor functions. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // // Staff sorting-related functions. // ////////////////////////////// // // ScorePageBase::analyzeSort -- Process "data" array and sort for use // in pagePrintSequence and // // void ScorePageBase::analyzeSort(void) { createDefaultPrintSortOrder(); createLineStaffSequence(); } ////////////////////////////// // // ScorePageBase::createDefaultPrintSortOrder -- place data indices in // the order in which they will be printed. The default print // sort order is the order in which the data is read from the input // file. // void ScorePageBase::createDefaultPrintSortOrder(void) { pagePrintSequence.setSize(getSize()); pagePrintSequence.allowGrowth(0); pagePrintSequence.setAll(0, 1); printAnalysisQ = 1; } ////////////////////////////// // // ScorePageBase::createLineStaffSequence -- split the page data into // lists of objects divided by staff ownership, and sort each list // by hpos (then by vpos, then by p1 value). // void ScorePageBase::createLineStaffSequence(void) { int i; ScorePageBase& thispage = *this; // first set the number of staves to 100. The list will be indexed by // the P2 value of the object (staff 0 will not be used for regular staves). // Currently staff count on a page of 99 or less is allowed. lineStaffSequence.setSize(100); for (i=0; i objcount(100); objcount.setAll(0); int staffnum; for (i=0; i= 100) { continue; } objcount[staffnum]++; } // pre-allocate space for each staff; for (i=0; i= 100) { continue; } if (staffnum > maxStaffNumber) { maxStaffNumber = staffnum; } lineStaffSequence[staffnum].append(i); } // Identify which staves have any data on them and store // a list of these staves in pageStaffList. pageStaffList.setSize(100); pageStaffList.setSize(0); for (i=0; i 0) { pageStaffList.append(i); } } // Create a reverse mapping of pageStaffList which can find the // consecutive staff enumeration from the P2 value. The P2 value // must be between 0 (but really 1 for real data) and 99. pageStaffListReverse.setSize(100); pageStaffListReverse.setAll(-1); for (i=0; i& objects) { ScorePageBase::quickSortByDataIndex(objects, 0, objects.getSize()-1); } ////////////////////////////// // // ScorePageBase::quickSortByDataIndex -- Called by sortByHpos() and does all // of the actual sorting. Uses the contents of the data array for // comparison of indices. // void ScorePageBase::quickSortByDataIndex(Array& indexes, int starti, int endi) { if (starti < endi) { int pivotvalue = indexes[starti]; int left = starti - 1; int right = endi + 1; for(;;) { while (isGreater(indexes[--right], pivotvalue)); while (isLess(indexes[++left], pivotvalue)); if (left >= right) break; int temp = indexes[right]; indexes[right] = indexes[left]; indexes[left] = temp; } int pivot = right; quickSortByDataIndex(indexes, starti, pivot); quickSortByDataIndex(indexes, pivot+1, endi); } } ////////////////////////////// // // isGreater -- returns true if the hpos of first item is greater // than second item. // int ScorePageBase::isGreater(int a, int b) { // primary sort by hpos if (data[a]->getHpos() > data[b]->getHpos()) { return 1; } else if (data[a]->getHpos() < data[b]->getHpos()) { return 0; } // ties sorted by vpos if (data[a]->getVpos() > data[b]->getVpos()) { return 1; } else if (data[a]->getVpos() < data[b]->getVpos()) { return 0; } // ties sorted by (int)P1 value if ((int)data[a]->getValue(P1) > (int)data[b]->getValue(P1)) { return 1; } else if ((int)data[a]->getValue(P1) < (int)data[b]->getValue(P1)) { return 0; } // same hpos, same vpos, same P1, so determine that two objects are equal // (neither is greater than the other): return 0; } ////////////////////////////// // // isLess -- returns true if the hpos of first item is less // than second item. // int ScorePageBase::isLess(int a, int b) { // primary sort by hpos if (data[a]->getHpos() < data[b]->getHpos()) { return 1; } else if (data[a]->getHpos() > data[b]->getHpos()) { return 0; } // ties sorted by vpos if (data[a]->getVpos() < data[b]->getVpos()) { return 1; } else if (data[a]->getVpos() > data[b]->getVpos()) { return 0; } // ties sorted by (int)P1 value if ((int)data[a]->getValue(P1) < (int)data[b]->getValue(P1)) { return 1; } else if ((int)data[a]->getValue(P1) > (int)data[b]->getValue(P1)) { return 0; } // same hpos, same vpos, same P1, so determine that two objects are equal // (neither is less than the other): return 0; } /////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // ScorePageBase::compareSystemIndexes -- sort staff number, then // horizontal position, then item code, then vertical position. // int ScorePageBase::compareSystemIndexes(const void* A, const void* B) { ScoreRecord& a = *((ScoreRecord*)A); ScoreRecord& b = *((ScoreRecord*)B); if (a.getPValue(2) < b.getPValue(2)) { return -1; } else if (a.getPValue(2) > b.getPValue(2)) { return 1; } // staff line tie: resolve by horizontal postion if (a.getPValue(3) < b.getPValue(3)) { return -1; } else if (a.getPValue(3) > b.getPValue(3)) { return 1; } // horizontal postion tie: resolve by code item if (a.getPValue(1) < b.getPValue(1)) { return -1; } else if (a.getPValue(1) > b.getPValue(1)) { return 1; } // still a tie: sort from lowest vertical postion to highest // vertical position if (a.getPValue(4) < b.getPValue(4)) { return -1; } else if (a.getPValue(4) > b.getPValue(4)) { return 1; } // still a tie: give up and say they are equal return 0; } /* ////////////////////////////// // // ScorePageBase::compareStaff -- sort staff number, then horizontal position, // then item code, then vertical position // int ScorePageBase::compareStaff(const void* A, const void* B) { ScoreRecord& a = **((ScoreRecord**)A); ScoreRecord& b = **((ScoreRecord**)B); if (a.getPValue(2) < b.getPValue(2)) { return -1; } else if (a.getPValue(2) > b.getPValue(2)) { return 1; } // staff line tie: resolve by horizontal postion if (a.getPValue(3) < b.getPValue(3)) { return -1; } else if (a.getPValue(3) > b.getPValue(3)) { return 1; } // horizontal postion tie: resolve by code item if (a.getPValue(1) < b.getPValue(1)) { return -1; } else if (a.getPValue(1) > b.getPValue(1)) { return 1; } // still a tie: sort from lowest vertical postion to highest // vertical position if (a.getPValue(4) < b.getPValue(4)) { return -1; } else if (a.getPValue(4) > b.getPValue(4)) { return 1; } // still a tie: give up and say they are equal return 0; } */ /* ////////////////////////////// // // ScorePageBase::compareSystem -- sort by system, then horizontal position, // then staff number, then item code, then vertical position // int ScorePageBase::compareSystem(const void* A, const void* B) { ScoreRecord& a = *(((SystemRecord*)A)->ptr); ScoreRecord& b = *(((SystemRecord*)B)->ptr); // Sort by horizontal postion if (a.getPValue(3) < b.getPValue(3)) { return -1; } else if (a.getPValue(3) > b.getPValue(3)) { return 1; } // then by staff line if (a.getPValue(2) < b.getPValue(2)) { return -1; } else if (a.getPValue(2) > b.getPValue(2)) { return 1; } // horizontal postion tie: resolve by code item if (a.getPValue(1) < b.getPValue(1)) { return -1; } else if (a.getPValue(1) > b.getPValue(1)) { return 1; } // still a tie: sort from lowest vertical postion to highest // vertical position if (a.getPValue(4) < b.getPValue(4)) { return -1; } else if (a.getPValue(4) > b.getPValue(4)) { return 1; } // still a tie: give up and say they are equal return 0; } */ // md5sum: e1c6f792fbddebf040ffe0355fedb619 ScorePageBase.cpp [20050403]