-rw-r--r-- | tools/midi2f0.cc | 151 |
1 files changed, 151 insertions, 0 deletions
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 | } | ||