-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 @@ +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; + } +} |