2024-07-15 11:46:59 +08:00

231 lines
5.6 KiB
C++

//
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Tue Feb 2 15:06:12 PST 2016
// Last Modified: Tue Feb 2 15:06:15 PST 2016
// Filename: tools/mid2mtb.cpp
// URL: https://github.com/craigsapp/midifile/blob/master/tools/mid2mtb.cpp
// Syntax: C++11
// vim: ts=3
//
// Description: Converts a MIDI file into a MIDI Toolbox compatible
// text file.
//
#include "MidiFile.h"
#include "Options.h"
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
using namespace smf;
void convertMidiFile (MidiFile& midifile, vector<vector<double> >& matlab);
void checkOptions (Options& opts, int argc, char** argv);
void example (void);
void usage (const char* command);
void printEvent (vector<double>& event);
void printLegend (MidiFile& midifile);
void printMatlabArray (MidiFile& midifile, vector<vector<double> >& matlab);
// User interface variables
Options options;
vector<vector<double> > matlabarray;
//////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) {
matlabarray.reserve(100000);
matlabarray.clear();
checkOptions(options, argc, argv);
MidiFile midifile(options.getArg(1));
convertMidiFile(midifile, matlabarray);
printMatlabArray(midifile, matlabarray);
return 0;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////
//
// convertMidiFile --
//
void convertMidiFile(MidiFile& midifile, vector<vector<double> >& matlab) {
midifile.absoluteTicks();
midifile.linkNotePairs();
midifile.joinTracks();
midifile.doTimeAnalysis();
vector<double> parameters(8);
// 1: beat on time
// 2: beat duration
// 3: channel
// 4: pitch #
// 5: velocity
// 6: start time (seconds)
// 7: duration (seconds)
// 8: track
double tpq = midifile.getTicksPerQuarterNote();
double beatstart;
double beatdur;
double starttime;
double duration;
double channel;
double key;
double velocity;
double track;
for (int i=0; i<midifile[0].size(); i++) {
if (!midifile[0][i].isNoteOn()) {
continue;
}
beatstart = midifile[0][i].tick / tpq;
beatdur = midifile[0][i].getTickDuration() / tpq;
starttime = midifile.getTimeInSeconds(0, i);
duration = midifile[0][i].getDurationInSeconds();
channel = midifile[0][i].getChannelNibble() + 1;
key = midifile[0][i][1];
velocity = midifile[0][i][2];
track = midifile[0][i].track + 1;
parameters[0] = beatstart;
parameters[1] = beatdur;
parameters[2] = channel;
parameters[3] = key;
parameters[4] = velocity;
parameters[5] = starttime;
parameters[6] = duration;
parameters[7] = track;
matlab.push_back(parameters);
}
}
//////////////////////////////
//
// checkOptions --
//
void checkOptions(Options& opts, int argc, char* argv[]) {
opts.define("author=b", "author of program");
opts.define("version=b", "compilation info");
opts.define("example=b", "example usages");
opts.define("h|help=b", "short description");
opts.define("debug=b", "debug mode to find errors in input file");
opts.define("max=i:100000", "maximum number of notes expected in input");
opts.process(argc, argv);
// handle basic options:
if (opts.getBoolean("author")) {
cout << "Written by Craig Stuart Sapp, "
<< "craig@ccrma.stanford.edu, 22 Jan 2002" << endl;
exit(0);
} else if (opts.getBoolean("version")) {
cout << argv[0] << ", version: 12 Nov 2003" << endl;
cout << "compiled: " << __DATE__ << endl;
exit(0);
} else if (opts.getBoolean("help")) {
usage(opts.getCommand().c_str());
exit(0);
} else if (opts.getBoolean("example")) {
example();
exit(0);
}
if (opts.getArgCount() != 1) {
usage(opts.getCommand().c_str());
exit(1);
}
}
//////////////////////////////
//
// example --
//
void example(void) {
}
//////////////////////////////
//
// usage --
//
void usage(const char* command) {
cout << "Usage: " << command << " midifile" << endl;
}
void printLegend(MidiFile& midifile) {
cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
cout << "%% DATA LEGEND %%\n";
cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
cout << "%%Filename: " << midifile.getFilename() << endl;
cout << "%%Ticks per quarter note: " << midifile.getTicksPerQuarterNote()
<< "\n";
cout << "%%" << endl;
cout << "%% Meaning of columns:" << endl;
cout << "%%(1) note start in beats (quarter notes)." << endl;
cout << "%%(2) note duration in beats (quarter notes)." << endl;
cout << "%%(3) MIDI channel (indexed from 1)." << endl;
cout << "%%(4) MIDI pitch (60 = C4)" << endl;
cout << "%%(5) MIDI velocity (60 = C4)" << endl;
cout << "%%(6) note start in seconds." << endl;
cout << "%%(7) note duration in seconds." << endl;
cout << "%%(8) MIDI file track." << endl;
cout << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
}
//////////////////////////////
//
// printMatlabArray -- print the Matlab array representing the MIDI file.
// If not in time order, see sourcecode for mid2mat.cpp for sorting function.
//
void printMatlabArray(MidiFile& midifile, vector<vector<double> >& matlab) {
int i;
printLegend(midifile);
for (i=0; i<(int)matlab.size(); i++) {
printEvent(matlab[i]);
}
}
//////////////////////////////
//
// printEvent -- print the event
//
void printEvent(vector<double>& event) {
for (int i=0; i<(int)event.size(); i++) {
cout << event[i];
if (i<(int)event.size()-1) {
cout << "\t";
}
}
cout << "\n";
}