//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Wed Jun 13 18:46:49 PDT 2001
// Last Modified: Wed Jun 13 18:46:49 PDT 2001
// Filename: ...museinfo/examples/all/parsepmx.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/parsepmx.cpp
// Syntax: C++; museinfo
//
// Description: Basic PMX Parser.
//
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#ifndef OLDCPP
#include <iostream>
#include <fstream>
using namespace std;
#else
#include <iostream.h>
#include <fstream.h>
#endif
// line type defines
#define LINE_UNKNOWN -1
#define LINE_BLANK 0
#define LINE_COMMENT 1
#define LINE_BOUNDARY 2
#define LINE_DEFINE 3
#define LINE_SETUP 4
#define LINE_INSTRUMENT 5
#define LINE_CLEF 6
// other defines:
#define SPACES " \t\n\015"
// function declarations:
void parseSetup(fstream& infile);
int getline(char* buffer, fstream& file);
void displayOriginalLine(const char* buffer);
int identifyline(const char* buffer, int stage);
void printCommentary(const char* buffer);
void printLineType(int type);
void parseSetupLine(const char* buffer);
void printSetupVariables(void);
void parseBody(fstream& infile);
void parseInstrumentLine(const char *inbuffer);
void parseClefLine(const char *inbuffer);
// global variables
int stage = 0; // part of file being read: 0=start, 1=def, 2=setup, 3=body
int line = 0; // number of the line being read.
int namecount = 0; // number of instrument names read
// setup variables read from header:
int setupcount = 0; // number of setup variables read
double setup[12] = {0}; // storage for setup variables
double& nv = setup[0]; // number of staves in a system
double& noinst = setup[1]; // number of instruments on a system
double& mtrnuml = setup[2]; // logical meter numerator
double& mtrdenl = setup[3]; // logical meter denominator
double& mtrnump = setup[4]; // printed meter numerator
double& mtrdenp = setup[5]; // printed meter denominator
double& xmtrnum0 = setup[6]; // number of beats in the pickup measure
double& isig = setup[7]; // key signature
double& npages = setup[8]; // number of pages to create
double& nsyst = setup[9]; // total number of systems to create
double& musicsize = setup[10]; // point size of staves
double& fracindent = setup[11]; // indentation of the first system
//////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
if (argc != 2) {
cout << "Usage: " << argv[0] << " input-pmx-file" << endl;
exit(1);
}
#ifndef OLDCPP
fstream infile(argv[1], ios::in);
#else
fstream infile(argv[1], ios::in | ios::nocreate);
#endif
if (!infile.is_open()) {
cout << "Error: cannot open " << argv[1] << " for reading" << endl;
exit(1);
}
parseSetup(infile);
printCommentary("This is the end of the SETUP section");
printCommentary("Now begins the body of the PMX file" );
parseBody(infile);
return 0;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// parseBody -- read the musical information section
//
void parseBody(fstream& infile) {
}
//////////////////////////////
//
// parseSetup -- read up to the end of the setup section of the music.
//
void parseSetup(fstream& infile) {
char inbuffer[2048] = {0};
char message[1024] = {0};
int done = 0;
int lineid = 0;
while (!done) {
line = getline(inbuffer, infile);
displayOriginalLine(inbuffer);
if (infile.eof()) {
cout << "Error: EOF when not finished parsing file" << endl;
exit(1);
}
lineid = identifyline(inbuffer, stage);
printLineType(lineid);
switch(lineid) {
case LINE_BOUNDARY:
stage++;
sprintf(message, "Going to stage %d", stage);
printCommentary(message);
break;
case LINE_SETUP:
parseSetupLine(inbuffer);
break;
case LINE_INSTRUMENT:
parseInstrumentLine(inbuffer);
break;
case LINE_CLEF:
parseClefLine(inbuffer);
break;
}
if (stage >= 5) {
done = 1;
break;
}
}
}
//////////////////////////////
//
// parseClefLine -- doesn't store the clefs for now.
//
void parseClefLine(const char *inbuffer) {
char tbuffer[2048] = {0};
int len = strlen(inbuffer);
strcpy(tbuffer, inbuffer);
char * ptr = strtok(tbuffer, SPACES);
len = strlen(ptr);
if (len != (int)nv) {
cout << "Error on line " << line << ": incorrect clef count" << endl;
exit(1);
}
stage = 5;
}
//////////////////////////////
//
// parseInstrumentLine --
//
void parseInstrumentLine(const char *inbuffer) {
char message[1024] = {0};
namecount++;
sprintf(message, "Instrument name %d: %s", namecount, inbuffer);
printCommentary(message);
if (namecount >= noinst) {
stage = 4;
printCommentary("Next line is expected to be the clef indicator line");
}
}
//////////////////////////////
//
// parseSetupLine --
//
void parseSetupLine(const char* buffer) {
char tbuffer[2048] = {0};
// int length = strlen(buffer);
char message[1024] = {0};
strcpy(tbuffer, buffer);
char* ptr = strtok(tbuffer, SPACES);
while (ptr != NULL) {
if (ptr[0] == '%') {
return;
}
if (setupcount > 11) {
cout << "Error on line " << line << ": too many setup values" << endl;
exit(1);
}
setup[setupcount] = strtod(ptr, NULL);
setupcount++;
sprintf(message, "Read setup variable number %d", setupcount);
printCommentary(message);
if (setupcount >= 12) {
stage = 3;
printSetupVariables();
printCommentary("Finished reading setup variables");
printCommentary("Expecting next non-comment line to be inst. names");
}
if (strchr(ptr, '%') != NULL) {
return;
}
ptr = strtok(NULL, SPACES);
}
}
//////////////////////////////
//
// identifyline -- identify what type of line this is.
//
int identifyline(const char* buffer, int stage) {
char tbuffer[2048] = {0};
int len = strlen(buffer);
int plen;
if (len == 0 && stage == 3) {
return LINE_INSTRUMENT;
}
if (len == 0) {
return LINE_BLANK;
}
strcpy(tbuffer, buffer);
char* ptr = strtok(tbuffer, SPACES);
if (ptr == NULL) {
if (stage == 3) {
return LINE_INSTRUMENT;
} else {
return LINE_BLANK;
}
}
// determine if this is a comment line
plen = strlen(ptr);
if (plen == 0) {
cout << "Error reading line: " << line << endl;
exit(1);
}
if (ptr[0] == '%') {
return LINE_COMMENT;
}
if (stage == 4) {
return LINE_CLEF;
}
if (stage == 3) {
return LINE_INSTRUMENT;
}
if (strcmp(ptr, "---") == 0) {
return LINE_BOUNDARY;
}
if (stage == 1) {
return LINE_DEFINE;
}
if (stage == 2 || stage == 0) {
if (isdigit(ptr[0]) || ptr[0] == '-') {
return LINE_SETUP;
stage = 2;
}
}
return LINE_UNKNOWN;
}
//////////////////////////////
//
// displayOriginalLine -- print the original line with a special start char.
//
void displayOriginalLine(const char* buffer) {
cout << "===>\t" << buffer << endl;
}
//////////////////////////////
//
// getline -- get a line from the file and increment the current
// line number
//
int getline(char* buffer, fstream& file) {
static int linecounter = 0;
file.getline(buffer, 1000, '\n');
linecounter++;
return linecounter;
}
//////////////////////////////
//
// printCommentary -- print a parser comment about the currentline
//
void printCommentary(const char* buffer) {
cout << " <+++\t" << buffer << endl;
}
//////////////////////////////
//
// printLineType -- print the type of line being processed
//
void printLineType(int type) {
switch (type) {
case LINE_UNKNOWN: printCommentary("Unknown line type"); break;
case LINE_BLANK: printCommentary("Empty line"); break;
case LINE_COMMENT: printCommentary("Comment line"); break;
case LINE_BOUNDARY: printCommentary("Boundary line"); break;
case LINE_DEFINE: printCommentary("Definition line"); break;
case LINE_SETUP: printCommentary("Setup line"); break;
case LINE_INSTRUMENT:printCommentary("Instrument name line");break;
case LINE_CLEF: printCommentary("Clef line"); break;
default: printCommentary("UNDOCUMENTED LINE"); break;
}
}
//////////////////////////////
//
// printSetupVariables --
//
void printSetupVariables(void) {
char message[1024] = {0};
sprintf(message, "1: nv = %f (number of staves per system)", nv);
printCommentary(message);
sprintf(message, "2: noinst = %f (number of instruments per system)", noinst);
printCommentary(message);
sprintf(message, "3: mtrnuml = %f (logical meter numerator)", mtrnuml);
printCommentary(message);
sprintf(message, "4: mtrdenl = %f (logical meter denominator)", mtrdenl);
printCommentary(message);
sprintf(message, "5: mtrnump = %f (printing meter denominator)", mtrnump);
printCommentary(message);
sprintf(message, "6: mtrdenp = %f (printing meter denominator)", mtrdenp);
printCommentary(message);
sprintf(message, "7: xmtrnum0 = %f (pickup measure beats)", xmtrnum0);
printCommentary(message);
sprintf(message, "8: isig = %f (key signature)", isig);
printCommentary(message);
sprintf(message, "9: npages = %f (number of pages)", npages);
printCommentary(message);
sprintf(message, "10: nsyst = %f (total number of systems)", nsyst);
printCommentary(message);
sprintf(message, "11: musicsize = %f (music size)", musicsize);
printCommentary(message);
sprintf(message, "12: fracindent = %f (first line indent)", fracindent);
printCommentary(message);
}
// md5sum: e30a832d7bd503b7a4a2f56a4fdc7bac parsepmx.cpp [20050403]