// // Programmer: Craig Stuart Sapp // Creation Date: Sat Feb 24 20:20:18 PST 2018 // Last Modified: Sat Feb 24 20:20:21 PST 2018 // Filename: tools/redexpress.cpp // URL: https://github.com/craigsapp/midifile/blob/master/tools/redexpress.cpp // Syntax: C++11 // vim: ts=3 // // Description: Adds expression information to notes extracted from // Red Welte-Mignon piano rolls. // /////////////////////////////////////////////////////////// // // red Welte-Mignon tracker holes (T100): // // 10 expression on left side: // 1: Mezzo-Forte-Off MIDI Key 14 // 2: Mezzo-Forte-On MIDI Key 15 // 3: Crescendo-Off MIDI Key 16 // 4: Crescendo-On MIDI Key 17 // 5: Forzando-Off MIDI Key 18 // 6: Forzando-On MIDI Key 19 // 7: Soft-Pedal-Off MIDI Key 20 // 8: Soft-Pedal-On MIDI Key 21 // 9: Motor-Off MIDI Key 22 // 10: Motor-On MIDI Key 23 // Then 80 notes from C1 to G7 (MIDI note 24 to 103): // 11: C1 MIDI Key 24 // ... // 50: D#4 MIDI Key 63 // Treble register (40 notes) from E4 to G7: // 51: E4 MIDI Key 64 // ... // 90: G7 MIDI Key 103 // Then 10 expression holes on the right side: // 91: -10: Rewind MIDI Key 104 // 92: -9: Electric-Cutoff MIDI Key 105 // 93: -8: Sustain-Pedal-On MIDI Key 106 // 94: -7: Sustain-Pedal-Off MIDI Key 107 // 95: -6: Forzando-On MIDI Key 108 // 96: -5: Forzando-Off MIDI Key 109 // 97: -4: Crescendo-On MIDI Key 110 // 98: -3: Crescendo-Off MIDI Key 111 // 99: -2: Mezzo-Forte-On MIDI Key 112 // 100: -1: Mezzo-Forte-Off MIDI Key 113 // /////////////////////////////////////////////////////////// #include "MidiFile.h" #include "Options.h" #include #include using namespace std; using namespace smf; void checkOptions (Options& opts, int argc, char** argv); void example (void); void usage (const char* command); void addExpression_T100 (MidiFile& midifile); int getRewindTime (MidiFile& midifile, int track); void addSustainPedalling (MidiFile& midifile, int sourcetrack, int targettrack); void addSoftPedalling (MidiFile& midifile, int sourcetrack, int targettrack); #define TYPE_NONE 0 #define TYPE_T100 1 int Rolltype = TYPE_T100; int RewindKey = 104; int PedalOnKey = 106; int PedalOffKey = 107; int SoftOnKey = 21; int SoftOffKey = 20; ////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { Options options; checkOptions(options, argc, argv); MidiFile midifile; if (options.getArgCount() > 0) { midifile.read(options.getArg(1)); } else { midifile.read(cin); } addExpression_T100(midifile); if (options.getArgCount() >= 2) { midifile.write(options.getArg(2)); } else { cout << midifile; } return 0; } ////////////////////////////////////////////////////////////////////////// ////////////////////////////// // // addExpression_T100 -- // void addExpression_T100(MidiFile& midifile) { int tracks = midifile.getTrackCount(); if (tracks != 5) { cerr << "This program expects a five-track MIDI file to process" << endl; exit(1); } // add a new track with some of the expression components (pedal) midifile.addTrack(); int expressiontrack = 5; int rewind = getRewindTime(midifile, 4); MidiEvent me; me.tick = rewind; me.track = expressiontrack; me.makeController(1, 7, 0); // mute for any post-rewind holes: bass midifile.addEvent(me); me.makeController(2, 7, 0); // mute for any post-rewind holes: treble midifile.addEvent(me); addSustainPedalling(midifile, 4, expressiontrack); addSoftPedalling(midifile, 4, expressiontrack); midifile.sortTracks(); } ////////////////////////////// // // addSustainPedalling -- // void addSustainPedalling(MidiFile& midifile, int sourcetrack, int targettrack) { int count = midifile.getEventCount(sourcetrack); MidiEvent me; me.track = targettrack; for (int i=0; i=0; i--) { if (!midifile[track][i].isNoteOn()) { continue; } if (midifile[track][i].getKeyNumber() == RewindKey) { return midifile[track][i].tick; } } return -1; } ////////////////////////////// // // checkOptions -- // void checkOptions(Options& opts, int argc, char* argv[]) { opts.define("t|type=s:redwelte", "type of roll to process"); opts.define("t100|T100=b", "red Welte-Mignon roll, 100 tracker holes"); 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.process(argc, argv); // handle basic options: if (opts.getBoolean("author")) { cout << "Written by Craig Stuart Sapp, " << "craig@ccrma.stanford.edu, 24 February 2018" << endl; exit(0); } else if (opts.getBoolean("version")) { cout << argv[0] << ", version: February 2018" << endl; cout << "compiled: " << __DATE__ << endl; exit(0); } else if (opts.getBoolean("help")) { usage(opts.getCommand().data()); exit(0); } else if (opts.getBoolean("example")) { example(); exit(0); } if (opts.getArgCount() > 2) { usage(opts.getCommand().data()); exit(1); } Rolltype = TYPE_T100; if (opts.getBoolean("type")) { string typestring = opts.getString("type"); if (typestring == "redwelte") { Rolltype = TYPE_T100; } else if (typestring == "t100") { Rolltype = TYPE_T100; } else if (typestring == "T100") { Rolltype = TYPE_T100; } } else if (opts.getBoolean("T100")) { Rolltype = TYPE_T100; } if (Rolltype != TYPE_T100) { cerr << "Unknown roll type" << endl; exit(1); } } ////////////////////////////// // // example -- // void example(void) { // add examples here } ////////////////////////////// // // usage -- // void usage(const char* command) { // add usage here }