libextractor

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

midi_extractor.c (5378B)


      1 /*
      2      This file is part of libextractor.
      3      Copyright (C) 2012 Christian Grothoff
      4 
      5      libextractor is free software; you can redistribute it and/or modify
      6      it under the terms of the GNU General Public License as published
      7      by the Free Software Foundation; either version 3, or (at your
      8      option) any later version.
      9 
     10      libextractor is distributed in the hope that it will be useful, but
     11      WITHOUT ANY WARRANTY; without even the implied warranty of
     12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13      General Public License for more details.
     14 
     15      You should have received a copy of the GNU General Public License
     16      along with libextractor; see the file COPYING.  If not, write to the
     17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18      Boston, MA 02110-1301, USA.
     19  */
     20 /**
     21  * @file plugins/midi_extractor.c
     22  * @brief plugin to support MIDI files
     23  * @author Christian Grothoff
     24  */
     25 #include "platform.h"
     26 #include "extractor.h"
     27 #include <smf.h>
     28 
     29 
     30 /**
     31  * Types of events in MIDI.
     32  */
     33 enum EventType
     34 {
     35   ET_SEQUENCE_NUMBER = 0,
     36   ET_TEXT_EVENT = 1,
     37   ET_COPYRIGHT_NOTICE = 2,
     38   ET_TRACK_NAME = 3,
     39   ET_INSTRUMENT_NAME = 4,
     40   ET_LYRIC_TEXT = 5,
     41   ET_MARKER_TEXT = 6,
     42   ET_CUE_POINT = 7,
     43   ET_CHANNEL_PREFIX_ASSIGNMENT = 0x20,
     44   ET_END_OF_TRACK = 0x2F,
     45   ET_TEMPO_SETTING = 0x51,
     46   ET_SMPTE_OFFSET = 0x54,
     47   ET_TIME_SIGNATURE = 0x58,
     48   ET_KEY_SIGNATURE = 0x59,
     49   ET_SEQUENCE_SPECIRFIC_EVENT = 0x7F
     50 };
     51 
     52 
     53 /**
     54  * Main entry method for the 'audio/midi' extraction plugin.
     55  *
     56  * @param ec extraction context provided to the plugin
     57  */
     58 void
     59 EXTRACTOR_midi_extract_method (struct EXTRACTOR_ExtractContext *ec)
     60 {
     61   void *buf;
     62   unsigned char *data;
     63   uint64_t size;
     64   uint64_t off;
     65   ssize_t iret;
     66   smf_t *m = NULL;
     67   smf_event_t *event;
     68   uint8_t len;
     69 
     70   if (4 >= (iret = ec->read (ec->cls, &buf, 1024)))
     71     return;
     72   data = buf;
     73   if ( (data[0] != 0x4D) || (data[1] != 0x54) ||
     74        (data[2] != 0x68) || (data[3] != 0x64) )
     75     return;                /* cannot be MIDI */
     76   size = ec->get_size (ec->cls);
     77   if (size > 16 * 1024 * 1024)
     78     return; /* too large */
     79   if (NULL == (data = malloc ((size_t) size)))
     80     return; /* out of memory */
     81   memcpy (data, buf, iret);
     82   off = iret;
     83   while (off < size)
     84   {
     85     if (0 >= (iret = ec->read (ec->cls, &buf, 16 * 1024)))
     86     {
     87       free (data);
     88       return;
     89     }
     90     memcpy (&data[off], buf, iret);
     91     off += iret;
     92   }
     93   if (0 != ec->proc (ec->cls,
     94                      "midi",
     95                      EXTRACTOR_METATYPE_MIMETYPE,
     96                      EXTRACTOR_METAFORMAT_UTF8,
     97                      "text/plain",
     98                      "audio/midi",
     99                      strlen ("audio/midi") + 1))
    100     goto CLEANUP;
    101   if (NULL == (m = smf_load_from_memory (data, size)))
    102     goto CLEANUP;
    103   while (NULL != (event = smf_get_next_event (m)))
    104   {
    105     if (! smf_event_is_metadata (event))
    106       break;
    107     len = event->midi_buffer[2];
    108     if ( (len > 0) &&
    109          isspace (event->midi_buffer[2 + len]))
    110       len--;
    111 #if 0
    112     fprintf (stderr,
    113              "type: %d, len: %d value: %.*s\n",
    114              event->midi_buffer[1],
    115              event->midi_buffer[2],
    116              (int) event->midi_buffer_length - 3,
    117              (char *) &event->midi_buffer[3]);
    118 #endif
    119     if (1 != event->track_number)
    120       continue; /* heuristic to not get instruments */
    121     if (0 == len)
    122       continue;
    123     switch (event->midi_buffer[1])
    124     {
    125     case ET_TEXT_EVENT:
    126       if (0 != ec->proc (ec->cls,
    127                          "midi",
    128                          EXTRACTOR_METATYPE_COMMENT,
    129                          EXTRACTOR_METAFORMAT_UTF8,
    130                          "text/plain",
    131                          (void*) &event->midi_buffer[3],
    132                          len))
    133         goto CLEANUP;
    134       break;
    135     case ET_COPYRIGHT_NOTICE:
    136       if (0 != ec->proc (ec->cls,
    137                          "midi",
    138                          EXTRACTOR_METATYPE_COPYRIGHT,
    139                          EXTRACTOR_METAFORMAT_UTF8,
    140                          "text/plain",
    141                          (void*) &event->midi_buffer[3],
    142                          len))
    143         goto CLEANUP;
    144       break;
    145     case ET_TRACK_NAME:
    146       if (0 != ec->proc (ec->cls,
    147                          "midi",
    148                          EXTRACTOR_METATYPE_TITLE,
    149                          EXTRACTOR_METAFORMAT_UTF8,
    150                          "text/plain",
    151                          (void*) &event->midi_buffer[3],
    152                          len))
    153         goto CLEANUP;
    154       break;
    155     case ET_INSTRUMENT_NAME:
    156       if (0 != ec->proc (ec->cls,
    157                          "midi",
    158                          EXTRACTOR_METATYPE_SOURCE_DEVICE,
    159                          EXTRACTOR_METAFORMAT_UTF8,
    160                          "text/plain",
    161                          (void*) &event->midi_buffer[3],
    162                          len))
    163         goto CLEANUP;
    164       break;
    165     case ET_LYRIC_TEXT:
    166       if (0 != ec->proc (ec->cls,
    167                          "midi",
    168                          EXTRACTOR_METATYPE_LYRICS,
    169                          EXTRACTOR_METAFORMAT_UTF8,
    170                          "text/plain",
    171                          (void*) &event->midi_buffer[3],
    172                          len))
    173         goto CLEANUP;
    174       break;
    175     default:
    176       break;
    177     }
    178   }
    179 
    180 CLEANUP:
    181   if (NULL != m)
    182     smf_delete (m);
    183   free (data);
    184 }
    185 
    186 
    187 /* end of midi_extractor.c */