1 //
2 // Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
3 // Creation Date: Tue Jun 18 12:14:03 PDT 2002
4 // Last Modified: Mon Feb  9 20:28:07 PST 2015 Updated for C++11.
5 // Filename:      midifile/tools/perfid.cpp
6 // Web Address:   http://sig.sapp.org/examples/museinfo/midi/perfid.cpp
7 // Syntax:        C++; museinfo
8 //
9 // Description:   Determine if a MIDI file is a live performance or if
10 //                it is step edit.
11 //
12 
13 #include "MidiFile.h"
14 #include "Options.h"
15 #include <iostream>
16 #include <iomanip>
17 #include <vector>
18 
19 using namespace std;
20 using namespace smf;
21 
22 // user interface variables:
23 Options options;
24 int     track    = -1;         // track to extract from (starting from 0)
25 int     debugQ   = 0;          // use with --debug option
26 int     maxcount = 100000;     // maximum number of notes expected
27 int     rawQ     = 0;          // display raw data used to determine id
28 int     cutoff   = 1000000;    // maximum duration to consider
29 int     fileQ    = 0;          // print file name before id
30 
31 // function declarations:
32 void      checkOptions          (Options& opts, int argc, char** argv);
33 void      example               (void);
34 void      getNoteOnDeltas       (vector<int>& noteondeltas,
35                                  MidiFile& midifile);
36 void      addNoteOnEvents       (vector<int>& noteondeltas, MidiFile& midifile,
37                                  int track);
38 void      usage                 (const char* command);
39 int       intcompare            (const void* a, const void* b);
40 void      sortArray             (vector<int>& noteondeltas);
41 void      printDeltas           (vector<int>& noteondeltas);
42 void      printID               (vector<int>& noteondeltas);
43 
44 //////////////////////////////////////////////////////////////////////////
45 
main(int argc,char * argv[])46 int main(int argc, char* argv[]) {
47    checkOptions(options, argc, argv);
48    MidiFile midifile;
49    midifile.read(options.getArg(1));
50    midifile.absoluteTicks();
51    vector<int> noteondeltas;
52    noteondeltas.reserve(maxcount);
53    noteondeltas.clear();
54    midifile.joinTracks();
55    getNoteOnDeltas(noteondeltas, midifile);
56    if (rawQ) {
57       cout << "// ";
58       printID(noteondeltas);
59       printDeltas(noteondeltas);
60    } else {
61       printID(noteondeltas);
62    }
63    return 0;
64 }
65 
66 //////////////////////////////////////////////////////////////////////////
67 
68 
69 //////////////////////////////
70 //
71 // printDeltas --
72 //
73 
printDeltas(vector<int> & noteondeltas)74 void printDeltas(vector<int>& noteondeltas) {
75    int i;
76    int count = 1;
77    if (noteondeltas.size() == 0) {
78       return;
79    }
80    for (i=1; i<(int)noteondeltas.size(); i++) {
81       if (noteondeltas[i] != noteondeltas[i-1]) {
82          cout << count << "\t" << noteondeltas[i-1] << "\n";
83          count = 1;
84       } else {
85          count++;
86       }
87    }
88    cout << count << "\t" << noteondeltas.back() << "\n";
89 }
90 
91 
92 
93 //////////////////////////////
94 //
95 // printID --
96 //
97 
printID(vector<int> & noteondeltas)98 void printID(vector<int>& noteondeltas) {
99    if (fileQ) {
100       cout << options.getArg(1) << "\t";
101    }
102    int i;
103    int count = 1;
104    if (noteondeltas.size() == 0) {
105       cout << "Empty" << endl;
106       return;
107    }
108    vector<int> deltas;
109    vector<int> hist;
110    deltas.reserve(noteondeltas.size());
111    hist.reserve(noteondeltas.size());
112    deltas.clear();
113    hist.clear();
114    for (i=1; i<(int)noteondeltas.size(); i++) {
115       if (noteondeltas[i] != noteondeltas[i-1]) {
116          deltas.push_back(noteondeltas[i-1]);
117          hist.push_back(count);
118          count = 1;
119       } else {
120          count++;
121       }
122    }
123    deltas.push_back(noteondeltas.back());
124    hist.push_back(count);
125    int size = (int)deltas.size();
126    if (size > 2) {
127       if (deltas[0] == 0 && hist[0] > 10 && deltas[1] >= 10) {
128          cout << "Quantized" << endl;
129          return;
130       }
131    }
132 
133    if (size > 3 && deltas[5] < 10) {
134       if (hist[0] < hist[1] + hist[2] + hist[3] + hist[4]) {
135          cout << "Performance" << endl;
136          return;
137       } else {
138          cout << "Quantized" << endl;
139          return;
140       }
141    }
142 
143    cout << "Unknown" << endl;
144 }
145 
146 
147 
148 //////////////////////////////
149 //
150 // getNoteOnDeltas --
151 //
152 
getNoteOnDeltas(vector<int> & noteondeltas,MidiFile & midifile)153 void getNoteOnDeltas(vector<int>& noteondeltas, MidiFile& midifile) {
154    int i;
155    for (i=0; i<midifile.getNumTracks(); i++) {
156       addNoteOnEvents(noteondeltas, midifile, i);
157    }
158 
159    // sort note ons here.
160    sortArray(noteondeltas);
161 }
162 
163 
164 //////////////////////////////
165 //
166 // sortArray --
167 //
168 
sortArray(vector<int> & noteondeltas)169 void sortArray(vector<int>& noteondeltas) {
170    qsort(noteondeltas.data(), noteondeltas.size(), sizeof(int), intcompare);
171 
172 }
173 
174 
175 
176 //////////////////////////////
177 //
178 // intcompare -- compare two integers for ordering
179 //
180 
intcompare(const void * a,const void * b)181 int intcompare(const void* a, const void* b) {
182    if (*((int*)a) < *((int*)b)) {
183       return -1;
184    } else if (*((int*)a) > *((int*)b)) {
185       return 1;
186    } else {
187       return 0;
188    }
189 }
190 
191 
192 
193 //////////////////////////////
194 //
195 // addNoteOnEvents -- get the Note-On delta times from the specified
196 //                    track.
197 //
198 
addNoteOnEvents(vector<int> & noteondeltas,MidiFile & midifile,int track)199 void addNoteOnEvents(vector<int>& noteondeltas, MidiFile& midifile,
200       int track) {
201    int i;
202    int lasttime = -1;
203    MidiEvent* event;
204    int delta = 0;
205 
206    for (i=0; i<midifile.getNumEvents(track); i++) {
207       event = &midifile[track][i];
208       if (((*event)[0] & 0xf0) == 0x90) {
209          if ((*event)[2] > 0) {
210             if (lasttime < 0) {
211                lasttime = event->tick;
212             } else {
213                delta = event->tick - lasttime;
214                if (delta < cutoff) {
215                   noteondeltas.push_back(delta);
216                }
217                lasttime = event->tick;
218             }
219          }
220       }
221    }
222 }
223 
224 
225 
226 //////////////////////////////
227 //
228 // checkOptions -- process command-line options.
229 //
230 
checkOptions(Options & opts,int argc,char * argv[])231 void checkOptions(Options& opts, int argc, char* argv[]) {
232    opts.define("author=b",  "author of program");
233    opts.define("version=b", "compilation info");
234    opts.define("example=b", "example usages");
235    opts.define("h|help=b",  "short description");
236 
237    opts.define("t|track=i:-1", "which track to extract");
238    opts.define("r|raw=b",      "print noteon deltas");
239    opts.define("f|file=b",      "display filename");
240    opts.define("max=i:100000", "maximum number of notes expected in input");
241    opts.define("debug=b",  "debug mode to find errors in input file");
242 
243    opts.process(argc, argv);
244 
245    // handle basic options:
246    if (opts.getBoolean("author")) {
247       cout << "Written by Craig Stuart Sapp, "
248            << "craig@ccrma.stanford.edu, 18 Jun 2002" << endl;
249       exit(0);
250    } else if (opts.getBoolean("version")) {
251       cout << argv[0] << ", version: 18 Jun 2002" << endl;
252       cout << "compiled: " << __DATE__ << endl;
253       exit(0);
254    } else if (opts.getBoolean("help")) {
255       usage(opts.getCommand().c_str());
256       exit(0);
257    } else if (opts.getBoolean("example")) {
258       example();
259       exit(0);
260    }
261 
262    track    = opts.getInteger("track");
263    debugQ   = opts.getBoolean("debug");
264    maxcount = opts.getInteger("max");
265    rawQ     = opts.getBoolean("raw");
266    fileQ    = opts.getBoolean("file");
267 
268    if (opts.getArgCount() != 1) {
269       usage(opts.getCommand().c_str());
270       exit(1);
271    }
272 }
273 
274 
275 
276 //////////////////////////////
277 //
278 // example -- give example calls to the program.
279 //
280 
example(void)281 void example(void) {
282 }
283 
284 
285 
286 //////////////////////////////
287 //
288 // usage --
289 //
290 
usage(const char * command)291 void usage(const char* command) {
292 }
293 
294 
295 
296