-rw-r--r-- | tools/.gitignore | 11 | ||||
-rw-r--r-- | tools/Makefile.am | 31 | ||||
-rw-r--r-- | tools/enflesh_filters_list.sh | 20 | ||||
-rw-r--r-- | tools/filters.list | 36 | ||||
-rw-r--r-- | tools/midi2f0.cc | 151 | ||||
-rw-r--r-- | tools/mididump.cc | 84 | ||||
-rw-r--r-- | tools/midifilter.cc | 295 |
7 files changed, 628 insertions, 0 deletions
diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 0000000..6d68099 --- a/dev/null +++ b/tools/.gitignore | |||
@@ -0,0 +1,11 @@ | |||
1 | Makefile.in | ||
2 | *.o | ||
3 | midifilter | ||
4 | midi2f0 | ||
5 | mididump | ||
6 | .libs | ||
7 | .deps | ||
8 | Makefile | ||
9 | COPYING.cc | ||
10 | filters_enumeration.cc | ||
11 | filters_definition.cc | ||
diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..811c4f8 --- a/dev/null +++ b/tools/Makefile.am | |||
@@ -0,0 +1,31 @@ | |||
1 | bin_PROGRAMS = midi2f0 midifilter mididump | ||
2 | |||
3 | INCLUDES = -I${top_srcdir}/include ${KONFORKA_CFLAGS} | ||
4 | LIBS += ${top_builddir}/lib/libmidillo.la ${KONFORKA_LIBS} | ||
5 | |||
6 | midi2f0_SOURCES = midi2f0.cc \ | ||
7 | COPYING.cc | ||
8 | midi2f0_DEPENDENCIES = ${top_builddir}/lib/libmidillo.la | ||
9 | |||
10 | midifilter_SOURCES = midifilter.cc \ | ||
11 | COPYING.cc \ | ||
12 | filters.list \ | ||
13 | enflesh_filters_list.sh | ||
14 | midifilter_DEPENDENCIES = ${top_builddir}/lib/libmidillo.la | ||
15 | ${srcdir}/midifilter.cc: filters_enumeration.cc filters_definition.cc | ||
16 | filters_enumeration.cc filters_definition.cc: enflesh_filters_list.sh filters.list | ||
17 | sh $^ \ | ||
18 | filters_enumeration.cc filters_definition.cc | ||
19 | |||
20 | mididump_SOURCES = mididump.cc \ | ||
21 | COPYING.cc | ||
22 | mididump_DEPENDENCIES = ${top_builddir}/lib/libmidillo.la | ||
23 | |||
24 | clean-local: | ||
25 | rm -f filters_enumeration.cc filters_definition.cc | ||
26 | |||
27 | |||
28 | COPYING.cc: ${top_srcdir}/COPYING | ||
29 | echo "const char * COPYING =" >$@ || (rm $@;exit 1) | ||
30 | sed 's/"/\\"/g' $< | sed 's/^/\"/' | sed 's/$$/\\n\"/' >>$@ || (rm $@;exit 1) | ||
31 | echo ";" >>$@ || (rm $@;exit 1) | ||
diff --git a/tools/enflesh_filters_list.sh b/tools/enflesh_filters_list.sh new file mode 100644 index 0000000..f1d8dfc --- a/dev/null +++ b/tools/enflesh_filters_list.sh | |||
@@ -0,0 +1,20 @@ | |||
1 | #!/bin/sh | ||
2 | srcfile="${1}" | ||
3 | enumfile="${2}" | ||
4 | deffile="${3}" | ||
5 | IFS=':' | ||
6 | exec 5>${enumfile} | ||
7 | exec 6>${deffile} | ||
8 | SEQN=0 | ||
9 | LN=0 | ||
10 | cat ${srcfile} \ | ||
11 | | while read id ids help ; do | ||
12 | LN="`expr ${LN} + 1`" | ||
13 | test -z "${id}" && continue | ||
14 | test "${id}" != "${id# }" && continue | ||
15 | echo "#line ${LN} \"${srcfile}\"" >&5 | ||
16 | echo " filter_${id} = ${SEQN}," >&5 | ||
17 | echo "#line ${LN} \"${srcfile}\"" >&6 | ||
18 | echo ' { { "'$(echo $ids|sed -e 's-/-", "-g')'", 0 }, "'"${help}"'", false },' >&6 | ||
19 | SEQN="`expr ${SEQN} + 1`" | ||
20 | done | ||
diff --git a/tools/filters.list b/tools/filters.list new file mode 100644 index 0000000..c0fb951 --- a/dev/null +++ b/tools/filters.list | |||
@@ -0,0 +1,36 @@ | |||
1 | system:system:strip all system messages | ||
2 | meta:meta:strip all meta events (except for EOT) | ||
3 | |||
4 | sysex:sysex:strip sysex messages | ||
5 | MTC_quarter_frame:MTC_quarter_frame/quarter_frame:strip 'MTC quarter frame' messages | ||
6 | song_position_pointer:song_position_pointer:strip 'song position pointer' messages | ||
7 | song_select:song_select:strip 'song select' messages | ||
8 | tune_request:tune_request:strip 'tune request' messages | ||
9 | |||
10 | midi_clock:midi_clock/timing_clock:strip 'midi clock' messages | ||
11 | midi_tick:midi_tick:strip 'midi tick' messages | ||
12 | midi_start:midi_start/start:strip 'midi start' messages | ||
13 | midi_continue:midi_continue/continue:strip 'midi continue' messages | ||
14 | midi_stop:midi_stop/stop:strip 'midi stop' messages | ||
15 | active_sense:active_sense:strip 'active sense' messages | ||
16 | |||
17 | meta_sequence_number:meta_sequence_number:strip 'sequence number' meta events | ||
18 | meta_text:meta_text:strip 'text' meta events | ||
19 | meta_copyright:meta_copyright:strip 'copyright' meta events | ||
20 | meta_seq_track_name:meta_seq_track_name:strip 'sequence track name' meta events | ||
21 | meta_instrument:meta_instrument:strip 'instrument' meta events | ||
22 | meta_lyric:meta_lyric/meta_lyrics:strip 'lyric' meta events | ||
23 | meta_marker:meta_marker:strip 'marker' meta events | ||
24 | meta_cue_point:meta_cue_point:strip 'cue point' meta events | ||
25 | meta_patch_name:meta_patch_name/meta_program_name:strip 'patch name' meta events | ||
26 | meta_port_name:meta_port_name/meta_device_name:strip 'port name' meta events | ||
27 | meta_tempo:meta_temp:strip 'tempo' meta events | ||
28 | meta_SMPTE_offset:meta_SMPTE_offset:strip 'SMPTE offset' meta events | ||
29 | meta_time_sig:meta_time_sig:strip 'time signature' meta events | ||
30 | meta_key_sig:meta_key_sig:strip 'key signature' meta events | ||
31 | meta_proprietary:meta_proprietary:strip 'proprietary' meta events | ||
32 | |||
33 | meta_midi_channel:meta_midi_channel:strip 'midi channel' meta events | ||
34 | meta_midi_port:meta_midi_port:strip 'midi port' meta events | ||
35 | |||
36 | meta_unknown:meta_unknown:strip meta events not known by midillo | ||
diff --git a/tools/midi2f0.cc b/tools/midi2f0.cc new file mode 100644 index 0000000..dc95be6 --- a/dev/null +++ b/tools/midi2f0.cc | |||
@@ -0,0 +1,151 @@ | |||
1 | #include <getopt.h> | ||
2 | #include <iostream> | ||
3 | #include <algorithm> | ||
4 | using namespace std; | ||
5 | #include <konforka/exception.h> | ||
6 | #include <midillo/SMF.h> | ||
7 | using namespace midillo; | ||
8 | |||
9 | #include "config.h" | ||
10 | #define PHEADER PACKAGE " " VERSION " - midi2f0 - convert to midi format 0" | ||
11 | #define PCOPY "Copyright (c) 2006 Klever Group" | ||
12 | |||
13 | static void usage(const char *p) { | ||
14 | cerr << PHEADER << endl | ||
15 | << PCOPY << endl << endl | ||
16 | << " " << p << " [options] [<input-file>[ <output-file>]]" << endl << endl | ||
17 | << " -h, --help" << endl | ||
18 | << " --usage display this text" << endl | ||
19 | << " -V, --version display version number" << endl | ||
20 | << " -L, --license show license" << endl; | ||
21 | } | ||
22 | |||
23 | static bool MTrk_is_empty(const MTrk_t& t) { | ||
24 | return | ||
25 | t.events.empty() | ||
26 | || t.events.front().message.is_meta(meta_EOT); | ||
27 | } | ||
28 | |||
29 | static bool MTrk_deltat_lt(const MTrk_t& a,const MTrk_t& b) { | ||
30 | // we assume tracks aren't empty | ||
31 | return a.events.front().deltat < b.events.front().deltat; | ||
32 | } | ||
33 | |||
34 | static bool event_has_nonzero_deltat_or_is_EOT(const event_t& e) { | ||
35 | return e.deltat!=0 || e.message.is_meta(meta_EOT); | ||
36 | } | ||
37 | |||
38 | main(int argc,char **argv) { | ||
39 | try { | ||
40 | while(true) { | ||
41 | static struct option opts[] = { | ||
42 | { "help", no_argument, 0, 'h' }, | ||
43 | { "usage", no_argument, 0, 'h' }, | ||
44 | { "version", no_argument, 0, 'V' }, | ||
45 | { "license", no_argument, 0, 'L' }, | ||
46 | { NULL, 0, 0, 0 } | ||
47 | }; | ||
48 | int c = getopt_long(argc,argv,"hVL",opts,NULL); | ||
49 | if(c==-1) | ||
50 | break; | ||
51 | switch(c) { | ||
52 | case 'h': | ||
53 | usage(*argv); | ||
54 | exit(0); | ||
55 | break; | ||
56 | case 'V': | ||
57 | cerr << VERSION << endl; | ||
58 | exit(0); | ||
59 | break; | ||
60 | case 'L': | ||
61 | extern const char *COPYING; | ||
62 | cerr << COPYING << endl; | ||
63 | exit(0); | ||
64 | break; | ||
65 | default: | ||
66 | cerr << "Huh??" << endl; | ||
67 | break; | ||
68 | } | ||
69 | } | ||
70 | const char *infile = "-"; | ||
71 | if(optind<argc) | ||
72 | infile = argv[optind++]; | ||
73 | const char *oufile = "-"; | ||
74 | if(optind<argc) | ||
75 | oufile = argv[optind++]; | ||
76 | if(optind<argc) { | ||
77 | usage(*argv); | ||
78 | exit(1); | ||
79 | } | ||
80 | SMF_t in(infile); | ||
81 | if(in.mthd.fmt==MThd_t::fmt_0) { | ||
82 | cerr << "File is already SMF 0" << endl; | ||
83 | in.save(oufile); | ||
84 | }else if(in.mthd.fmt==MThd_t::fmt_1) { | ||
85 | cerr << "Converting from SMF 1 to SMF 0" << endl; | ||
86 | SMF_t ou; | ||
87 | ou.mthd = in.mthd; | ||
88 | ou.mthd.fmt = MThd_t::fmt_0; ou.mthd.ntracks = 1; | ||
89 | ou.tracks.resize(1); | ||
90 | MTrk_t& mtrk = ou.tracks.front(); | ||
91 | events_t& evs = mtrk.events; | ||
92 | for(;;) { | ||
93 | // Cleaning up empty tracks | ||
94 | in.tracks.erase( | ||
95 | remove_if( | ||
96 | in.tracks.begin(),in.tracks.end(), | ||
97 | MTrk_is_empty), | ||
98 | in.tracks.end() ); | ||
99 | if(in.tracks.empty()) | ||
100 | break; | ||
101 | // Find the least deltat | ||
102 | unsigned long mindt = min_element( | ||
103 | in.tracks.begin(), in.tracks.end(), | ||
104 | MTrk_deltat_lt )->events.front().deltat; | ||
105 | int t=0; | ||
106 | bool reset = false; | ||
107 | for(SMF_t::tracks_t::iterator i=in.tracks.begin();i!=in.tracks.end();++i) { | ||
108 | if(i->events.front().deltat > mindt) { | ||
109 | i->events.front().deltat-=mindt; | ||
110 | }else{ | ||
111 | do{ | ||
112 | evs.splice( | ||
113 | evs.end(), | ||
114 | i->events,i->events.begin() ); | ||
115 | if(reset) | ||
116 | evs.back().deltat = 0; | ||
117 | else | ||
118 | reset = true; | ||
119 | events_t::iterator lze=find_if( | ||
120 | i->events.begin(),i->events.end(), | ||
121 | event_has_nonzero_deltat_or_is_EOT ); | ||
122 | evs.splice( | ||
123 | evs.end(), | ||
124 | i->events,i->events.begin(),lze ); | ||
125 | }while( (!MTrk_is_empty(*i)) && i->events.front().deltat==0 ); | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | event_t& eot = *evs.append_event(); | ||
130 | eot.deltat=0; | ||
131 | eot.message.status = status_system_meta; | ||
132 | eot.message.meta_status = meta_EOT; | ||
133 | ou.save(oufile); | ||
134 | }else if(in.mthd.fmt==MThd_t::fmt_2) { | ||
135 | // TODO | ||
136 | cerr << "Not implemented" << endl; | ||
137 | }else{ | ||
138 | cerr << "Unknown MIDI file format" << endl; | ||
139 | } | ||
140 | return 0; | ||
141 | }catch(konforka::exception& e) { | ||
142 | cerr << "Oops... Konforka exception:" << endl | ||
143 | << " what: " << e.what() << endl | ||
144 | << " where: " << e.where() << endl; | ||
145 | return 1; | ||
146 | }catch(exception& e) { | ||
147 | cerr << "Oops... Exception:" << endl | ||
148 | << " what: " << e.what() << endl; | ||
149 | return 1; | ||
150 | } | ||
151 | } | ||
diff --git a/tools/mididump.cc b/tools/mididump.cc new file mode 100644 index 0000000..83b7086 --- a/dev/null +++ b/tools/mididump.cc | |||
@@ -0,0 +1,84 @@ | |||
1 | #include <getopt.h> | ||
2 | #include <iostream> | ||
3 | #include <fstream> | ||
4 | #include <string> | ||
5 | #include <algorithm> | ||
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 " - mididump - dump midi files" | ||
13 | #define PCOPY "Copyright (c) 2006 Klever Group" | ||
14 | |||
15 | static void usage(const char *p) { | ||
16 | cerr << PHEADER << endl | ||
17 | << PCOPY << endl << endl | ||
18 | << " " << p << " [options] [<input-file>[ <output-file>]]" << endl << endl | ||
19 | << " -h, --help" << endl | ||
20 | << " --usage display this text" << endl | ||
21 | << " -V, --version display version number" << endl | ||
22 | << " -L, --license show license" << endl; | ||
23 | } | ||
24 | |||
25 | main(int argc,char **argv) { | ||
26 | try { | ||
27 | while(true) { | ||
28 | static struct option opts[] = { | ||
29 | { "help", no_argument, 0, 'h' }, | ||
30 | { "usage", no_argument, 0, 'h' }, | ||
31 | { "version", no_argument, 0, 'V' }, | ||
32 | { "license", no_argument, 0, 'L' }, | ||
33 | { NULL, 0, 0, 0 } | ||
34 | }; | ||
35 | int c = getopt_long(argc,argv,"f:hVLl",opts,NULL); | ||
36 | if(c==-1) | ||
37 | break; | ||
38 | switch(c) { | ||
39 | case 'h': | ||
40 | usage(*argv); | ||
41 | exit(0); | ||
42 | break; | ||
43 | case 'V': | ||
44 | cerr << VERSION << endl; | ||
45 | exit(0); | ||
46 | break; | ||
47 | case 'L': | ||
48 | extern const char *COPYING; | ||
49 | cerr << COPYING << endl; | ||
50 | exit(0); | ||
51 | break; | ||
52 | default: | ||
53 | cerr << "Huh??" << endl; | ||
54 | break; | ||
55 | } | ||
56 | } | ||
57 | const char *infile = "-"; | ||
58 | if(optind<argc) | ||
59 | infile = argv[optind++]; | ||
60 | const char *oufile = "-"; | ||
61 | if(optind<argc) | ||
62 | oufile = argv[optind++]; | ||
63 | if(optind<argc) { | ||
64 | usage(*argv); | ||
65 | exit(1); | ||
66 | } | ||
67 | SMF_t in(infile); | ||
68 | if(strcmp(oufile,"-")) { | ||
69 | ofstream s(oufile); s << in; | ||
70 | }else{ | ||
71 | cout << in; | ||
72 | } | ||
73 | return 0; | ||
74 | }catch(konforka::exception& e) { | ||
75 | cerr << "Oops... Konforka exception:" << endl | ||
76 | << " what: " << e.what() << endl | ||
77 | << " where: " << e.where() << endl; | ||
78 | return 1; | ||
79 | }catch(exception& e) { | ||
80 | cerr << "Oops... Exception:" << endl | ||
81 | << " what: " << e.what() << endl; | ||
82 | return 1; | ||
83 | } | ||
84 | } | ||
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 | } | ||