//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Thu Nov 22 10:57:44 PST 2001
// Last Modified: Mon Nov 26 18:34:55 PST 2001
// Filename: ...museinfo/examples/all/notelink.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/notelink.cpp
// Syntax: C++; museinfo
//
// Description: Creates a linked list of humdrum data.
//
//
#include "humdrum.h"
#include <string.h>
class Node {
public:
Node(void) {
lastline.setSize(0);
lastspine.setSize(0);
nextline.setSize(0);
nextspine.setSize(0);
}
void add(Node& newnode);
Array<int> lastline;
Array<int> lastspine;
Array<int> nextline;
Array<int> nextspine;
};
void Node::add(Node& newnode) {
int i;
for (i=0; i<newnode.lastline.getSize(); i++) {
lastline.append(newnode.lastline[i]);
lastspine.append(newnode.lastspine[i]);
}
for (i=0; i<newnode.nextline.getSize(); i++) {
nextline.append(newnode.nextline[i]);
nextspine.append(newnode.nextspine[i]);
}
}
//////////////////////////////////////////////////////////////////////////
typedef Array<Node> ANode;
typedef Array<ANode> AANode;
void processHumdrumFile(HumdrumFile& hfile, AANode& nodes);
void printAnalysis(HumdrumFile& hfile, AANode& nodes);
int hasSpineManip(HumdrumRecord& aRecord);
void insertNullNode(int location, ANode& current);
void processTransition(HumdrumRecord& aRecord, ANode& current, int& init,
int& tinit);
void processData(HumdrumRecord& aRecord, ANode& current, int line);
void deleteNode(int index, ANode& current);
int findLineBack(int currentline, int target);
////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
if (argc != 2) {
cout << "Usage: " << argv[0] << " input-kern-file" << endl;
exit(1);
}
AANode nodes;
HumdrumFile hfile(argv[1]);
processHumdrumFile(hfile, nodes);
printAnalysis(hfile, nodes);
return 0;
}
////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// printAnalysis --
//
void printAnalysis(HumdrumFile& hfile, AANode& nodes) {
int i, j, k;
int hline;
cout << "!! LASTLINE ANALYSIS ---------------" << endl;
for (i=0; i<nodes.getSize(); i++) {
hline = i;
cout << hline << " ::\t";
for (j=0; j<nodes[i].getSize(); j++) {
for (k=0; k<nodes[i][j].lastline.getSize(); k++) {
cout << nodes[i][j].lastline[k] << ":";
cout << nodes[i][j].lastspine[k];
if (k<nodes[i][j].lastline.getSize()-1) {
cout << "+";
}
}
cout << "\t";
}
cout << hfile[hline] << endl;
}
cout << "!! NEXTLINE ANALYSIS ---------------" << endl;
for (i=0; i<nodes.getSize(); i++) {
hline = i;
cout << hline << " ::\t";
for (j=0; j<nodes[i].getSize(); j++) {
for (k=0; k<nodes[i][j].nextline.getSize(); k++) {
cout << nodes[i][j].nextline[k] << ":";
cout << nodes[i][j].nextspine[k];
if (k<nodes[i][j].nextline.getSize()-1) {
cout << "+";
}
}
cout << "\t";
}
cout << hfile[hline] << endl;
}
}
//////////////////////////////
//
// processHumdrumFile
//
void processHumdrumFile(HumdrumFile& hfile, AANode& nodes) {
nodes.setSize(0);
ANode current;
ANode nullnode(0);
current.setSize(0);
nodes.setSize(hfile.getNumLines());
nodes.setSize(0);
int i, j, k;
int m;
int init = 0;
int tinit = 0;
// first: assign last token values
for (i=0; i<hfile.getNumLines(); i++) {
switch (hfile[i].getType()) {
case E_humrec_none:
case E_humrec_empty:
case E_humrec_global_comment:
case E_humrec_bibliography:
nodes.append(nullnode);
break;
case E_humrec_data_comment:
case E_humrec_data_kern_measure:
// treating measure as an entire line
nodes.append(current);
break;
case E_humrec_interpretation:
nodes.append(current);
if (hasSpineManip(hfile[i])) {
processTransition(hfile[i], current, init, tinit);
}
break;
case E_humrec_data:
nodes.append(current);
processData(hfile[i], current, i);
break;
default:
break;
}
}
// now go back and assign next token values by going backwards in analysis
// skipping over null tokens and non-data items
int nline, nspine;
int pline, pspine;
for (i=nodes.getSize()-1; i>=0; i--) {
if (hfile[i].getType() != E_humrec_data) {
continue;
}
for (j=0; j<nodes[i].getSize(); j++) {
if (strcmp(hfile[i][j], ".") == 0) {
continue;
}
for (k=0; k<nodes[i][j].lastline.getSize(); k++) {
nline = i;
nspine = j;
pline = nodes[i][j].lastline[k];
pspine = nodes[i][j].lastspine[k];
nodes[pline][pspine].nextline.append(nline);
nodes[pline][pspine].nextspine.append(nspine);
}
}
}
// now add the next spine information to null tokens, where the
// next token information is found by going back to the last
// non-null token and copying its next token information.
for (i=0; i<nodes.getSize(); i++) {
for (j=0; j<nodes[i].getSize(); j++) {
if (strcmp(hfile[i][j], ".") != 0) {
continue;
}
for (k=0; k<nodes[i][j].lastline.getSize(); k++) {
pline = nodes[i][j].lastline[k];
pspine = nodes[i][j].lastspine[k];
for (m=0; m<nodes[pline][pspine].nextline.getSize(); m++) {
nline = nodes[pline][pspine].nextline[m];
nspine = nodes[pline][pspine].nextspine[m];
nodes[i][j].nextline.append(nline);
nodes[i][j].nextspine.append(nspine);
}
}
}
}
// add to measures, data comments and interpretations
// as done with null tokens
for (i=0; i<nodes.getSize(); i++) {
for (j=0; j<nodes[i].getSize(); j++) {
switch (hfile[i].getType()) {
case E_humrec_interpretation:
case E_humrec_data_comment:
case E_humrec_data_kern_measure:
for (k=0; k<nodes[i][j].lastline.getSize(); k++) {
pline = nodes[i][j].lastline[k];
pspine = nodes[i][j].lastspine[k];
for (m=0; m<nodes[pline][pspine].nextline.getSize(); m++) {
nline = nodes[pline][pspine].nextline[m];
nspine = nodes[pline][pspine].nextspine[m];
nodes[i][j].nextline.append(nline);
nodes[i][j].nextspine.append(nspine);
}
}
}
}
}
}
//////////////////////////////
//
// findLineBack -- find the previous analysis line based on the previous
// data line.
//
int findLineBack(int currentline, int target, Array& lines) {
int i = currentline - 1;
while (i>0 && lines[i] != target) {
i--;
}
return i;
}
//////////////////////////////
//
// processData --
//
void processData(HumdrumRecord& aRecord, ANode& current, int line) {
if (current.getSize() != aRecord.getFieldCount()) {
cout << "ERROR in processData" << endl;
exit(1);
}
int i;
for (i=0; i<aRecord.getFieldCount(); i++) {
if (strcmp(aRecord[i], ".") != 0) {
current[i].lastline.setSize(1);
current[i].lastline[0] = line;
current[i].lastspine.setSize(1);
current[i].lastspine[0] = i;
}
}
}
//////////////////////////////
//
// processTransition --
//
void processTransition(HumdrumRecord& aRecord, ANode& current, int& init,
int& tinit) {
int i, j;
int correction = 0;
int tempcorrection = 0;
for (i=0; i<aRecord.getFieldCount(); i++) {
if (strncmp(aRecord[i], "**", 2) == 0) {
if (init == 0) {
insertNullNode(i+correction, current);
tinit = 1;
} else {
// do nothing: the *+ operator has already added a new spine
}
} else if (strcmp(aRecord[i], "*-") == 0) {
deleteNode(i+correction, current);
} else if (strcmp(aRecord[i], "*x") == 0) {
if (i < aRecord.getFieldCount() - 1) {
Node temp;
temp = current[i+correction];
current[i+correction] = current[i+1+correction];
current[i+1+correction] = temp;
i++;
}
} else if (strcmp(aRecord[i], "*^") == 0) {
insertNullNode(i+correction+1, current);
current[i+correction+1] = current[i+correction];
correction++;
} else if (strcmp(aRecord[i], "*v") == 0) {
tempcorrection = 0;
for (j=i+1; j<aRecord.getFieldCount(); j++) {
if (strcmp(aRecord[j], "*v") != 0) {
break;
}
current[i+correction].add(current[i+1+correction]);
deleteNode(i+correction+1, current);
tempcorrection++;
}
correction += tempcorrection;
i += tempcorrection;
} else if (strcmp(aRecord[i], "*+") == 0) {
insertNullNode(i+correction+1, current);
correction++;
}
}
if (tinit > 0) {
init = 1;
}
}
//////////////////////////////
//
// deleteNode --
//
void deleteNode(int index, ANode& current) {
if (index == current.getSize() - 1) {
current.setSize(current.getSize() - 1 );
return;
}
int i;
for (i=index; i<current.getSize()-1; i++) {
current[i] = current[i+1];
}
current.setSize(current.getSize() - 1);
}
//////////////////////////////
//
// insertNullNode --
//
void insertNullNode(int location, ANode& current) {
Node node;
if (current.getSize() == 0) {
current.append(node);
return;
}
if (current.getSize() == location) {
current.append(node);
return;
}
if (current.getSize() > location) {
int i;
current.append(current[current.getSize()-1]);
for (i=current.getSize()-2; i>location; i--) {
current[i] = current[i-1];
}
current[location] = node;
return;
}
cout << "Error in insert NULL" << endl;
cout << "Location = " << location << endl;
cout << "Size = " << current.getSize() << endl;
exit(1);
}
//////////////////////////////
//
// hasSpineManip --
//
int hasSpineManip(HumdrumRecord& aRecord) {
int i;
for (i=0; i<aRecord.getFieldCount(); i++) {
if (strncmp(aRecord[i], "**", 2) == 0) {
return 1;
} else if (strcmp(aRecord[i], "*^") == 0) {
return 1;
} else if (strcmp(aRecord[i], "*v") == 0) {
return 1;
} else if (strcmp(aRecord[i], "*x") == 0) {
return 1;
} else if (strcmp(aRecord[i], "*-") == 0) {
return 1;
} else if (strcmp(aRecord[i], "*+") == 0) {
return 1;
}
}
return 0;
}
// md5sum: 6b4baeb51c2b32f5d1e20c9a0498288f humlink.cpp [20050403]