//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sun Oct 24 10:39:47 PDT 1999
// Last Modified: Sun Oct 24 12:24:26 PDT 1999
// Filename: ...sig/examples/all/simpsmf.cpp
// Web Address: http://sig.sapp.org/examples/museinfo/humdrum/simpsmf.cpp
// Syntax: C++; museinfo
//
// Description: Simple converter from Humdrum **MIDI data into
// a Standard MIDI File format.
//
#include "FileIO.h"
#include "Array.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#ifndef OLDCPP
#include <iostream>
#include <fstream>
#else
#include <iostream.h>
#include <fstream.h>
#endif
typedef unsigned char uchar;
// function declarations:
void finishOutput(FileIO& output, Array<uchar>& array);
int processDataLine(const char* buffer, Array<uchar>& array);
int processInput(fstream& input, Array<uchar>& array);
void startOutput(FileIO& output);
int writeVLV(int duration, Array<uchar>& array);
///////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv) {
if (argc != 2) {
cerr << "Usage: " << argv[0] << " humdrum-midi-file " << endl;
exit(1);
}
#ifndef OLDCPP
fstream input(argv[1], ios::in);
#else
fstream input(argv[1], ios::in | ios::nocreate);
#endif
char outputname[1000] = {0};
strncpy(outputname, argv[1], 1000);
char* extensionStart = strchr(outputname, '.');
if (extensionStart == NULL) {
strcat(outputname, ".mid");
} else {
strcpy(extensionStart, ".mid");
}
FileIO output(outputname, ios::out);
Array<uchar> miditrack;
miditrack.setSize(10000);
miditrack.setSize(0);
if (!input.is_open()) {
cerr << "Error: cannot open file: " << argv[1] << endl;
exit(1);
}
startOutput(output);
int status = processInput(input, miditrack);
finishOutput(output, miditrack);
return status;
}
///////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// finishOutput -- write the track size and its data to the output MIDI file.
//
void finishOutput(FileIO& output, Array& array) {
uchar arraydatum;
// add the end-of-track to the track data:
arraydatum = 0x00;
array.append(arraydatum);
arraydatum = 0xff;
array.append(arraydatum);
arraydatum = 0x2f;
array.append(arraydatum);
arraydatum = 0x00;
array.append(arraydatum);
// now write the size of the track data to the output file:
unsigned long parameter = array.getSize();
output.writeBigEndian(parameter);
// and finally, write the track data itself:
output.write((char*)array.getBase(), array.getSize());
}
//////////////////////////////
//
// processDataLine -- convert the dataline into MIDI data.
//
int processDataLine(const char* buffer, Array& array) {
static char tokenbuffer[1024] = {0};
strncpy(tokenbuffer, buffer, 1000);
char* token = strtok(tokenbuffer, ". \t");
int count = 0;
int duration = 0;
int midikey = 0;
int midivel = 0;
int status = 0;
uchar arraydatum = 0;
while (token != NULL) {
if (strchr(token, '/') == NULL) {
// this token has ill-formed MIDI data.
token = strtok(NULL, ". \t");
continue;
}
count++;
status = sscanf(token, "%d/%d/%d", &duration, &midikey, &midivel);
if (status != 3) {
array.setSize(0);
cerr << "Did not read a MIDI data entry properly" << endl;
return 1;
}
// write the midi delta time to the MIDI track data:
if (count == 1) {
writeVLV(duration, array);
} else {
arraydatum = 0;
array.append(arraydatum);
}
// write the MIDI command byte to the track data:
if (midikey > 0) {
arraydatum = 0x90;
array.append(arraydatum);
arraydatum = midikey;
array.append(arraydatum);
arraydatum = midivel;
array.append(arraydatum);
} else {
arraydatum = 0x80;
array.append(arraydatum);
arraydatum = -midikey;
array.append(arraydatum);
arraydatum = midivel;
array.append(arraydatum);
}
// get the next token ready for testing at the top of the loop
token = strtok(NULL, ". \t");
}
return 0;
}
//////////////////////////////
//
// processInput -- read the input file and write to the midi output
// file as required.
//
int processInput(fstream& input, Array& array) {
char buffer[1024] = {0};
int exclusiveCount = 0;
int tempo = 90;
int status = 0;
input.getline(buffer, 1000, '\n');
while (!input.eof()) {
if (buffer[0] == '\0' || buffer[0] == '!' || buffer[0] == '=') {
input.getline(buffer, 1000, '\n');
continue;
}
if (buffer[0] == '*') {
if (buffer[1] == '*') {
exclusiveCount++;
if (exclusiveCount > 1) {
array.setSize(0);
cerr << "Error: too many exclusive interpretation lines" << endl;
return 1;
}
} else if (buffer[1] == 'M' && buffer[2] == 'M' &&
isdigit(buffer[3])) {
sscanf(buffer, "*MM%d", &tempo);
} else {
input.getline(buffer, 1000, '\n');
continue;
}
}
// we must have data if this point is reached
status = processDataLine(buffer, array);
if (status != 0) {
array.setSize(0);
return 1;
}
input.getline(buffer, 1000, '\n');
}
return 0;
}
//////////////////////////////
//
// startOutput -- write the header for the output MIDI file
//
void startOutput(FileIO& output) {
// write the basic MIDI header into output file.
output << "MThd";
unsigned long parameter;
// write size of header chunk
parameter = 6;
output.writeBigEndian(parameter);
// write MIDI format (type 0);
unsigned short lparam;
lparam = 0;
output.writeBigEndian(lparam);
// write the number of tracks in the file
lparam = 1;
output.writeBigEndian(lparam);
// write the ticks per quarter-note
lparam = 72;
output.writeBigEndian(lparam);
// write track chunk header
output << "MTrk";
// the next thing to write is the size of the data in bytes
// and then the data. This will be done by the finishOutput
// function.
};
//////////////////////////////
//
// writeVLV -- write the header for the output MIDI file
//
int writeVLV(int number, Array& array) {
unsigned long value = (unsigned long)number;
uchar arraydatum = 0;
if (value >= (1 << 28)) {
array.setSize(0);
cerr << "Error: number too large to handle" << endl;
return 1;
}
unsigned long byte[4];
byte[0] = (value >> 21) & 0x7f;
byte[1] = (value >> 14) & 0x7f;
byte[2] = (value >> 7) & 0x7f;
byte[3] = (value >> 0) & 0x7f;
int i;
int flag = 0;
for (i=0; i<3; i++) {
if (byte[i] != 0) {
flag = 1;
}
if (flag) {
byte[i] |= 0x80;
}
}
for (i=0; i<4; i++) {
if (byte[i] >= 0x80 || i == 3) {
arraydatum = (uchar)byte[i];
array.append(arraydatum);
}
}
return 0;
}
// md5sum: 603f2570ec87d0ae62934f97d7e151fc simpsmf.cpp [20050403]