libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

commit 33c16e297af5aad1bd7ee22741c4c2fc347eee5c
parent 072eeeccc8bc85170b90b36ec9a4fce9cb328f00
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed, 22 Aug 2012 19:18:55 +0000

adding support for MIDI

Diffstat:
Mconfigure.ac | 19++++++++++++++++++-
Msrc/plugins/Makefile.am | 23+++++++++++++++++++++++
Asrc/plugins/midi_extractor.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/test_midi.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/plugins/testdata/midi_dth.mid | 0
5 files changed, 320 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac @@ -22,6 +22,7 @@ AM_INIT_AUTOMAKE([silent-rules]) AC_USE_SYSTEM_EXTENSIONS AC_PROG_AWK AC_PROG_CC +AM_PROG_CC_C_O AC_PROG_CPP AC_PROG_CXX AC_CHECK_PROG(HAVE_CXX, $CXX, yes, no) @@ -423,7 +424,18 @@ else AM_CONDITIONAL(HAVE_GLIB,false) AC_DEFINE(HAVE_GLIB, 0, [Have glib]) fi - + +# smf requires glib.h +CFLAGS_OLD=$CFLAGS +export CFLAGS="$CFLAGS $GLIB_CFLAGS" + +AC_CHECK_LIB(smf, smf_load_from_memory, + [AC_CHECK_HEADERS([smf.h], + AM_CONDITIONAL(HAVE_SMF, true) + AC_DEFINE(HAVE_MPEG2,1,[Have libsmf]), + AM_CONDITIONAL(HAVE_SMF, false))], + AM_CONDITIONAL(HAVE_SMF, false)) +export CFLAGS=$CFLAGS_OLD # check for gtk >= 2.6.0 AC_MSG_CHECKING(for gtk) @@ -645,6 +657,11 @@ then AC_MSG_NOTICE([NOTICE: libflac not found, flac support disabled]) fi +if test "x$HAVE_SMF_TRUE" = "x#" +then + AC_MSG_NOTICE([NOTICE: libsmf not found, midi support disabled]) +fi + if test "x$HAVE_MPEG2_TRUE" = "x#" then AC_MSG_NOTICE([NOTICE: libmpeg2 not found, mpeg2 support disabled]) diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am @@ -25,6 +25,7 @@ EXTRA_DIST = \ testdata/it_dawn.it \ testdata/jpeg_image.jpg \ testdata/man_extract.1 \ + testdata/midi_dth.mid \ testdata/mpeg_alien.mpg \ testdata/mpeg_melt.mpg \ testdata/nsf_arkanoid.nsf \ @@ -118,6 +119,11 @@ PLUGIN_RPM=libextractor_rpm.la TEST_RPM=test_rpm endif +if HAVE_SMF +PLUGIN_MIDI=libextractor_midi.la +TEST_MIDI=test_midi +endif + if HAVE_TIFF PLUGIN_TIFF=libextractor_tiff.la TEST_TIFF=test_tiff @@ -159,6 +165,7 @@ plugin_LTLIBRARIES = \ $(PLUGIN_GTK) \ $(PLUGIN_HTML) \ $(PLUGIN_JPEG) \ + $(PLUGIN_MIDI) \ $(PLUGIN_MIME) \ $(PLUGIN_MPEG) \ $(PLUGIN_OGG) \ @@ -195,6 +202,7 @@ check_PROGRAMS = \ $(TEST_GTK) \ $(TEST_HTML) \ $(TEST_JPEG) \ + $(TEST_MIDI) \ $(TEST_MIME) \ $(TEST_MPEG) \ $(TEST_OGG) \ @@ -343,6 +351,21 @@ test_man_LDADD = \ $(top_builddir)/src/plugins/libtest.la +libextractor_midi_la_SOURCES = \ + midi_extractor.c +libextractor_midi_la_CFLAGS = \ + $(GLIB_CFLAGS) +libextractor_midi_la_LDFLAGS = \ + $(PLUGINFLAGS) +libextractor_midi_la_LIBADD = \ + -lsmf + +test_midi_SOURCES = \ + test_midi.c +test_midi_LDADD = \ + $(top_builddir)/src/plugins/libtest.la + + libextractor_mime_la_SOURCES = \ mime_extractor.c libextractor_mime_la_LDFLAGS = \ diff --git a/src/plugins/midi_extractor.c b/src/plugins/midi_extractor.c @@ -0,0 +1,187 @@ +/* + This file is part of libextractor. + (C) 2012 Christian Grothoff + + libextractor is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + libextractor is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libextractor; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + */ +/** + * @file plugins/midi_extractor.c + * @brief plugin to support MIDI files + * @author Christian Grothoff + */ +#include "platform.h" +#include "extractor.h" +#include <smf.h> + + +/** + * Types of events in MIDI. + */ +enum EventType + { + ET_SEQUENCE_NUMBER = 0, + ET_TEXT_EVENT = 1, + ET_COPYRIGHT_NOTICE = 2, + ET_TRACK_NAME = 3, + ET_INSTRUMENT_NAME = 4, + ET_LYRIC_TEXT = 5, + ET_MARKER_TEXT = 6, + ET_CUE_POINT = 7, + ET_CHANNEL_PREFIX_ASSIGNMENT = 0x20, + ET_END_OF_TRACK = 0x2F, + ET_TEMPO_SETTING = 0x51, + ET_SMPTE_OFFSET = 0x54, + ET_TIME_SIGNATURE = 0x58, + ET_KEY_SIGNATURE = 0x59, + ET_SEQUENCE_SPECIRFIC_EVENT = 0x7F + }; + + +/** + * Main entry method for the 'audio/midi' extraction plugin. + * + * @param ec extraction context provided to the plugin + */ +void +EXTRACTOR_midi_extract_method (struct EXTRACTOR_ExtractContext *ec) +{ + void *buf; + unsigned char *data; + uint64_t size; + uint64_t off; + ssize_t iret; + smf_t *m = NULL; + smf_event_t *event; + uint8_t len; + + if (4 >= (iret = ec->read (ec->cls, &buf, 1024))) + return; + data = buf; + if ( (data[0] != 0x4D) || (data[1] != 0x54) || + (data[2] != 0x68) || (data[3] != 0x64) ) + return; /* cannot be MIDI */ + size = ec->get_size (ec->cls); + if (size > 16 * 1024 * 1024) + return; /* too large */ + if (NULL == (data = malloc ((size_t) size))) + return; /* out of memory */ + memcpy (data, buf, iret); + off = iret; + while (off < size) + { + if (0 >= (iret = ec->read (ec->cls, &buf, 16 * 1024))) + { + free (data); + return; + } + memcpy (&data[off], buf, iret); + off += iret; + } + if (0 != ec->proc (ec->cls, + "midi", + EXTRACTOR_METATYPE_MIMETYPE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "audio/midi", + strlen ("audio/midi") + 1)) + goto CLEANUP; + if (NULL == (m = smf_load_from_memory (data, size))) + goto CLEANUP; + while (NULL != (event = smf_get_next_event (m))) + { + if (! smf_event_is_metadata (event)) + break; + len = event->midi_buffer[2]; + if ( (len > 0) && + isspace (event->midi_buffer[2 + len])) + len--; +#if 0 + fprintf (stderr, + "type: %d, len: %d value: %.*s\n", + event->midi_buffer[1], + event->midi_buffer[2], + (int) event->midi_buffer_length - 3, + (char *) &event->midi_buffer[3]); +#endif + if (1 != event->track_number) + continue; /* heuristic to not get instruments */ + if (0 == len) + continue; + switch (event->midi_buffer[1]) + { + case ET_TEXT_EVENT: + if (0 != ec->proc (ec->cls, + "midi", + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + (void*) &event->midi_buffer[3], + len)) + goto CLEANUP; + break; + case ET_COPYRIGHT_NOTICE: + if (0 != ec->proc (ec->cls, + "midi", + EXTRACTOR_METATYPE_COPYRIGHT, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + (void*) &event->midi_buffer[3], + len)) + goto CLEANUP; + break; + case ET_TRACK_NAME: + if (0 != ec->proc (ec->cls, + "midi", + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + (void*) &event->midi_buffer[3], + len)) + goto CLEANUP; + break; + case ET_INSTRUMENT_NAME: + if (0 != ec->proc (ec->cls, + "midi", + EXTRACTOR_METATYPE_SOURCE_DEVICE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + (void*) &event->midi_buffer[3], + len)) + goto CLEANUP; + break; + case ET_LYRIC_TEXT: + if (0 != ec->proc (ec->cls, + "midi", + EXTRACTOR_METATYPE_LYRICS, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + (void*) &event->midi_buffer[3], + len)) + goto CLEANUP; + break; + default: + break; + } + } + + CLEANUP: + if (NULL != m) + smf_delete (m); + free (data); +} + + +/* end of midi_extractor.c */ diff --git a/src/plugins/test_midi.c b/src/plugins/test_midi.c @@ -0,0 +1,92 @@ +/* + This file is part of libextractor. + (C) 2012 Vidyut Samanta and Christian Grothoff + + libextractor is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + libextractor is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libextractor; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file plugins/test_midi.c + * @brief testcase for midi plugin + * @author Christian Grothoff + */ +#include "platform.h" +#include "test_lib.h" + + +/** + * Main function for the MIDI testcase. + * + * @param argc number of arguments (ignored) + * @param argv arguments (ignored) + * @return 0 on success + */ +int +main (int argc, char *argv[]) +{ + struct SolutionData midi_dth_sol[] = + { + { + EXTRACTOR_METATYPE_MIMETYPE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "audio/midi", + strlen ("audio/midi") + 1, + 0 + }, + { + EXTRACTOR_METATYPE_COPYRIGHT, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "(c) 2012 d-o-o", + strlen ("(c) 2012 d-o-o"), + 0 + }, + { + EXTRACTOR_METATYPE_TITLE, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "Tage wie diese T2", + strlen ("Tage wie diese T2"), + 0 + }, + { + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "XFhd:::Rock:8 Beat:1:m1:-:-:-:-:DD", + strlen ("XFhd:::Rock:8 Beat:1:m1:-:-:-:-:DD"), + 0 + }, + { + EXTRACTOR_METATYPE_COMMENT, + EXTRACTOR_METAFORMAT_UTF8, + "text/plain", + "XFln:L1:Tage wie diese:von Holst:von Holst:-:Toten Hosen:DD", + strlen ("XFln:L1:Tage wie diese:von Holst:von Holst:-:Toten Hosen:DD"), + 0 + }, + { 0, 0, NULL, NULL, 0, -1 } + }; + struct ProblemSet ps[] = + { + { "testdata/midi_dth.mid", + midi_dth_sol }, + { NULL, NULL } + }; + return ET_main ("midi", ps); +} + +/* end of test_midi.c */ diff --git a/src/plugins/testdata/midi_dth.mid b/src/plugins/testdata/midi_dth.mid Binary files differ.