author | Michael Krelin <hacker@klever.net> | 2006-08-11 16:01:56 (UTC) |
---|---|---|
committer | Michael Krelin <hacker@klever.net> | 2006-08-11 16:01:56 (UTC) |
commit | 0c21a7a0d5b84dc6726462f0fbe51b8c32433262 (patch) (unidiff) | |
tree | 9df6334cb1a61efebe68f7bcef9aa119a823626a /tools/midifilter.cc | |
parent | 9bcc235e575a95989a5903394c127accbeef2e0f (diff) | |
download | midillo-0c21a7a0d5b84dc6726462f0fbe51b8c32433262.zip midillo-0c21a7a0d5b84dc6726462f0fbe51b8c32433262.tar.gz midillo-0c21a7a0d5b84dc6726462f0fbe51b8c32433262.tar.bz2 |
initial commit into repository0.0
-rw-r--r-- | tools/midifilter.cc | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/tools/midifilter.cc b/tools/midifilter.cc new file mode 100644 index 0000000..1c130de --- a/dev/null +++ b/tools/midifilter.cc | |||
@@ -0,0 +1,295 @@ | |||
1 | #include <getopt.h> | ||
2 | #include <iostream> | ||
3 | #include <string> | ||
4 | #include <algorithm> | ||
5 | #include <iterator> | ||
6 | using namespace std; | ||
7 | #include <konforka/exception.h> | ||
8 | #include <midillo/SMF.h> | ||
9 | using namespace midillo; | ||
10 | |||
11 | #include "config.h" | ||
12 | #define PHEADER PACKAGE " " VERSION " - midifilter - midi filter tool" | ||
13 | #define PCOPY "Copyright (c) 2006 Klever Group" | ||
14 | |||
15 | enum { | ||
16 | # include "filters_enumeration.cc" | ||
17 | total_filters | ||
18 | }; | ||
19 | |||
20 | struct filter_t { | ||
21 | const char *ids[5]; | ||
22 | const char *help; | ||
23 | bool filter; | ||
24 | } filters[] = { | ||
25 | # include "filters_definition.cc" | ||
26 | {0,0,0} | ||
27 | }; | ||
28 | #define FILTER(f) filters[filter_##f].filter | ||
29 | |||
30 | inline ostream& operator<<(ostream& s,const filter_t& f) { | ||
31 | ios::fmtflags ff = s.flags(); | ||
32 | int w = s.width(25); | ||
33 | s.unsetf(ios::right); s.setf(ios::left); | ||
34 | s << *f.ids << " " << f.help; | ||
35 | s.width(w); | ||
36 | s.flags(ff); | ||
37 | return s; | ||
38 | } | ||
39 | |||
40 | static bool message_is_filtered(const message_t& m) { | ||
41 | if(m.is_meta(meta_EOT)) | ||
42 | return false; | ||
43 | |||
44 | if(FILTER(sysex) && (m.status==status_system_sysex || m.status==status_system_end_of_sysex)) | ||
45 | return true; | ||
46 | if(FILTER(MTC_quarter_frame) && m.status==status_system_MTC_quarter_frame) | ||
47 | return true; | ||
48 | if(FILTER(song_position_pointer) && m.status==status_system_song_position_pointer) | ||
49 | return true; | ||
50 | if(FILTER(song_select) && m.status==status_system_song_select) | ||
51 | return true; | ||
52 | if(FILTER(tune_request) && m.status==status_system_tune_request) | ||
53 | return true; | ||
54 | if(FILTER(midi_clock) && m.status==status_system_midi_clock) | ||
55 | return true; | ||
56 | if(FILTER(midi_tick) && m.status==status_system_midi_tick) | ||
57 | return true; | ||
58 | if(FILTER(midi_start) && m.status==status_system_midi_start) | ||
59 | return true; | ||
60 | if(FILTER(midi_continue) && m.status==status_system_midi_continue) | ||
61 | return true; | ||
62 | if(FILTER(midi_stop) && m.status==status_system_midi_stop) | ||
63 | return true; | ||
64 | if(FILTER(active_sense) && m.status==status_system_active_sense) | ||
65 | return true; | ||
66 | |||
67 | if(FILTER(meta_sequence_number) && m.is_meta(meta_sequence_number)) | ||
68 | return true; | ||
69 | if(FILTER(meta_text) && m.is_meta(meta_text)) | ||
70 | return true; | ||
71 | if(FILTER(meta_copyright) && m.is_meta(meta_copyright)) | ||
72 | return true; | ||
73 | if(FILTER(meta_seq_track_name) && m.is_meta(meta_seq_track_name)) | ||
74 | return true; | ||
75 | if(FILTER(meta_instrument) && m.is_meta(meta_instrument)) | ||
76 | return true; | ||
77 | if(FILTER(meta_lyric) && m.is_meta(meta_lyric)) | ||
78 | return true; | ||
79 | if(FILTER(meta_marker) && m.is_meta(meta_marker)) | ||
80 | return true; | ||
81 | if(FILTER(meta_cue_point) && m.is_meta(meta_cue_point)) | ||
82 | return true; | ||
83 | if(FILTER(meta_patch_name) && m.is_meta(meta_patch_name)) | ||
84 | return true; | ||
85 | if(FILTER(meta_port_name) && m.is_meta(meta_port_name)) | ||
86 | return true; | ||
87 | if(FILTER(meta_tempo) && m.is_meta(meta_tempo)) | ||
88 | return true; | ||
89 | if(FILTER(meta_SMPTE_offset) && m.is_meta(meta_SMPTE_offset)) | ||
90 | return true; | ||
91 | if(FILTER(meta_time_sig) && m.is_meta(meta_time_sig)) | ||
92 | return true; | ||
93 | if(FILTER(meta_key_sig) && m.is_meta(meta_key_sig)) | ||
94 | return true; | ||
95 | if(FILTER(meta_proprietary) && m.is_meta(meta_proprietary)) | ||
96 | return true; | ||
97 | |||
98 | if(FILTER(meta_midi_channel) && m.is_meta(meta_midi_channel)) | ||
99 | return true; | ||
100 | if(FILTER(meta_midi_port) && m.is_meta(meta_midi_port)) | ||
101 | return true; | ||
102 | |||
103 | if(FILTER(meta_unknown) && m.is_meta()) { | ||
104 | const int known_metas[] = { | ||
105 | meta_sequence_number, meta_text, meta_copyright, meta_seq_track_name, | ||
106 | meta_instrument, meta_lyric, meta_marker, meta_cue_point, | ||
107 | meta_patch_name, meta_port_name, meta_EOT, meta_tempo, | ||
108 | meta_SMPTE_offset, meta_time_sig, meta_key_sig, meta_proprietary, | ||
109 | meta_midi_channel, meta_midi_port }; | ||
110 | const int* lastknown = &known_metas[sizeof(known_metas)/sizeof(*known_metas)]; | ||
111 | if( find( | ||
112 | known_metas, lastknown, | ||
113 | m.meta_status ) == lastknown ) { | ||
114 | return true; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | if(FILTER(meta) && m.is_meta()) | ||
119 | return true; | ||
120 | |||
121 | return false; | ||
122 | } | ||
123 | |||
124 | static bool event_is_filtered(const event_t& e) { | ||
125 | return message_is_filtered(e.message); | ||
126 | } | ||
127 | |||
128 | static bool MTrk_is_empty(const MTrk_t& t) { | ||
129 | return | ||
130 | t.events.empty() | ||
131 | || t.events.front().message.is_meta(meta_EOT); | ||
132 | } | ||
133 | |||
134 | struct filter_preset_t { | ||
135 | const char *id; | ||
136 | const char *help; | ||
137 | int filters[total_filters]; | ||
138 | } filter_presets[] = { | ||
139 | { "system_common", "strip system common messages", | ||
140 | { filter_sysex, filter_song_position_pointer, filter_song_select, | ||
141 | filter_tune_request, -1 } }, | ||
142 | { "system_runtime", "strip system runtime messages", | ||
143 | { filter_midi_clock, filter_midi_tick, filter_midi_start, | ||
144 | filter_midi_continue, filter_midi_stop, filter_active_sense, -1 } }, | ||
145 | { "meta_obsolete", "strip obsolete meta events", | ||
146 | { filter_meta_midi_channel, filter_meta_midi_port, -1 } }, | ||
147 | { "meta_texts", "strip textual meta events", | ||
148 | { filter_meta_text, filter_meta_copyright, | ||
149 | filter_meta_seq_track_name, filter_meta_instrument, | ||
150 | filter_meta_lyric, filter_meta_marker, filter_meta_cue_point, | ||
151 | filter_meta_patch_name, filter_meta_port_name, -1 } } | ||
152 | }; | ||
153 | |||
154 | inline ostream& operator<<(ostream& s,const filter_preset_t& fp) { | ||
155 | ios::fmtflags ff = s.flags(); | ||
156 | int w = s.width(25); | ||
157 | s.unsetf(ios::right); s.setf(ios::left); | ||
158 | s << fp.id << " " << fp.help; | ||
159 | s.width(w); | ||
160 | s.flags(ff); | ||
161 | return s; | ||
162 | } | ||
163 | |||
164 | static void usage(const char *p) { | ||
165 | cerr << PHEADER << endl | ||
166 | << PCOPY << endl << endl | ||
167 | << " " << p << " [options] [<input-file>[ <output-file>]]" << endl << endl | ||
168 | << " -h, --help" << endl | ||
169 | << " --usage display this text" << endl | ||
170 | << " -V, --version display version number" << endl | ||
171 | << " -L, --license show license" << endl | ||
172 | << " -f <filters>, --filter=<filters>" | ||
173 | << " specify the list of events (comma-separated) to" << endl | ||
174 | << " strip" << endl | ||
175 | << " -l, --list-filters" << endl | ||
176 | << " list available filters" << endl; | ||
177 | } | ||
178 | |||
179 | main(int argc,char **argv) { | ||
180 | try { | ||
181 | while(true) { | ||
182 | static struct option opts[] = { | ||
183 | { "help", no_argument, 0, 'h' }, | ||
184 | { "usage", no_argument, 0, 'h' }, | ||
185 | { "version", no_argument, 0, 'V' }, | ||
186 | { "license", no_argument, 0, 'L' }, | ||
187 | { "filter", no_argument, 0, 'f' }, | ||
188 | { "list-filters", no_argument, 0, 'l' }, | ||
189 | { NULL, 0, 0, 0 } | ||
190 | }; | ||
191 | int c = getopt_long(argc,argv,"f:hVLl",opts,NULL); | ||
192 | if(c==-1) | ||
193 | break; | ||
194 | switch(c) { | ||
195 | case 'h': | ||
196 | usage(*argv); | ||
197 | exit(0); | ||
198 | break; | ||
199 | case 'V': | ||
200 | cerr << VERSION << endl; | ||
201 | exit(0); | ||
202 | break; | ||
203 | case 'L': | ||
204 | extern const char *COPYING; | ||
205 | cerr << COPYING << endl; | ||
206 | exit(0); | ||
207 | break; | ||
208 | case 'f': | ||
209 | { | ||
210 | string fs = optarg; | ||
211 | while(!fs.empty()) { | ||
212 | string::size_type ns = fs.find_first_not_of(" :/,;"); | ||
213 | if(ns==string::npos) | ||
214 | break; | ||
215 | if(ns) | ||
216 | fs.erase(ns); | ||
217 | string::size_type s = fs.find_first_of(" :/,;"); | ||
218 | string f; | ||
219 | if(s==string::npos) { | ||
220 | f = fs; fs.clear(); | ||
221 | }else{ | ||
222 | f = fs.substr(0,ns); | ||
223 | fs.erase(0,ns+1); | ||
224 | } | ||
225 | for(int fn=0;fn<total_filters;++fn) { | ||
226 | filter_t& filter = filters[fn]; | ||
227 | for(int fid=0;fid<(sizeof(filter.ids)/sizeof(*filter.ids)) && filter.ids[fid];++fid) { | ||
228 | if(f == filter.ids[fid]) | ||
229 | filter.filter = true; | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | break; | ||
235 | case 'l': | ||
236 | cerr << PHEADER << endl | ||
237 | << PCOPY << endl << endl; | ||
238 | copy( | ||
239 | filters, &filters[total_filters], | ||
240 | ostream_iterator<filter_t>(cerr,"\n") ); | ||
241 | copy( | ||
242 | filter_presets, &filter_presets[sizeof(filter_presets)/sizeof(*filter_presets)], | ||
243 | ostream_iterator<filter_preset_t>(cerr,"\n") ); | ||
244 | exit(0); | ||
245 | break; | ||
246 | default: | ||
247 | cerr << "Huh??" << endl; | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | const char *infile = "-"; | ||
252 | if(optind<argc) | ||
253 | infile = argv[optind++]; | ||
254 | const char *oufile = "-"; | ||
255 | if(optind<argc) | ||
256 | oufile = argv[optind++]; | ||
257 | if(optind<argc) { | ||
258 | usage(*argv); | ||
259 | exit(1); | ||
260 | } | ||
261 | SMF_t in(infile); | ||
262 | for(SMF_t::tracks_t::iterator t=in.tracks.begin();t!=in.tracks.end();++t) { | ||
263 | for(events_t::iterator e=t->events.begin();e!=t->events.end();) { | ||
264 | if(event_is_filtered(*e)) { | ||
265 | events_t::iterator i = e++; | ||
266 | // we assume it is not the last event, since the last event | ||
267 | // (meta_EOT) is unfilterable | ||
268 | e->deltat += i->deltat; | ||
269 | t->events.erase(i); | ||
270 | }else | ||
271 | ++e; | ||
272 | } | ||
273 | } | ||
274 | in.tracks.erase( | ||
275 | remove_if( | ||
276 | in.tracks.begin(),in.tracks.end(), | ||
277 | MTrk_is_empty), | ||
278 | in.tracks.end() ); | ||
279 | if(in.tracks.empty()) { | ||
280 | cerr << "We have no MIDI data in the output file"; | ||
281 | } | ||
282 | in.mthd.ntracks = in.tracks.size(); | ||
283 | in.save(oufile); | ||
284 | return 0; | ||
285 | }catch(konforka::exception& e) { | ||
286 | cerr << "Oops... Konforka exception:" << endl | ||
287 | << " what: " << e.what() << endl | ||
288 | << " where: " << e.where() << endl; | ||
289 | return 1; | ||
290 | }catch(exception& e) { | ||
291 | cerr << "Oops... Exception:" << endl | ||
292 | << " what: " << e.what() << endl; | ||
293 | return 1; | ||
294 | } | ||
295 | } | ||