summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitignore22
-rw-r--r--AUTHORS3
-rw-r--r--COPYING19
-rw-r--r--ChangeLog0
-rw-r--r--Doxyfile.in247
-rw-r--r--Makefile.am22
-rw-r--r--NEWS.xml6
-rw-r--r--NEWS.xsl24
-rw-r--r--README0
-rw-r--r--acinclude.m480
-rwxr-xr-xautogen.sh9
-rw-r--r--configure.ac55
-rw-r--r--include/.gitignore2
-rw-r--r--include/Makefile.am5
-rw-r--r--include/midillo/MThd.h74
-rw-r--r--include/midillo/MTrk.h54
-rw-r--r--include/midillo/SMF.h87
-rw-r--r--include/midillo/chunk.h88
-rw-r--r--include/midillo/event.h99
-rw-r--r--include/midillo/exception.h55
-rw-r--r--include/midillo/message.h200
-rw-r--r--include/midillo/util.h63
-rw-r--r--lib/.gitignore7
-rw-r--r--lib/MThd.cc38
-rw-r--r--lib/MTrk.cc34
-rw-r--r--lib/Makefile.am15
-rw-r--r--lib/SMF.cc62
-rw-r--r--lib/chunk.cc31
-rw-r--r--lib/event.cc58
-rw-r--r--lib/message.cc247
-rw-r--r--lib/util.cc96
-rw-r--r--man/.gitignore2
-rw-r--r--man/Makefile.am3
-rw-r--r--man/midi2f0.185
-rw-r--r--man/mididump.172
-rw-r--r--man/midifilter.193
-rw-r--r--midillo.pc.in11
-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
44 files changed, 2696 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..204d437
--- a/dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+configure
+Makefile.in
+Doxyfile
+config.log
+depcomp
+config.guess
+config.h
+ltmain.sh
+config.sub
+INSTALL
+NEWS
+Makefile
+config.status
+midillo.pc
+stamp-h1
+config.h.in
+libtool
+autom4te.cache
+missing
+aclocal.m4
+install-sh
+doxydox
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a9fb0c7
--- a/dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Klever dissected:
+ Michael 'hacker' Krelin <hacker@klever.net>
+ Leonid Ivanov <kamel@klever.net>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..9a21651
--- a/dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+Copyright (c) 2006 Klever Group (http://www.klever.net/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/ChangeLog
diff --git a/Doxyfile.in b/Doxyfile.in
new file mode 100644
index 0000000..95552d7
--- a/dev/null
+++ b/Doxyfile.in
@@ -0,0 +1,247 @@
+# Doxyfile 1.3.9.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = @PACKAGE@
+PROJECT_NUMBER = @VERSION@
+OUTPUT_DIRECTORY = @builddir@/doxydox
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = include
+STRIP_FROM_INC_PATH = include
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = YES
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = NO
+SHOW_DIRECTORIES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+INPUT = \
+ @srcdir@/include/midillo/
+FILE_PATTERNS = *.h
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 2
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+GENERATE_XML = YES
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = @HAVE_DOT@
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH = @DOT@
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 0
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+SEARCHENGINE = NO
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..5a2a2c7
--- a/dev/null
+++ b/Makefile.am
@@ -0,0 +1,22 @@
+SUBDIRS=include lib tools man
+EXTRA_DIST= NEWS NEWS.xml NEWS.xsl
+
+DISTCHECK_CONFIGURE_FLAGS=--with-pkgconfigdir=$${dc_install_base}/lib/pkgconfig
+if HAVE_PKGCONFIG
+pkgconfigdir=@PKGCONFIG_DIR@
+pkgconfig_DATA=midillo.pc
+endif
+
+all-local: NEWS
+if HAVE_DOXYGEN
+clean-local:
+ rm -rf doxydox
+endif
+
+NEWS: NEWS.xsl NEWS.xml
+ ${XSLTPROC} -o $@ NEWS.xsl NEWS.xml
+
+if HAVE_DOXYGEN
+dox:
+ ${DOXYGEN}
+endif
diff --git a/NEWS.xml b/NEWS.xml
new file mode 100644
index 0000000..f30ed3b
--- a/dev/null
+++ b/NEWS.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<news>
+ <version version="0.0" date="August 1st, 2006">
+ <ni>Initial release</ni>
+ </version>
+</news>
diff --git a/NEWS.xsl b/NEWS.xsl
new file mode 100644
index 0000000..7c71307
--- a/dev/null
+++ b/NEWS.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="us-ascii"?>
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ >
+ <xsl:output
+ method="text"
+ encoding="us-ascii"
+ media-type="text/plain" />
+
+ <xsl:template match="news">
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="version">
+ <xsl:value-of select="concat(@version,' (',@date,')&#xA;')"/>
+ <xsl:apply-templates/>
+ </xsl:template>
+ <xsl:template match="ni">
+ <xsl:text> - </xsl:text>
+ <xsl:apply-templates mode="text"/>
+ <xsl:text>&#xA;</xsl:text>
+ </xsl:template>
+ <xsl:template match="*|text()"/>
+
+</xsl:stylesheet>
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/README
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..ec2c50f
--- a/dev/null
+++ b/acinclude.m4
@@ -0,0 +1,80 @@
+dnl AC_WITH_PKGCONFIG([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: PKGCONFIG_PKGCONFIG PKGCONFIG_DIR
+dnl AM_CONDTIONAL: HAVE_PKGCONFIG
+AC_DEFUN([AC_WITH_PKGCONFIG],[
+ PKGCONFIG_PKGCONFIG=""
+ PKGCONFIG_DIR=""
+ HAVE_PKGCONFIG="no"
+ EXPLICIT_PKGCONFIGDIR="no"
+ test -z "${WANT_PKGCONFIG}" && WANT_PKGCONFIG=""
+ AC_PATH_PROG([PKGCONFIG_PKGCONFIG],[pkg-config],[false])
+ if test "${PKGCONFIG_PKGCONFIG}" != "false" ; then
+ AC_ARG_WITH([pkgconfigdir],
+ AC_HELP_STRING([--with-pkgconfigdir=dir],[Specify pkgconfig directory]),
+ [
+ if test "${withval}" = "no" ; then
+ WANT_PKGCONFIG="no"
+ else
+ PKGCONFIG_DIR="${withval}"
+ EXPLICIT_PKGCONFIGDIR="yes"
+ fi
+ ],[
+ AC_MSG_CHECKING([for pkgconfig directory])
+ PKGCONFIG_DIR="`${PKGCONFIG_PKGCONFIG} --debug 2>&1 | grep '^Scanning'| head -n 1 | cut -d\' -f2-|cut -d\' -f1`"
+ AC_MSG_RESULT([${PKGCONFIG_DIR}])
+ ]
+ )
+ if test -d "${PKGCONFIG_DIR}" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ AC_MSG_NOTICE([unexistent pkgconfig directory: ${PKGCONFIG_DIR}])
+ if test "${EXPLICIT_PKGCONFIGDIR}" = "yes" ; then
+ HAVE_PKGCONFIG=yes
+ AC_SUBST([PKGCONFIG_PKGCONFIG])
+ AC_SUBST([PKGCONFIG_DIR])
+ else
+ ifelse([$2], , :, [$2])
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_PKGCONFIG],[test "${HAVE_PKGCONFIG}" = "yes"])
+])
+
+dnl AC_WITH_DOXYGEN([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOXYGEN HAVE_DOXYGEN
+dnl AM_CONDTIONAL: HAVE_DOXYGEN
+AC_DEFUN([AC_WITH_DOXYGEN],[
+ HAVE_DOXYGEN="no"
+ AC_PATH_PROG([DOXYGEN],[doxygen],[false])
+ if test "${DOXYGEN}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOXYGEN="yes"
+ AC_SUBST([DOXYGEN])
+ $1
+ fi
+ AC_SUBST([HAVE_DOXYGEN])
+ AM_CONDITIONAL([HAVE_DOXYGEN],[test "${HAVE_DOXYGEN}" = "yes"])
+])
+
+dnl AC_WITH_DOT([ACTION-IF-FOUND[,ACTION-IF-NOT-FOUND]])
+dnl Outputs:
+dnl AC_SUBST: DOT HAVE_DOT
+dnl AM_CONDITIONAL: HAVE_DOT
+AC_DEFUN([AC_WITH_DOT],[
+ HAVE_DOT="no"
+ AC_PATH_PROG([DOT],[dot],[false])
+ if test "${DOT}" = "false" ; then
+ ifelse([$2], , :, [$2])
+ else
+ HAVE_DOT="yes"
+ AC_SUBST([DOT])
+ $1
+ fi
+AC_SUBST([HAVE_DOT])
+ AM_CONDITIONAL([HAVE_DOT],[test "${HAVE_DOT}" = "yes"])
+])
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..ba27501
--- a/dev/null
+++ b/autogen.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+WANT_AUTOMAKE=1.8
+export WANT_AUTOMAKE
+libtoolize -f \
+&& aclocal \
+&& autoheader \
+&& automake -a \
+&& autoconf \
+&& ./configure "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..040b9cf
--- a/dev/null
+++ b/configure.ac
@@ -0,0 +1,55 @@
+AC_INIT([midillo], [0.0], [midillo-bugs@klever.net])
+AC_CONFIG_SRCDIR([include/midillo/SMF.h])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([dist-bzip2])
+
+AC_PROG_INSTALL
+AC_PROG_AWK
+AC_PROG_CXX
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS([sys/types.h sys/stat.h])
+AC_CHECK_DECLS([environ],,,[
+ #include <unistd.h>
+])
+
+AC_C_CONST
+
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+
+AC_PATH_PROG([XSLTPROC],[xsltproc],[true])
+
+AC_WITH_PKGCONFIG
+
+PKG_CHECK_MODULES([KONFORKA],[konforka],,[
+ AC_MSG_ERROR([no konforka library found. get one from http://kin.klever.net/konforka/])
+])
+
+WANT_DOXYGEN="yes"
+AC_ARG_ENABLE([doxygen],
+ AC_HELP_STRING([--disable-doxygen],[do not generate documentation]),
+ [
+ test "${enableval}" = "no" && WANT_DOXYGEN="no"
+ ]
+)
+if test "${WANT_DOXYGEN}" = "yes" ; then
+ AC_WITH_DOXYGEN
+ AC_WITH_DOT
+else
+ AM_CONDITIONAL([HAVE_DOXYGEN],[false])
+ AM_CONDITIONAL([HAVE_DOT],[false])
+fi
+
+AC_CONFIG_FILES([
+ Makefile
+ midillo.pc
+ Doxyfile
+ include/Makefile
+ lib/Makefile
+ tools/Makefile
+ man/Makefile
+])
+AC_OUTPUT
diff --git a/include/.gitignore b/include/.gitignore
new file mode 100644
index 0000000..282522d
--- a/dev/null
+++ b/include/.gitignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..edfb186
--- a/dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,5 @@
+nobase_include_HEADERS = \
+ midillo/util.h midillo/exception.h \
+ midillo/SMF.h \
+ midillo/chunk.h midillo/MTrk.h midillo/MThd.h \
+ midillo/event.h midillo/message.h
diff --git a/include/midillo/MThd.h b/include/midillo/MThd.h
new file mode 100644
index 0000000..20263cd
--- a/dev/null
+++ b/include/midillo/MThd.h
@@ -0,0 +1,74 @@
+#ifndef __MIDILLO_MTHD_H
+#define __MIDILLO_MTHD_H
+
+#include <istream>
+#include <ostream>
+#include <midillo/chunk.h>
+
+/**
+ * @file
+ * @brief the MThd_t -- MThd header chunk class
+ */
+
+namespace midillo {
+ using std::istream;
+ using std::ostream;
+
+ /**
+ * MThd header chunk container
+ */
+ class MThd_t : public chunk_t {
+ public:
+ enum {
+ fmt_0 = 0, fmt_1 = 1, fmt_2 = 2,
+ fmt_singletrack = fmt_0,
+ fmt_multitrack = fmt_1,
+ fmt_tracksequence = fmt_2
+ };
+ /**
+ * SMF format. 0 for single track, 1 for multitrack, 2 for track
+ * sequence.
+ */
+ int fmt;
+ /**
+ * Number of tracks in the file
+ */
+ int ntracks;
+ /**
+ * The number of pulses per quarter note
+ */
+ int division;
+
+ /**
+ * Load MThd chunk from the stream
+ * @param s input stream
+ */
+ void load(istream& s);
+
+ /**
+ * Read MThd chunk data from the stream. This function assumes that
+ * header is already read.
+ * @param s input stream
+ */
+ void load_data(istream& s);
+
+ /**
+ * Save MThd chunk to the stream
+ * @param s output stream
+ */
+ void save(ostream& s) const;
+
+ /**
+ * Dump textual representation of MThd chunk to stream
+ * @param s output stream
+ */
+ void dump(ostream& s) const;
+ };
+
+ inline ostream& operator<<(ostream& s,const MThd_t& mthd) {
+ mthd.dump(s); return s;
+ }
+
+}
+
+#endif /* MIDILLO_MTHD_H */
diff --git a/include/midillo/MTrk.h b/include/midillo/MTrk.h
new file mode 100644
index 0000000..0884388
--- a/dev/null
+++ b/include/midillo/MTrk.h
@@ -0,0 +1,54 @@
+#ifndef __MIDILLO_MTRK_H
+#define __MIDILLO_MTRK_H
+
+#include <istream>
+#include <ostream>
+#include <list>
+#include <midillo/chunk.h>
+#include <midillo/event.h>
+
+/**
+ * @file
+ * @brief MTrk -- track chunk container
+ */
+
+namespace midillo {
+ using std::istream;
+ using std::ostream;
+
+ /**
+ * MTrk track chunk container class
+ */
+ class MTrk_t : public chunk_t {
+ public:
+ /**
+ * MIDI events contained in the track
+ */
+ events_t events;
+
+ /**
+ * Load MTrk chunk from the stream
+ * @param s input stream
+ */
+ void load(istream& s);
+
+ /**
+ * Save MTrk chunk to the stream
+ * @param s output stream
+ */
+ void save(ostream& s) const;
+
+ /**
+ * Dump textual representation of MTrk chunk to stream
+ * @param s output stream
+ */
+ void dump(ostream& s) const;
+ };
+
+ inline ostream& operator<<(ostream& s,const MTrk_t& mtrk) {
+ mtrk.dump(s); return s;
+ }
+
+}
+
+#endif /* __MIDILLO_MTRK_H */
diff --git a/include/midillo/SMF.h b/include/midillo/SMF.h
new file mode 100644
index 0000000..bec9f7a
--- a/dev/null
+++ b/include/midillo/SMF.h
@@ -0,0 +1,87 @@
+#ifndef __MIDILLO_SMF_H
+#define __MIDILLO_SMF_H
+
+#include <istream>
+#include <ostream>
+#include <list>
+#include <midillo/MThd.h>
+#include <midillo/MTrk.h>
+
+/**
+ * @file
+ * @brief the SMF_t -- standard midi file
+ */
+
+namespace midillo {
+ using std::istream;
+ using std::vector;
+ using std::ostream;
+
+ /**
+ * Standard midi file object
+ */
+ class SMF_t {
+ public:
+ /**
+ * MThd header chunk
+ */
+ MThd_t mthd;
+ /**
+ * The type for collection of MTrk track chunks
+ */
+ typedef list<MTrk_t> tracks_t;
+ /**
+ * MTrk track chunks collection for the file
+ */
+ tracks_t tracks;
+
+ SMF_t() { }
+ /**
+ * Construct object from the file
+ * @see load(const char *f,bool stdinable)
+ */
+ SMF_t(const char *f,bool stdinable=true) { load(f,stdinable); }
+ /**
+ * Construct object from the stream
+ * @see load(istream& s)
+ */
+ SMF_t(istream& s) { load(s); }
+
+ /**
+ * Load MIDI data from the file
+ * @param f filename
+ * @param stdinable true if '-' is treatead as cin input stream
+ */
+ void load(const char *f,bool stdinable=true);
+ /**
+ * Load midi data from the stream
+ * @param s input stream
+ */
+ void load(istream& s);
+
+ /**
+ * Save MIDI data to the file
+ * @param f filename
+ * @param stdoutable true if '-' is treated as cout output stream
+ */
+ void save(const char *f,bool stdoutable=true) const;
+ /**
+ * Save MIDI data to the stream
+ * @param s output stream
+ */
+ void save(ostream& s) const;
+
+ /**
+ * Dump textual representation of SMF to stream
+ * @param s output stream
+ */
+ void dump(ostream& s) const;
+ };
+
+ inline ostream& operator<<(ostream& s,const SMF_t& smf) {
+ smf.dump(s); return s;
+ }
+
+}
+
+#endif /* __MIDILLO_SMF_H */
diff --git a/include/midillo/chunk.h b/include/midillo/chunk.h
new file mode 100644
index 0000000..8b6c034
--- a/dev/null
+++ b/include/midillo/chunk.h
@@ -0,0 +1,88 @@
+#ifndef __MIDILLO_CHUNK_H
+#define __MIDILLO_CHUNK_H
+
+#include <istream>
+#include <ostream>
+
+/**
+ * @file
+ * @brief Generic SMF chunk manipulation
+ */
+
+namespace midillo {
+ using std::istream;
+ using std::ostream;
+
+ enum {
+ chunk_id_MThd = 0x6468544d,
+ chunk_id_MTrk = 0x6b72544d
+ };
+ /**
+ * Chunk header data structure
+ */
+ struct chunk_header_t {
+ /**
+ * Track signature data
+ */
+ union {
+ /**
+ * ASCII representation
+ */
+ char id_chars[4];
+ /**
+ * long integer representation
+ */
+ unsigned long id_number;
+ };
+ /**
+ * Chunk length
+ */
+ unsigned long length;
+
+ chunk_header_t()
+ : id_number(0), length(0) { }
+ chunk_header_t(const chunk_header_t& s)
+ : id_number(s.id_number), length(s.length) { };
+
+ chunk_header_t& operator=(const chunk_header_t& s) {
+ id_number=s.id_number; length=s.length;
+ return *this;
+ }
+
+ /**
+ * Load chunk header from the stream
+ * @param s input stream
+ */
+ void load(istream& s);
+ /**
+ * Save chunk header to the stream
+ * @param s output stream
+ */
+ void save(ostream& s) const;
+
+ /**
+ * Dump textual representation of chunk header to stream
+ * @param s output stream
+ */
+ void dump(ostream& s) const;
+
+ };
+
+ inline ostream& operator<<(ostream& s,const chunk_header_t& ch) {
+ ch.dump(s); return s;
+ }
+
+ /**
+ * Base class for specific chunk containers
+ */
+ class chunk_t {
+ public:
+ /**
+ * Chunk header data
+ */
+ chunk_header_t header;
+ };
+
+}
+
+#endif /* __MIDILLO_CHUNK_H */
diff --git a/include/midillo/event.h b/include/midillo/event.h
new file mode 100644
index 0000000..85f6175
--- a/dev/null
+++ b/include/midillo/event.h
@@ -0,0 +1,99 @@
+#ifndef __MIDILLO_EVENT_H
+#define __MIDILLO_EVENT_H
+
+#include <istream>
+#include <ostream>
+#include <list>
+#include <midillo/message.h>
+
+/**
+ * @file
+ * @brief midi event container
+ */
+
+namespace midillo {
+ using std::istream;
+ using std::ostream;
+ using std::list;
+
+ /**
+ * MIDI event container class
+ */
+ class event_t {
+ public:
+ /**
+ * delta time since the last event
+ */
+ long deltat;
+ /**
+ * MIDI message itself
+ */
+ message_t message;
+
+ /**
+ * Load MIDI event from the stream
+ * @param rs reference to the running status
+ * @param s input stream
+ */
+ void load(int& rs,istream& s);
+
+ /**
+ * Save MIDI event to the stream
+ * @param rs reference to the running status
+ * @param s output stream
+ */
+ void save(int& rs,ostream& s) const;
+
+ /**
+ * Calculate the amount of data that would be written to stream in
+ * case of save
+ * @param rs reference to the running status
+ * @return the number of bytes
+ */
+ unsigned long calculate_save_size(int& rs) const;
+
+ /**
+ * Dump textual representation of event to stream
+ * @param s output stream
+ */
+ void dump(ostream& s) const;
+ };
+
+ inline ostream& operator<<(ostream& s,const event_t& e) {
+ e.dump(s); return s;
+ }
+
+ /**
+ * MIDI events list container
+ */
+ class events_t : public list<event_t> {
+ public:
+
+ /**
+ * Append empty event to the end of the list
+ * @return iterator, pointing to the appended event
+ */
+ iterator append_event();
+
+ /**
+ * Load MIDI events (track data) from the stream
+ * @param s input stream
+ */
+ void load(istream& s);
+ /**
+ * Save MIDI events (track data) to the stream
+ * @param s output stream
+ */
+ void save(ostream& s) const;
+
+ /**
+ * Calculate the size of the track data that would be written to
+ * the stream by save()
+ * @return the number of bytes
+ */
+ unsigned long calculate_save_size() const;
+ };
+
+}
+
+#endif /* __MIDILLO_EVENT_H */
diff --git a/include/midillo/exception.h b/include/midillo/exception.h
new file mode 100644
index 0000000..fb6da27
--- a/dev/null
+++ b/include/midillo/exception.h
@@ -0,0 +1,55 @@
+#ifndef __MIDILLO_EXCEPTION_H
+#define __MIDILLO_EXCEPTION_H
+
+#include <konforka/exception.h>
+
+/**
+ * @file
+ * @brief midillo specific exceptions
+ */
+
+namespace midillo {
+ using std::string;
+
+ /**
+ * Base midillo exception class
+ */
+ class exception : public konforka::exception {
+ public:
+ explicit exception(const string& fi,const string& fu,int l,const string& w)
+ : konforka::exception(fi,fu,l,w) { }
+ };
+
+ class exception_io_error : public exception {
+ public:
+ explicit exception_io_error(const string& fi,const string& fu,int l,const string& w)
+ : exception(fi,fu,l,w) { }
+ };
+
+ class exception_input_error : public exception_io_error {
+ public:
+ explicit exception_input_error(const string& fi,const string& fu,int l,const string& w)
+ : exception_io_error(fi,fu,l,w) { }
+ };
+
+ class exception_invalid_input : public exception_input_error {
+ public:
+ explicit exception_invalid_input(const string& fi,const string& fu,int l,const string& w)
+ : exception_input_error(fi,fu,l,w) { }
+ };
+
+ class exception_unexpected_input : public exception_invalid_input {
+ public:
+ explicit exception_unexpected_input(const string& fi,const string& fu,int l,const string& w)
+ : exception_invalid_input(fi,fu,l,w) { }
+ };
+
+ class exception_output_error : public exception_io_error {
+ public:
+ explicit exception_output_error(const string& fi,const string& fu,int l,const string& w)
+ : exception_io_error(fi,fu,l,w) { }
+ };
+
+};
+
+#endif /* __MIDILLO_EXCEPTION_H */
diff --git a/include/midillo/message.h b/include/midillo/message.h
new file mode 100644
index 0000000..d6f0f36
--- a/dev/null
+++ b/include/midillo/message.h
@@ -0,0 +1,200 @@
+#ifndef __MIDILLO_MESSAGE_H
+#define __MIDILLO_MESSAGE_H
+
+#include <istream>
+#include <ostream>
+#include <vector>
+
+/**
+ * @file
+ * @brief MIDI message
+ */
+
+namespace midillo {
+ using std::istream;
+ using std::ostream;
+ using std::vector;
+
+ enum {
+ // bits
+ status_bit = 0x80,
+ status_event_bits = 0xF0,
+ status_channel_bits = 0x0F,
+ status_system_bits = 0xFF,
+ // channel voice messages
+ status_note_off = 0x80,
+ status_note_on = 0x90,
+ status_polyphonic_key_pressure = 0xA0,
+ status_aftertouch = status_polyphonic_key_pressure,
+ status_control_change = 0xB0,
+ status_program_change = 0xC0,
+ status_channel_pressure = 0xD0,
+ status_pitch_wheel_change = 0xE0,
+ status_system = 0xF0,
+ // system common messages
+ status_system_sysex = 0xF0,
+ status_system_MTC_quarter_frame = 0xF1,
+ status_system_song_position_pointer = 0xF2,
+ status_system_song_select = 0xF3,
+ status_system_tune_request = 0xF6,
+ status_system_end_of_sysex = 0xF7,
+ // system real-time messages
+ status_system_timing_clock = 0xF8,
+ status_system_midi_clock = status_system_timing_clock,
+ status_system_midi_tick = 0xF9,
+ status_system_start = 0xFA,
+ status_system_midi_start = status_system_start,
+ status_system_continue = 0xFB,
+ status_system_midi_continue = status_system_continue,
+ status_system_stop = 0xFC,
+ status_system_midi_stop = status_system_stop,
+ status_system_active_sense = 0xFE,
+ status_system_rest = 0xFF,
+ status_system_reset = status_system_rest,
+ // midi file specific
+ status_system_meta = 0xFF
+ };
+ enum {
+ // meta events
+ meta_sequence_number = 0x00,
+ meta_text = 0x01,
+ meta_copyright = 0x02,
+ meta_seq_track_name = 0x03,
+ meta_instrument = 0x04,
+ meta_lyric = 0x05,
+ meta_marker = 0x06,
+ meta_cue_point = 0x07,
+ meta_patch_name = 0x08,
+ meta_port_name = 0x09,
+ meta_EOT = 0x2F,
+ meta_tempo = 0x51,
+ meta_SMPTE_offset = 0x54,
+ meta_time_sig = 0x58,
+ meta_key_sig = 0x59,
+ meta_proprietary = 0x7F,
+ // obsolete meta events
+ meta_midi_channel = 0x20,
+ meta_midi_port = 0x21
+ };
+
+ /**
+ * MIDI message container
+ */
+ class message_t {
+ public:
+ /**
+ * MIDI status byte
+ */
+ int status;
+ /**
+ * MIDI meta event type
+ */
+ int meta_status;
+ typedef unsigned char byte_t;
+ typedef vector<byte_t> bytes_t;
+ /**
+ * MIDI message data -- content is message-specific
+ */
+ bytes_t data;
+
+ message_t()
+ : status(-1) { }
+ message_t(const message_t& m)
+ : status(m.status), meta_status(m.meta_status), data(m.data) { }
+
+ message_t& operator=(const message_t& m) {
+ status = m.status;
+ meta_status = m.meta_status;
+ data = m.data;
+ return *this;
+ }
+
+ /**
+ * Load MIDI message from the stream
+ * @param rs reference to the running status
+ * @param s input stream
+ */
+ void load(int& rs,istream& s);
+ /**
+ * Save MIDI message to the stream
+ * @param rs reference to the running status
+ * @param s output stream
+ */
+ void save(int& rs,ostream& s) const;
+ /**
+ * Calculate the amount of data that would be written to stream in
+ * case of save()
+ * @param rs reference to the running status
+ * @return the number of bytes
+ */
+ unsigned long calculate_save_size(int& rs) const;
+
+ /**
+ * Load data so that we have c bytes of data for the event
+ * @param s input stream
+ * @param c size of data needed for the event
+ */
+ void load_data(istream& s,int c);
+ /**
+ * Load sysex data from the stream
+ * @param s input stream
+ */
+ void load_sysex(istream& s);
+
+ /**
+ * Save data to the stream
+ * @param s output stream
+ */
+ void save_data(ostream& s) const;
+ /**
+ * Save data to the stream and verify if the amount of data is
+ * correct
+ * @param s output stream
+ * @param c data bytes count
+ */
+ void save_data(ostream& s,int c) const;
+ /**
+ * Save sysex data to the stream
+ * @param s output stream
+ */
+ void save_sysex(ostream& s) const;
+
+ /**
+ * See if the event is meta event
+ * @return true if yes
+ */
+ bool is_meta() const {
+ return status==status_system_meta;
+ }
+ /**
+ * Check whether the event is a specific meta event
+ * @param meta meta event type
+ * @return true if yes
+ */
+ bool is_meta(int meta) const {
+ return is_meta() && (meta_status==meta);
+ }
+
+ /**
+ * See if the event is system event
+ * @return true if yes
+ */
+ bool is_system() const {
+ return (status&status_event_bits)==status_system && !is_meta();
+ }
+
+ /**
+ * Dump textual representation of midi message to stream
+ * @param s output stream
+ */
+ void dump(ostream& s) const;
+
+ };
+
+ inline ostream& operator<<(ostream& s,const message_t& m) {
+ m.dump(s); return s;
+ }
+
+}
+
+#endif /* __MIDILLO_MESSAGE_H */
diff --git a/include/midillo/util.h b/include/midillo/util.h
new file mode 100644
index 0000000..f9c8430
--- a/dev/null
+++ b/include/midillo/util.h
@@ -0,0 +1,63 @@
+#ifndef __MIDILLO_UTIL_H
+#define __MIDILLO_UTIL_H
+
+#include <istream>
+#include <ostream>
+
+/**
+ * @file
+ * @brief utilities
+ */
+
+namespace midillo {
+ using std::istream;
+ using std::ostream;
+
+ /**
+ * read 32 bits word from the stream
+ * @param s input stream
+ * @return the data acquired
+ */
+ unsigned long read32(istream& s);
+ /**
+ * read 16 bits word from the stream
+ * @param s input stream
+ * @return the data acquired
+ */
+ unsigned int read16(istream& s);
+ /**
+ * read the variable length quantity from the stream
+ * @param s input stream
+ * @return the data acquired
+ */
+ unsigned long readVL(istream& s);
+
+ /**
+ * write 32 bits word to the stream
+ * @param s output stream
+ * @param d data to write
+ */
+ void write32(ostream& s,unsigned long d);
+ /**
+ * write 16 bits word to the stream
+ * @param s output stream
+ * @param d data to write
+ */
+ void write16(ostream& s,unsigned int d);
+ /**
+ * write the variable length quantity to the stream
+ * @param s output stream
+ * @param d data to write
+ */
+ void writeVL(ostream& s,unsigned long d);
+
+ /**
+ * calculate the amount of data that would be written by writeVL
+ * @param d data that would be written
+ * @return the number of bytes
+ */
+ unsigned long calcVLsize(unsigned long d);
+
+}
+
+#endif /* __MIDILLO_UTIL_H */
diff --git a/lib/.gitignore b/lib/.gitignore
new file mode 100644
index 0000000..dc5e416
--- a/dev/null
+++ b/lib/.gitignore
@@ -0,0 +1,7 @@
+*.lo
+*.o
+Makefile.in
+.libs
+.deps
+Makefile
+*.la
diff --git a/lib/MThd.cc b/lib/MThd.cc
new file mode 100644
index 0000000..110c98a
--- a/dev/null
+++ b/lib/MThd.cc
@@ -0,0 +1,38 @@
+#include <midillo/MThd.h>
+#include <midillo/util.h>
+#include <midillo/exception.h>
+
+namespace midillo {
+ using std::endl;
+
+ void MThd_t::load(istream& s) {
+ header.load(s);
+ if(header.id_number!=chunk_id_MThd)
+ throw exception_unexpected_input(CODEPOINT,"MThd chunk expected");
+ if(header.length!=6)
+ throw exception_invalid_input(CODEPOINT,"MThd chunk is not 6 bytes long");
+ load_data(s);
+ }
+
+ void MThd_t::load_data(istream& s) {
+ fmt = read16(s);
+ ntracks = read16(s);
+ division = read16(s);
+ }
+
+ void MThd_t::save(ostream& s) const {
+ header.save(s);
+ write16(s,fmt);
+ write16(s,ntracks);
+ write16(s,division);
+ }
+
+ void MThd_t::dump(ostream& s) const {
+ std::ios::fmtflags ff = s.flags();
+ s.unsetf(std::ios::hex); s.setf(std::ios::dec);
+ s << " " << header << endl
+ << " fmt=" << fmt << ", " << ntracks << " track(s), division=" << division << endl;
+ s.flags(ff);
+ }
+
+}
diff --git a/lib/MTrk.cc b/lib/MTrk.cc
new file mode 100644
index 0000000..fa1e0f8
--- a/dev/null
+++ b/lib/MTrk.cc
@@ -0,0 +1,34 @@
+#include <algorithm>
+#include <iterator>
+#include <midillo/MTrk.h>
+#include <midillo/exception.h>
+
+namespace midillo {
+ using std::copy;
+ using std::ostream_iterator;
+ using std::endl;
+
+ void MTrk_t::load(istream& s) {
+ header.load(s);
+ if(header.id_number!=chunk_id_MTrk)
+ throw exception_unexpected_input(CODEPOINT,"MTrk chunk expected");
+ events.load(s);
+ }
+
+ void MTrk_t::save(ostream& s) const {
+ chunk_header_t h = header;
+ h.id_number = chunk_id_MTrk;
+ h.length = events.calculate_save_size();
+ h.save(s);
+ events.save(s);
+ }
+
+ void MTrk_t::dump(ostream& s) const {
+ s << " " << header << endl
+ << " ";
+ copy(
+ events.begin(), events.end(),
+ ostream_iterator<event_t>(s,"\n ") );
+ }
+
+}
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..de49c97
--- a/dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,15 @@
+lib_LTLIBRARIES = libmidillo.la
+
+INCLUDES = -I${top_srcdir}/include -I${top_srcdir}
+AM_CXXFLAGS = ${KONFORKA_CFLAGS}
+LDADD = ${KONFORKA_LIBS}
+
+libmidillo_la_SOURCES = \
+ util.cc \
+ SMF.cc \
+ chunk.cc \
+ MThd.cc MTrk.cc \
+ event.cc \
+ message.cc
+
+libmidillo_la_LDFLAGS = -version-info 0:0:0
diff --git a/lib/SMF.cc b/lib/SMF.cc
new file mode 100644
index 0000000..ba3179d
--- a/dev/null
+++ b/lib/SMF.cc
@@ -0,0 +1,62 @@
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <iterator>
+#include <midillo/SMF.h>
+
+namespace midillo {
+ using std::ifstream;
+ using std::ofstream;
+ using std::cin;
+ using std::cout;
+ using std::copy;
+ using std::ostream_iterator;
+ using std::endl;
+
+ void SMF_t::load(const char *f,bool stdinable) {
+ if(stdinable && !strcmp(f,"-")) {
+ load(cin);
+ }else{
+ ifstream s(f,std::ios::in|std::ios::binary);
+ load(s);
+ }
+ }
+
+ void SMF_t::load(istream& s) {
+ mthd.load(s);
+ tracks.resize(mthd.ntracks);
+ tracks_t::iterator i = tracks.begin();
+ for(int t=0;t<mthd.ntracks;++t,++i) {
+ i->load(s);
+ }
+ }
+
+ void SMF_t::save(const char *f,bool stdoutable) const {
+ if(stdoutable && !strcmp(f,"-")) {
+ save(cout);
+ }else{
+ ofstream s(f,std::ios::out|std::ios::trunc|std::ios::binary);
+ save(s);
+ }
+ }
+
+ void SMF_t::save(ostream& s) const {
+ mthd.save(s);
+ for(tracks_t::const_iterator i=tracks.begin();i!=tracks.end();++i) {
+ i->save(s);
+ }
+ }
+
+ void SMF_t::dump(ostream& s) const {
+ std::ios::fmtflags ff = s.flags();
+ s.unsetf(std::ios::hex); s.setf(std::ios::dec);
+ s
+ << "SMF with " << tracks.size() << " track(s)" << endl
+ << mthd << endl;
+ copy(
+ tracks.begin(), tracks.end(),
+ ostream_iterator<MTrk_t>(s,"\n") );
+ s.flags(ff);
+ }
+
+}
diff --git a/lib/chunk.cc b/lib/chunk.cc
new file mode 100644
index 0000000..7cc15ff
--- a/dev/null
+++ b/lib/chunk.cc
@@ -0,0 +1,31 @@
+#include <midillo/chunk.h>
+#include <midillo/util.h>
+#include <midillo/exception.h>
+
+namespace midillo {
+
+ void chunk_header_t::load(istream& s) {
+ s.read((char*)id_chars,sizeof(id_chars));
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading chunk header");
+ length = read32(s);
+ }
+
+ void chunk_header_t::save(ostream& s) const {
+ s.write((char*)id_chars,sizeof(id_chars));
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Error writing chunk header");
+ write32(s,length);
+ }
+
+ void chunk_header_t::dump(ostream& s) const {
+ std::ios::fmtflags ff = s.flags();
+ s.unsetf(std::ios::hex); s.setf(std::ios::dec);
+ s
+ << id_chars[0] << id_chars[1]
+ << id_chars[2] << id_chars[3]
+ << " chunk of " << length << " byte(s)";
+ s.flags(ff);
+ }
+
+}
diff --git a/lib/event.cc b/lib/event.cc
new file mode 100644
index 0000000..39438fa
--- a/dev/null
+++ b/lib/event.cc
@@ -0,0 +1,58 @@
+#include <midillo/event.h>
+#include <midillo/util.h>
+
+namespace midillo {
+
+ void event_t::load(int& rs,istream& s) {
+ deltat = readVL(s);
+ message.load(rs,s);
+ }
+
+ void event_t::save(int& rs,ostream& s) const {
+ writeVL(s,deltat);
+ message.save(rs,s);
+ }
+
+ unsigned long event_t::calculate_save_size(int& rs) const {
+ return calcVLsize(deltat) + message.calculate_save_size(rs);
+ }
+
+ void event_t::dump(ostream& s) const {
+ std::ios::fmtflags ff = s.flags();
+ s.unsetf(std::ios::hex); s.setf(std::ios::dec);
+ s << "deltat=" << deltat << " [" << message << "]";
+ s.flags(ff);
+ }
+
+
+ events_t::iterator events_t::append_event() {
+ static event_t empty;
+ return insert(end(),empty);
+ }
+
+ void events_t::load(istream& s) {
+ int rs = -1;
+ for(;;) {
+ iterator i=append_event();
+ i->load(rs,s);
+ if(i->message.is_meta(meta_EOT))
+ break;
+ }
+ }
+
+ void events_t::save(ostream& s) const {
+ int rs = -1;
+ for(const_iterator i=begin();i!=end();++i) {
+ i->save(rs,s);
+ }
+ }
+
+ unsigned long events_t::calculate_save_size() const {
+ unsigned long rv = 0;
+ int rs = -1;
+ for(const_iterator i=begin();i!=end();++i) {
+ rv += i->calculate_save_size(rs);
+ }
+ return rv;
+ }
+}
diff --git a/lib/message.cc b/lib/message.cc
new file mode 100644
index 0000000..8f9e68a
--- a/dev/null
+++ b/lib/message.cc
@@ -0,0 +1,247 @@
+#include <algorithm>
+#include <iterator>
+#include <midillo/message.h>
+#include <midillo/util.h>
+#include <midillo/exception.h>
+
+namespace midillo {
+ using std::copy;
+ using std::ostream_iterator;
+
+ unsigned long message_t::calculate_save_size(int& rs) const {
+ unsigned long rv = 0;
+ if(status!=rs) {
+ ++rv;
+ rs = status;
+ }else if((status&status_event_bits)==status_system) {
+ rs = -1;
+ ++rv; // XXX: is it really needed?
+ }
+ switch(status&status_event_bits) {
+ case status_note_off:
+ case status_note_on:
+ case status_polyphonic_key_pressure: // aka status_aftertouch
+ case status_control_change:
+ case status_pitch_wheel_change:
+ rv += 2; break;
+ case status_program_change:
+ case status_channel_pressure:
+ ++rv; break;
+ case status_system:
+ switch(status&status_system_bits) {
+ case status_system_sysex:
+ case status_system_end_of_sysex:
+ rv += data.size()+1; break;
+ case status_system_MTC_quarter_frame:
+ case status_system_song_select:
+ ++rv; break;
+ case status_system_song_position_pointer:
+ rv += 2; break;
+ case status_system_tune_request:
+ case status_system_timing_clock: // aka status_system_midi_clock
+ case status_system_midi_tick:
+ case status_system_start: // aka status_system_midi_start
+ case status_system_stop: // aka status_system_midi_stop
+ case status_system_continue: // aka status_system_midi_continue
+ case status_system_active_sense:
+ break; /* XXX: ensure there is no data? */
+ case status_system_meta: // also reset, but not for the purpose of midi file
+ ++rv;
+ rv += calcVLsize(data.size());
+ rv += data.size();
+ break;
+ default:
+ throw exception(CODEPOINT,"Internal error");
+ break;
+ }
+ break;
+ default:
+ throw exception(CODEPOINT,"Internal error");
+ break;
+ }
+ return rv;
+ }
+
+ void message_t::save(int& rs,ostream& s) const {
+ if(status!=rs) {
+ s.put(status);
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Error writing midi status byte");
+ rs = status;
+ }else if((status&status_event_bits)==status_system) {
+ rs = -1;
+ s.put(status); // XXX: is it really needed?
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Error writing midi system status byte");
+ }
+ switch(status&status_event_bits) {
+ case status_note_off:
+ case status_note_on:
+ case status_polyphonic_key_pressure: // aka status_aftertouch
+ case status_control_change:
+ case status_pitch_wheel_change:
+ save_data(s,2); break;
+ case status_program_change:
+ case status_channel_pressure:
+ save_data(s,1); break;
+ case status_system:
+ switch(status&status_system_bits) {
+ case status_system_sysex:
+ case status_system_end_of_sysex:
+ save_sysex(s); break;
+ case status_system_MTC_quarter_frame:
+ case status_system_song_select:
+ save_data(s,1); break;
+ case status_system_song_position_pointer:
+ save_data(s,2); break;
+ case status_system_tune_request:
+ case status_system_timing_clock: // aka status_system_midi_clock
+ case status_system_midi_tick:
+ case status_system_start: // aka status_system_midi_start
+ case status_system_stop: // aka status_system_midi_stop
+ case status_system_continue: // aka status_system_midi_continue
+ case status_system_active_sense:
+ break; /* XXX: ensure there is no data? */
+ case status_system_meta: // also reset, but not for the purpose of midi file
+ s.put(meta_status&0xFF);
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Error writing meta event");
+ writeVL(s,data.size());
+ save_data(s);
+ break;
+ default:
+ throw exception(CODEPOINT,"Internal error");
+ break;
+ }
+ break;
+ default:
+ throw exception(CODEPOINT,"Internal error");
+ break;
+ }
+ }
+
+ void message_t::load(int& rs,istream& s) {
+ data.clear();
+ status = s.get();
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading MIDI event status byte");
+ if(status&status_bit) {
+ if((status&status_event_bits)!=status_system)
+ rs = status;
+ }else{
+ if(rs<0)
+ throw exception_invalid_input(CODEPOINT,"Attempt to rely on the absent running status");
+ data.push_back(status);
+ status = rs;
+ }
+ switch(status&status_event_bits) {
+ case status_note_off:
+ case status_note_on:
+ case status_polyphonic_key_pressure: // a.k.a. status_aftertouch
+ case status_control_change:
+ case status_pitch_wheel_change:
+ load_data(s,2); break;
+ case status_program_change:
+ case status_channel_pressure:
+ load_data(s,1); break;
+ case status_system:
+ switch(status&status_system_bits) {
+ case status_system_sysex:
+ case status_system_end_of_sysex:
+ load_sysex(s); break;
+ case status_system_MTC_quarter_frame:
+ case status_system_song_select:
+ load_data(s,1); break;
+ case status_system_song_position_pointer:
+ load_data(s,2); break;
+ case status_system_tune_request:
+ case status_system_timing_clock: // a.k.a. status_system_midi_clock
+ case status_system_midi_tick:
+ case status_system_start: // a.k.a. status_system_midi_start
+ case status_system_stop: // a.k.a. status_system_midi_stop
+ case status_system_continue: // a.k.a. status_system_midi_continue
+ case status_system_active_sense:
+ break;
+ case status_system_meta: // also, reset, but not in midi files
+ {
+ meta_status = s.get();
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading meta event type");
+ int l = readVL(s);
+ load_data(s,l);
+ }
+ break;
+ default:
+ throw exception(CODEPOINT,"Internal error");
+ break;
+ }
+ break;
+ default:
+ throw exception(CODEPOINT,"Internal error");
+ break;
+ }
+ }
+
+ void message_t::save_data(ostream& s,int c) const {
+ if(c!=data.size())
+ throw exception(CODEPOINT,"Writing corrupt data");
+ save_data(s);
+ }
+
+ void message_t::save_data(ostream& s) const {
+ for(bytes_t::const_iterator i=data.begin();i!=data.end();++i)
+ s.put(*i);
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Error writing MIDI message data");
+ }
+
+ void message_t::load_data(istream& s,int c) {
+ c -= data.size();
+ if(c<0)
+ throw exception(CODEPOINT,"Internal error");
+ while(c-- > 0) {
+ data.push_back(s.get());
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading MIDI data");
+ }
+ }
+
+ void message_t::save_sysex(ostream& s) const {
+ save_data(s);
+ s.put(0xF7); /* XXX: Or is it better to put it into data? */
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Error writing sysex data");
+ }
+
+ void message_t::load_sysex(istream& s) {
+ int b = s.get();
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading sysex data");
+ assert(!(b&0x80)); // manufacturer ought to be 7 bit. not sure if it belongs here, it may well be continuation.
+ do {
+ data.push_back(b);
+ b = s.get();
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading sysex data");
+ }while(b!=0xF7);
+ }
+
+ void message_t::dump(ostream& s) const {
+ std::ios::fmtflags ff = s.flags();
+ int w = s.width(2);
+ s.unsetf(std::ios::dec); s.setf(std::ios::hex);
+ s << "status=" << status;
+ if(is_meta()) {
+ s << ", meta_status=" << meta_status;
+ }
+ if(!data.empty()) {
+ s << ", data: ";
+ copy(
+ data.begin(), data.end(),
+ ostream_iterator<int>(s," ") );
+ }
+ s.width(w);
+ s.flags(ff);
+ }
+
+}
diff --git a/lib/util.cc b/lib/util.cc
new file mode 100644
index 0000000..4bbe6f3
--- a/dev/null
+++ b/lib/util.cc
@@ -0,0 +1,96 @@
+#include <midillo/util.h>
+#include <midillo/exception.h>
+
+namespace midillo {
+
+ unsigned long read32(istream& s) {
+ unsigned long rv = 0;
+ for(int t=0;t<4;++t) {
+ rv<<=8;
+ rv|=0xFF&s.get();
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Input error");
+ }
+ return rv;
+ }
+
+ unsigned int read16(istream& s) {
+ unsigned int rv = 0;
+ for(int t=0;t<2;++t) {
+ rv<<=8;
+ rv|=0xFF&s.get();
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Input error");
+ }
+ return rv;
+ }
+
+ unsigned long readVL(istream& s) {
+ unsigned long rv=s.get();
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading VLQ");
+ int b;
+ if(rv&0x80) {
+ rv&=0x7F;
+ do {
+ rv = (rv<<7)|( (b=s.get())&0x7F );
+ if(!s.good())
+ throw exception_input_error(CODEPOINT,"Error reading VLQ");
+ }while(b&0x80);
+ }
+ return rv;
+ }
+
+ void write32(ostream& s,unsigned long d) {
+ for(int t=3;t>=0;--t) {
+ s.put(((const char*)&d)[t]);
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Output error");
+ }
+ }
+
+ void write16(ostream& s,unsigned int d) {
+ for(int t=1;t>=0;--t) {
+ s.put(((const char*)&d)[t]);
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Output error");
+ }
+ }
+
+ void writeVL(ostream& s,unsigned long d) {
+ // TODO: I don't think this is perfectly written code
+ unsigned long tmp = d&0x7F;
+ while(d>>=7) {
+ tmp<<=8;
+ tmp |=((d&0x7F)|0x80);
+ }
+ for(;;) {
+ s.put(tmp&0xFF);
+ if(!s.good())
+ throw exception_output_error(CODEPOINT,"Error writing VLQ");
+ if(tmp&0x80)
+ tmp>>=8;
+ else
+ break;
+ }
+ }
+
+ unsigned long calcVLsize(unsigned long d) {
+ unsigned long rv = 0;
+ // TODO: imperfect code revisited
+ unsigned long tmp = d&0x7F;
+ while(d>>=7) {
+ tmp<<=8;
+ tmp |=((d&0x7F)|0x80);
+ }
+ for(;;) {
+ ++rv;
+ if(tmp&0x80)
+ tmp>>=8;
+ else
+ break;
+ }
+ return rv;
+ }
+
+}
diff --git a/man/.gitignore b/man/.gitignore
new file mode 100644
index 0000000..3dda729
--- a/dev/null
+++ b/man/.gitignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..13bcb82
--- a/dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,3 @@
+man_MANS = midi2f0.1 midifilter.1 mididump.1
+
+EXTRA_DIST=${man_MANS}
diff --git a/man/midi2f0.1 b/man/midi2f0.1
new file mode 100644
index 0000000..ae89ea8
--- a/dev/null
+++ b/man/midi2f0.1
@@ -0,0 +1,85 @@
+.TH midi2f0 1 "August 11th, 2006" "midi2f0(1)" "Klever Group (http://www.klever.net/)"
+.hla en
+
+.SH NAME
+
+midi2f0 \- Standard MIDI File converter
+
+.SH SYNOPSYS
+
+\fBmidi2f0\fR
+[\fB-h\fR | \fB--help\fR | \fB--usage\fR]
+[\fB-V\fR | \fB--version\fR]
+[\fB-L\fR | \fB--license\fR]
+[<input-file>[ <output-file>]]
+
+.SH DESCRIPTION
+
+midi2f0 converts Standard MIDI Files to Standard MIDI Files format 0, which
+is single track midi file. You may want to perform such conversion before
+putting the file on the memory card for some MIDI keyboard consumption.
+
+if you want to load file from standard input or dump results to standard output
+just omit corresponding file or specify '-'.
+
+.SH OPTIONS
+
+.TP
+\fB-h\fR, \fB--help\fR, \fB--usage\fR
+Display short usage message and exit.
+.TP
+\fB-V\fR, \fB--version\fR
+Report version and exit.
+.TP
+\fB-L\fR, \fB--license\fR
+Show licensing terms.
+
+.SH EXAMPLE
+
+.TP
+.nf
+\fBmidi2f0\fR midifile.mid \\
+| \fBmidifilter\fR \fB-f\fR \fBsysex,meta_unknown,meta_obsolete,meta_texts\fR \\
+>/mnt/card/casio_md/midifile.mid
+.fi
+
+This command converts file to SMF0 file, strips events not understood and not
+used by the keyboard and puts it to the memory card.
+
+.SH EXIT STATUS
+
+Zero in case of success, non-zero otherwise.
+
+.SH AUTHOR
+
+Written by Michael 'hacker' Krelin <hacker@klever.net>
+
+.SH COPYRIGHT
+
+Copyright (c) 2006 Klever Group (http://www.klever.net/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+.SH BUGS
+
+You tell me. Send reports to <midillo-bugs@klever.net>
+
+.SH SEE ALSO
+\fBmidifilter\fR(1)
+\fBmididump\fR(1)
diff --git a/man/mididump.1 b/man/mididump.1
new file mode 100644
index 0000000..e236ddc
--- a/dev/null
+++ b/man/mididump.1
@@ -0,0 +1,72 @@
+.TH mididump 1 "August 11th, 2006" "mididump(1)" "Klever Group (http://www.klever.net/)"
+.hla en
+
+.SH NAME
+
+mididump \- Standard MIDI File dump
+
+.SH SYNOPSYS
+
+\fBmididump\fR
+[\fB-h\fR | \fB--help\fR | \fB--usage\fR]
+[\fB-V\fR | \fB--version\fR]
+[\fB-L\fR | \fB--license\fR]
+[<input-file>[ <output-file>]]
+
+.SH DESCRIPTION
+
+mididump outputs ascii representation of the input SMF file. At this point it
+may only be useful for debugging purpose.
+
+if you want to load file from standard input or dump results to standard output
+just omit corresponding file or specify '-'.
+
+.SH OPTIONS
+
+.TP
+\fB-h\fR, \fB--help\fR, \fB--usage\fR
+Display short usage message and exit.
+.TP
+\fB-V\fR, \fB--version\fR
+Report version and exit.
+.TP
+\fB-L\fR, \fB--license\fR
+Show licensing terms.
+
+.SH EXIT STATUS
+
+Zero in case of success, non-zero otherwise.
+
+.SH AUTHOR
+
+Written by Michael 'hacker' Krelin <hacker@klever.net>
+
+.SH COPYRIGHT
+
+Copyright (c) 2006 Klever Group (http://www.klever.net/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+.SH BUGS
+
+You tell me. Send reports to <midillo-bugs@klever.net>
+
+.SH SEE ALSO
+\fBmidi2f0\fR(1)
+\fBmidifilter\fR(1)
diff --git a/man/midifilter.1 b/man/midifilter.1
new file mode 100644
index 0000000..eddd66d
--- a/dev/null
+++ b/man/midifilter.1
@@ -0,0 +1,93 @@
+.TH midifilter 1 "August 11th, 2006" "midifilter(1)" "Klever Group (http://www.klever.net/)"
+.hla en
+
+.SH NAME
+
+midifilter \- Standard MIDI File filter
+
+.SH SYNOPSYS
+
+\fBmidifilter\fR
+[\fB-h\fR | \fB--help\fR | \fB--usage\fR]
+[\fB-V\fR | \fB--version\fR]
+[\fB-L\fR | \fB--license\fR]
+[\fB-f\fR \fI<filters>\fR | \fB--filter=\fI<filters>\fR]
+[\fB-l\fR | \fB--list-filters\fR]
+[<input-file>[ <output-file>]]
+
+.SH DESCRIPTION
+
+midifilter simply strips unwanted events from the Standard MIDI File. You may
+wish to strip some certain events if you know the events may break whatever
+will do any further processing of the file or just to reduce file size.
+
+if you want to load file from standard input or dump results to standard output
+just omit corresponding file or specify '-'.
+
+.SH OPTIONS
+
+.TP
+\fB-h\fR, \fB--help\fR, \fB--usage\fR
+Display short usage message and exit.
+.TP
+\fB-V\fR, \fB--version\fR
+Report version and exit.
+.TP
+\fB-L\fR, \fB--license\fR
+Show licensing terms.
+.TP
+\fB-f\fR \fI<filters>\fR, \fB--filter=\fI<filters\fR
+Specify the list of comma-separated filters to apply.
+.TP
+\fB-l\fR, \fB--list-filters\fR
+List available filters.
+
+.SH EXAMPLE
+
+.TP
+.nf
+\fBmidi2f0\fR midifile.mid \\
+| \fBmidifilter\fR \fB-f\fR \fBsysex,meta_unknown,meta_obsolete,meta_texts\fR \\
+>/mnt/card/casio_md/midifile.mid
+.fi
+
+This command converts file to SMF0 file, strips events not understood and not
+used by the keyboard and puts it to the memory card.
+
+.SH EXIT STATUS
+
+Zero in case of success, non-zero otherwise.
+
+.SH AUTHOR
+
+Written by Michael 'hacker' Krelin <hacker@klever.net>
+
+.SH COPYRIGHT
+
+Copyright (c) 2006 Klever Group (http://www.klever.net/)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+.SH BUGS
+
+You tell me. Send reports to <midillo-bugs@klever.net>
+
+.SH SEE ALSO
+\fBmidi2f0\fR(1)
+\fBmididump\fR(1)
diff --git a/midillo.pc.in b/midillo.pc.in
new file mode 100644
index 0000000..dd57130
--- a/dev/null
+++ b/midillo.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: midillo
+Description: C++ midi manipulation library
+Version: @VERSION@
+Requires: konforka
+Libs: -L${libdir} -lmidillo
+Cflags: -I${includedir}
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;
+ }
+}