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