summaryrefslogtreecommitdiffabout
path: root/tools
Side-by-side diff
Diffstat (limited to 'tools') (more/less context) (show whitespace changes)
-rw-r--r--tools/.gitignore11
-rw-r--r--tools/Makefile.am31
-rw-r--r--tools/enflesh_filters_list.sh20
-rw-r--r--tools/filters.list36
-rw-r--r--tools/midi2f0.cc151
-rw-r--r--tools/mididump.cc84
-rw-r--r--tools/midifilter.cc295
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 @@
+Makefile.in
+*.o
+midifilter
+midi2f0
+mididump
+.libs
+.deps
+Makefile
+COPYING.cc
+filters_enumeration.cc
+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 @@
+bin_PROGRAMS = midi2f0 midifilter mididump
+
+INCLUDES = -I${top_srcdir}/include ${KONFORKA_CFLAGS}
+LIBS += ${top_builddir}/lib/libmidillo.la ${KONFORKA_LIBS}
+
+midi2f0_SOURCES = midi2f0.cc \
+ COPYING.cc
+midi2f0_DEPENDENCIES = ${top_builddir}/lib/libmidillo.la
+
+midifilter_SOURCES = midifilter.cc \
+ COPYING.cc \
+ filters.list \
+ enflesh_filters_list.sh
+midifilter_DEPENDENCIES = ${top_builddir}/lib/libmidillo.la
+${srcdir}/midifilter.cc: filters_enumeration.cc filters_definition.cc
+filters_enumeration.cc filters_definition.cc: enflesh_filters_list.sh filters.list
+ sh $^ \
+ filters_enumeration.cc filters_definition.cc
+
+mididump_SOURCES = mididump.cc \
+ COPYING.cc
+mididump_DEPENDENCIES = ${top_builddir}/lib/libmidillo.la
+
+clean-local:
+ rm -f filters_enumeration.cc filters_definition.cc
+
+
+COPYING.cc: ${top_srcdir}/COPYING
+ echo "const char * COPYING =" >$@ || (rm $@;exit 1)
+ sed 's/"/\\"/g' $< | sed 's/^/\"/' | sed 's/$$/\\n\"/' >>$@ || (rm $@;exit 1)
+ 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 @@
+#!/bin/sh
+srcfile="${1}"
+enumfile="${2}"
+deffile="${3}"
+IFS=':'
+exec 5>${enumfile}
+exec 6>${deffile}
+SEQN=0
+LN=0
+cat ${srcfile} \
+ | while read id ids help ; do
+ LN="`expr ${LN} + 1`"
+ test -z "${id}" && continue
+ test "${id}" != "${id# }" && continue
+ echo "#line ${LN} \"${srcfile}\"" >&5
+ echo " filter_${id} = ${SEQN}," >&5
+ echo "#line ${LN} \"${srcfile}\"" >&6
+ echo ' { { "'$(echo $ids|sed -e 's-/-", "-g')'", 0 }, "'"${help}"'", false },' >&6
+ SEQN="`expr ${SEQN} + 1`"
+ 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 @@
+system:system:strip all system messages
+meta:meta:strip all meta events (except for EOT)
+
+sysex:sysex:strip sysex messages
+MTC_quarter_frame:MTC_quarter_frame/quarter_frame:strip 'MTC quarter frame' messages
+song_position_pointer:song_position_pointer:strip 'song position pointer' messages
+song_select:song_select:strip 'song select' messages
+tune_request:tune_request:strip 'tune request' messages
+
+midi_clock:midi_clock/timing_clock:strip 'midi clock' messages
+midi_tick:midi_tick:strip 'midi tick' messages
+midi_start:midi_start/start:strip 'midi start' messages
+midi_continue:midi_continue/continue:strip 'midi continue' messages
+midi_stop:midi_stop/stop:strip 'midi stop' messages
+active_sense:active_sense:strip 'active sense' messages
+
+meta_sequence_number:meta_sequence_number:strip 'sequence number' meta events
+meta_text:meta_text:strip 'text' meta events
+meta_copyright:meta_copyright:strip 'copyright' meta events
+meta_seq_track_name:meta_seq_track_name:strip 'sequence track name' meta events
+meta_instrument:meta_instrument:strip 'instrument' meta events
+meta_lyric:meta_lyric/meta_lyrics:strip 'lyric' meta events
+meta_marker:meta_marker:strip 'marker' meta events
+meta_cue_point:meta_cue_point:strip 'cue point' meta events
+meta_patch_name:meta_patch_name/meta_program_name:strip 'patch name' meta events
+meta_port_name:meta_port_name/meta_device_name:strip 'port name' meta events
+meta_tempo:meta_temp:strip 'tempo' meta events
+meta_SMPTE_offset:meta_SMPTE_offset:strip 'SMPTE offset' meta events
+meta_time_sig:meta_time_sig:strip 'time signature' meta events
+meta_key_sig:meta_key_sig:strip 'key signature' meta events
+meta_proprietary:meta_proprietary:strip 'proprietary' meta events
+
+meta_midi_channel:meta_midi_channel:strip 'midi channel' meta events
+meta_midi_port:meta_midi_port:strip 'midi port' meta events
+
+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 @@
+#include <getopt.h>
+#include <iostream>
+#include <algorithm>
+using namespace std;
+#include <konforka/exception.h>
+#include <midillo/SMF.h>
+using namespace midillo;
+
+#include "config.h"
+#define PHEADER PACKAGE " " VERSION " - midi2f0 - convert to midi format 0"
+#define PCOPY "Copyright (c) 2006 Klever Group"
+
+static void usage(const char *p) {
+ cerr << PHEADER << endl
+ << PCOPY << endl << endl
+ << " " << p << " [options] [<input-file>[ <output-file>]]" << endl << endl
+ << " -h, --help" << endl
+ << " --usage display this text" << endl
+ << " -V, --version display version number" << endl
+ << " -L, --license show license" << endl;
+}
+
+static bool MTrk_is_empty(const MTrk_t& t) {
+ return
+ t.events.empty()
+ || t.events.front().message.is_meta(meta_EOT);
+}
+
+static bool MTrk_deltat_lt(const MTrk_t& a,const MTrk_t& b) {
+ // we assume tracks aren't empty
+ return a.events.front().deltat < b.events.front().deltat;
+}
+
+static bool event_has_nonzero_deltat_or_is_EOT(const event_t& e) {
+ return e.deltat!=0 || e.message.is_meta(meta_EOT);
+}
+
+main(int argc,char **argv) {
+ try {
+ while(true) {
+ static struct option opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "usage", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V' },
+ { "license", no_argument, 0, 'L' },
+ { NULL, 0, 0, 0 }
+ };
+ int c = getopt_long(argc,argv,"hVL",opts,NULL);
+ if(c==-1)
+ break;
+ switch(c) {
+ case 'h':
+ usage(*argv);
+ exit(0);
+ break;
+ case 'V':
+ cerr << VERSION << endl;
+ exit(0);
+ break;
+ case 'L':
+ extern const char *COPYING;
+ cerr << COPYING << endl;
+ exit(0);
+ break;
+ default:
+ cerr << "Huh??" << endl;
+ break;
+ }
+ }
+ const char *infile = "-";
+ if(optind<argc)
+ infile = argv[optind++];
+ const char *oufile = "-";
+ if(optind<argc)
+ oufile = argv[optind++];
+ if(optind<argc) {
+ usage(*argv);
+ exit(1);
+ }
+ SMF_t in(infile);
+ if(in.mthd.fmt==MThd_t::fmt_0) {
+ cerr << "File is already SMF 0" << endl;
+ in.save(oufile);
+ }else if(in.mthd.fmt==MThd_t::fmt_1) {
+ cerr << "Converting from SMF 1 to SMF 0" << endl;
+ SMF_t ou;
+ ou.mthd = in.mthd;
+ ou.mthd.fmt = MThd_t::fmt_0; ou.mthd.ntracks = 1;
+ ou.tracks.resize(1);
+ MTrk_t& mtrk = ou.tracks.front();
+ events_t& evs = mtrk.events;
+ for(;;) {
+ // Cleaning up empty tracks
+ in.tracks.erase(
+ remove_if(
+ in.tracks.begin(),in.tracks.end(),
+ MTrk_is_empty),
+ in.tracks.end() );
+ if(in.tracks.empty())
+ break;
+ // Find the least deltat
+ unsigned long mindt = min_element(
+ in.tracks.begin(), in.tracks.end(),
+ MTrk_deltat_lt )->events.front().deltat;
+ int t=0;
+ bool reset = false;
+ for(SMF_t::tracks_t::iterator i=in.tracks.begin();i!=in.tracks.end();++i) {
+ if(i->events.front().deltat > mindt) {
+ i->events.front().deltat-=mindt;
+ }else{
+ do{
+ evs.splice(
+ evs.end(),
+ i->events,i->events.begin() );
+ if(reset)
+ evs.back().deltat = 0;
+ else
+ reset = true;
+ events_t::iterator lze=find_if(
+ i->events.begin(),i->events.end(),
+ event_has_nonzero_deltat_or_is_EOT );
+ evs.splice(
+ evs.end(),
+ i->events,i->events.begin(),lze );
+ }while( (!MTrk_is_empty(*i)) && i->events.front().deltat==0 );
+ }
+ }
+ }
+ event_t& eot = *evs.append_event();
+ eot.deltat=0;
+ eot.message.status = status_system_meta;
+ eot.message.meta_status = meta_EOT;
+ ou.save(oufile);
+ }else if(in.mthd.fmt==MThd_t::fmt_2) {
+ // TODO
+ cerr << "Not implemented" << endl;
+ }else{
+ cerr << "Unknown MIDI file format" << endl;
+ }
+ return 0;
+ }catch(konforka::exception& e) {
+ cerr << "Oops... Konforka exception:" << endl
+ << " what: " << e.what() << endl
+ << " where: " << e.where() << endl;
+ return 1;
+ }catch(exception& e) {
+ cerr << "Oops... Exception:" << endl
+ << " what: " << e.what() << endl;
+ return 1;
+ }
+}
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 @@
+#include <getopt.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <algorithm>
+using namespace std;
+#include <konforka/exception.h>
+#include <midillo/SMF.h>
+using namespace midillo;
+
+#include "config.h"
+#define PHEADER PACKAGE " " VERSION " - mididump - dump midi files"
+#define PCOPY "Copyright (c) 2006 Klever Group"
+
+static void usage(const char *p) {
+ cerr << PHEADER << endl
+ << PCOPY << endl << endl
+ << " " << p << " [options] [<input-file>[ <output-file>]]" << endl << endl
+ << " -h, --help" << endl
+ << " --usage display this text" << endl
+ << " -V, --version display version number" << endl
+ << " -L, --license show license" << endl;
+}
+
+main(int argc,char **argv) {
+ try {
+ while(true) {
+ static struct option opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "usage", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V' },
+ { "license", no_argument, 0, 'L' },
+ { NULL, 0, 0, 0 }
+ };
+ int c = getopt_long(argc,argv,"f:hVLl",opts,NULL);
+ if(c==-1)
+ break;
+ switch(c) {
+ case 'h':
+ usage(*argv);
+ exit(0);
+ break;
+ case 'V':
+ cerr << VERSION << endl;
+ exit(0);
+ break;
+ case 'L':
+ extern const char *COPYING;
+ cerr << COPYING << endl;
+ exit(0);
+ break;
+ default:
+ cerr << "Huh??" << endl;
+ break;
+ }
+ }
+ const char *infile = "-";
+ if(optind<argc)
+ infile = argv[optind++];
+ const char *oufile = "-";
+ if(optind<argc)
+ oufile = argv[optind++];
+ if(optind<argc) {
+ usage(*argv);
+ exit(1);
+ }
+ SMF_t in(infile);
+ if(strcmp(oufile,"-")) {
+ ofstream s(oufile); s << in;
+ }else{
+ cout << in;
+ }
+ return 0;
+ }catch(konforka::exception& e) {
+ cerr << "Oops... Konforka exception:" << endl
+ << " what: " << e.what() << endl
+ << " where: " << e.where() << endl;
+ return 1;
+ }catch(exception& e) {
+ cerr << "Oops... Exception:" << endl
+ << " what: " << e.what() << endl;
+ return 1;
+ }
+}
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 @@
+#include <getopt.h>
+#include <iostream>
+#include <string>
+#include <algorithm>
+#include <iterator>
+using namespace std;
+#include <konforka/exception.h>
+#include <midillo/SMF.h>
+using namespace midillo;
+
+#include "config.h"
+#define PHEADER PACKAGE " " VERSION " - midifilter - midi filter tool"
+#define PCOPY "Copyright (c) 2006 Klever Group"
+
+enum {
+# include "filters_enumeration.cc"
+ total_filters
+};
+
+struct filter_t {
+ const char *ids[5];
+ const char *help;
+ bool filter;
+} filters[] = {
+# include "filters_definition.cc"
+ {0,0,0}
+};
+#define FILTER(f) filters[filter_##f].filter
+
+inline ostream& operator<<(ostream& s,const filter_t& f) {
+ ios::fmtflags ff = s.flags();
+ int w = s.width(25);
+ s.unsetf(ios::right); s.setf(ios::left);
+ s << *f.ids << " " << f.help;
+ s.width(w);
+ s.flags(ff);
+ return s;
+}
+
+static bool message_is_filtered(const message_t& m) {
+ if(m.is_meta(meta_EOT))
+ return false;
+
+ if(FILTER(sysex) && (m.status==status_system_sysex || m.status==status_system_end_of_sysex))
+ return true;
+ if(FILTER(MTC_quarter_frame) && m.status==status_system_MTC_quarter_frame)
+ return true;
+ if(FILTER(song_position_pointer) && m.status==status_system_song_position_pointer)
+ return true;
+ if(FILTER(song_select) && m.status==status_system_song_select)
+ return true;
+ if(FILTER(tune_request) && m.status==status_system_tune_request)
+ return true;
+ if(FILTER(midi_clock) && m.status==status_system_midi_clock)
+ return true;
+ if(FILTER(midi_tick) && m.status==status_system_midi_tick)
+ return true;
+ if(FILTER(midi_start) && m.status==status_system_midi_start)
+ return true;
+ if(FILTER(midi_continue) && m.status==status_system_midi_continue)
+ return true;
+ if(FILTER(midi_stop) && m.status==status_system_midi_stop)
+ return true;
+ if(FILTER(active_sense) && m.status==status_system_active_sense)
+ return true;
+
+ if(FILTER(meta_sequence_number) && m.is_meta(meta_sequence_number))
+ return true;
+ if(FILTER(meta_text) && m.is_meta(meta_text))
+ return true;
+ if(FILTER(meta_copyright) && m.is_meta(meta_copyright))
+ return true;
+ if(FILTER(meta_seq_track_name) && m.is_meta(meta_seq_track_name))
+ return true;
+ if(FILTER(meta_instrument) && m.is_meta(meta_instrument))
+ return true;
+ if(FILTER(meta_lyric) && m.is_meta(meta_lyric))
+ return true;
+ if(FILTER(meta_marker) && m.is_meta(meta_marker))
+ return true;
+ if(FILTER(meta_cue_point) && m.is_meta(meta_cue_point))
+ return true;
+ if(FILTER(meta_patch_name) && m.is_meta(meta_patch_name))
+ return true;
+ if(FILTER(meta_port_name) && m.is_meta(meta_port_name))
+ return true;
+ if(FILTER(meta_tempo) && m.is_meta(meta_tempo))
+ return true;
+ if(FILTER(meta_SMPTE_offset) && m.is_meta(meta_SMPTE_offset))
+ return true;
+ if(FILTER(meta_time_sig) && m.is_meta(meta_time_sig))
+ return true;
+ if(FILTER(meta_key_sig) && m.is_meta(meta_key_sig))
+ return true;
+ if(FILTER(meta_proprietary) && m.is_meta(meta_proprietary))
+ return true;
+
+ if(FILTER(meta_midi_channel) && m.is_meta(meta_midi_channel))
+ return true;
+ if(FILTER(meta_midi_port) && m.is_meta(meta_midi_port))
+ return true;
+
+ if(FILTER(meta_unknown) && m.is_meta()) {
+ const int known_metas[] = {
+ meta_sequence_number, meta_text, meta_copyright, meta_seq_track_name,
+ meta_instrument, meta_lyric, meta_marker, meta_cue_point,
+ meta_patch_name, meta_port_name, meta_EOT, meta_tempo,
+ meta_SMPTE_offset, meta_time_sig, meta_key_sig, meta_proprietary,
+ meta_midi_channel, meta_midi_port };
+ const int* lastknown = &known_metas[sizeof(known_metas)/sizeof(*known_metas)];
+ if( find(
+ known_metas, lastknown,
+ m.meta_status ) == lastknown ) {
+ return true;
+ }
+ }
+
+ if(FILTER(meta) && m.is_meta())
+ return true;
+
+ return false;
+}
+
+static bool event_is_filtered(const event_t& e) {
+ return message_is_filtered(e.message);
+}
+
+static bool MTrk_is_empty(const MTrk_t& t) {
+ return
+ t.events.empty()
+ || t.events.front().message.is_meta(meta_EOT);
+}
+
+struct filter_preset_t {
+ const char *id;
+ const char *help;
+ int filters[total_filters];
+} filter_presets[] = {
+ { "system_common", "strip system common messages",
+ { filter_sysex, filter_song_position_pointer, filter_song_select,
+ filter_tune_request, -1 } },
+ { "system_runtime", "strip system runtime messages",
+ { filter_midi_clock, filter_midi_tick, filter_midi_start,
+ filter_midi_continue, filter_midi_stop, filter_active_sense, -1 } },
+ { "meta_obsolete", "strip obsolete meta events",
+ { filter_meta_midi_channel, filter_meta_midi_port, -1 } },
+ { "meta_texts", "strip textual meta events",
+ { filter_meta_text, filter_meta_copyright,
+ filter_meta_seq_track_name, filter_meta_instrument,
+ filter_meta_lyric, filter_meta_marker, filter_meta_cue_point,
+ filter_meta_patch_name, filter_meta_port_name, -1 } }
+};
+
+inline ostream& operator<<(ostream& s,const filter_preset_t& fp) {
+ ios::fmtflags ff = s.flags();
+ int w = s.width(25);
+ s.unsetf(ios::right); s.setf(ios::left);
+ s << fp.id << " " << fp.help;
+ s.width(w);
+ s.flags(ff);
+ return s;
+}
+
+static void usage(const char *p) {
+ cerr << PHEADER << endl
+ << PCOPY << endl << endl
+ << " " << p << " [options] [<input-file>[ <output-file>]]" << endl << endl
+ << " -h, --help" << endl
+ << " --usage display this text" << endl
+ << " -V, --version display version number" << endl
+ << " -L, --license show license" << endl
+ << " -f <filters>, --filter=<filters>"
+ << " specify the list of events (comma-separated) to" << endl
+ << " strip" << endl
+ << " -l, --list-filters" << endl
+ << " list available filters" << endl;
+}
+
+main(int argc,char **argv) {
+ try {
+ while(true) {
+ static struct option opts[] = {
+ { "help", no_argument, 0, 'h' },
+ { "usage", no_argument, 0, 'h' },
+ { "version", no_argument, 0, 'V' },
+ { "license", no_argument, 0, 'L' },
+ { "filter", no_argument, 0, 'f' },
+ { "list-filters", no_argument, 0, 'l' },
+ { NULL, 0, 0, 0 }
+ };
+ int c = getopt_long(argc,argv,"f:hVLl",opts,NULL);
+ if(c==-1)
+ break;
+ switch(c) {
+ case 'h':
+ usage(*argv);
+ exit(0);
+ break;
+ case 'V':
+ cerr << VERSION << endl;
+ exit(0);
+ break;
+ case 'L':
+ extern const char *COPYING;
+ cerr << COPYING << endl;
+ exit(0);
+ break;
+ case 'f':
+ {
+ string fs = optarg;
+ while(!fs.empty()) {
+ string::size_type ns = fs.find_first_not_of(" :/,;");
+ if(ns==string::npos)
+ break;
+ if(ns)
+ fs.erase(ns);
+ string::size_type s = fs.find_first_of(" :/,;");
+ string f;
+ if(s==string::npos) {
+ f = fs; fs.clear();
+ }else{
+ f = fs.substr(0,ns);
+ fs.erase(0,ns+1);
+ }
+ for(int fn=0;fn<total_filters;++fn) {
+ filter_t& filter = filters[fn];
+ for(int fid=0;fid<(sizeof(filter.ids)/sizeof(*filter.ids)) && filter.ids[fid];++fid) {
+ if(f == filter.ids[fid])
+ filter.filter = true;
+ }
+ }
+ }
+ }
+ break;
+ case 'l':
+ cerr << PHEADER << endl
+ << PCOPY << endl << endl;
+ copy(
+ filters, &filters[total_filters],
+ ostream_iterator<filter_t>(cerr,"\n") );
+ copy(
+ filter_presets, &filter_presets[sizeof(filter_presets)/sizeof(*filter_presets)],
+ ostream_iterator<filter_preset_t>(cerr,"\n") );
+ exit(0);
+ break;
+ default:
+ cerr << "Huh??" << endl;
+ break;
+ }
+ }
+ const char *infile = "-";
+ if(optind<argc)
+ infile = argv[optind++];
+ const char *oufile = "-";
+ if(optind<argc)
+ oufile = argv[optind++];
+ if(optind<argc) {
+ usage(*argv);
+ exit(1);
+ }
+ SMF_t in(infile);
+ for(SMF_t::tracks_t::iterator t=in.tracks.begin();t!=in.tracks.end();++t) {
+ for(events_t::iterator e=t->events.begin();e!=t->events.end();) {
+ if(event_is_filtered(*e)) {
+ events_t::iterator i = e++;
+ // we assume it is not the last event, since the last event
+ // (meta_EOT) is unfilterable
+ e->deltat += i->deltat;
+ t->events.erase(i);
+ }else
+ ++e;
+ }
+ }
+ in.tracks.erase(
+ remove_if(
+ in.tracks.begin(),in.tracks.end(),
+ MTrk_is_empty),
+ in.tracks.end() );
+ if(in.tracks.empty()) {
+ cerr << "We have no MIDI data in the output file";
+ }
+ in.mthd.ntracks = in.tracks.size();
+ in.save(oufile);
+ return 0;
+ }catch(konforka::exception& e) {
+ cerr << "Oops... Konforka exception:" << endl
+ << " what: " << e.what() << endl
+ << " where: " << e.where() << endl;
+ return 1;
+ }catch(exception& e) {
+ cerr << "Oops... Exception:" << endl
+ << " what: " << e.what() << endl;
+ return 1;
+ }
+}