libextractor

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

midi_extractor.c (5654B)


      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
     62 EXTRACTOR_midi_extract_method (struct EXTRACTOR_ExtractContext *ec)
     63 {
     64   void *buf;
     65   unsigned char *data;
     66   uint64_t size;
     67   uint64_t off;
     68   ssize_t iret;
     69   smf_t *m = NULL;
     70   smf_event_t *event;
     71   uint8_t len;
     72 
     73   if (4 >= (iret = ec->read (ec->cls, &buf, 1024)))
     74     return;
     75   data = buf;
     76   if ( (data[0] != 0x4D) || (data[1] != 0x54) ||
     77        (data[2] != 0x68) || (data[3] != 0x64) )
     78     return;                /* cannot be MIDI */
     79   size = ec->get_size (ec->cls);
     80   if (size > 16 * 1024 * 1024)
     81     return; /* too large */
     82   if (NULL == (data = malloc ((size_t) size)))
     83     return; /* out of memory */
     84   memcpy (data, buf, iret);
     85   off = iret;
     86   while (off < size)
     87   {
     88     if (0 >= (iret = ec->read (ec->cls, &buf, 16 * 1024)))
     89     {
     90       free (data);
     91       return;
     92     }
     93     memcpy (&data[off], buf, iret);
     94     off += iret;
     95   }
     96   if (0 != ec->proc (ec->cls,
     97                      "midi",
     98                      EXTRACTOR_METATYPE_MIMETYPE,
     99                      EXTRACTOR_METAFORMAT_UTF8,
    100                      "text/plain",
    101                      "audio/midi",
    102                      strlen ("audio/midi") + 1))
    103     goto CLEANUP;
    104   if (NULL == (m = smf_load_from_memory (data, size)))
    105     goto CLEANUP;
    106   while (NULL != (event = smf_get_next_event (m)))
    107   {
    108     if (! smf_event_is_metadata (event))
    109       break;
    110     if (event->midi_buffer_length < 3)
    111       continue; /* need at least FF type len */
    112     len = event->midi_buffer[2];
    113     if (event->midi_buffer_length < 3 + (int) len)
    114       continue; /* declared length exceeds available buffer */
    115     if ( (len > 0) &&
    116          isspace (event->midi_buffer[2 + len]))
    117       len--;
    118 #if 0
    119     fprintf (stderr,
    120              "type: %d, len: %d value: %.*s\n",
    121              event->midi_buffer[1],
    122              event->midi_buffer[2],
    123              (int) event->midi_buffer_length - 3,
    124              (char *) &event->midi_buffer[3]);
    125 #endif
    126     if (1 != event->track_number)
    127       continue; /* heuristic to not get instruments */
    128     if (0 == len)
    129       continue;
    130     switch (event->midi_buffer[1])
    131     {
    132     case ET_TEXT_EVENT:
    133       if (0 != ec->proc (ec->cls,
    134                          "midi",
    135                          EXTRACTOR_METATYPE_COMMENT,
    136                          EXTRACTOR_METAFORMAT_UTF8,
    137                          "text/plain",
    138                          (void*) &event->midi_buffer[3],
    139                          len))
    140         goto CLEANUP;
    141       break;
    142     case ET_COPYRIGHT_NOTICE:
    143       if (0 != ec->proc (ec->cls,
    144                          "midi",
    145                          EXTRACTOR_METATYPE_COPYRIGHT,
    146                          EXTRACTOR_METAFORMAT_UTF8,
    147                          "text/plain",
    148                          (void*) &event->midi_buffer[3],
    149                          len))
    150         goto CLEANUP;
    151       break;
    152     case ET_TRACK_NAME:
    153       if (0 != ec->proc (ec->cls,
    154                          "midi",
    155                          EXTRACTOR_METATYPE_TITLE,
    156                          EXTRACTOR_METAFORMAT_UTF8,
    157                          "text/plain",
    158                          (void*) &event->midi_buffer[3],
    159                          len))
    160         goto CLEANUP;
    161       break;
    162     case ET_INSTRUMENT_NAME:
    163       if (0 != ec->proc (ec->cls,
    164                          "midi",
    165                          EXTRACTOR_METATYPE_SOURCE_DEVICE,
    166                          EXTRACTOR_METAFORMAT_UTF8,
    167                          "text/plain",
    168                          (void*) &event->midi_buffer[3],
    169                          len))
    170         goto CLEANUP;
    171       break;
    172     case ET_LYRIC_TEXT:
    173       if (0 != ec->proc (ec->cls,
    174                          "midi",
    175                          EXTRACTOR_METATYPE_LYRICS,
    176                          EXTRACTOR_METAFORMAT_UTF8,
    177                          "text/plain",
    178                          (void*) &event->midi_buffer[3],
    179                          len))
    180         goto CLEANUP;
    181       break;
    182     default:
    183       break;
    184     }
    185   }
    186 
    187 CLEANUP:
    188   if (NULL != m)
    189     smf_delete (m);
    190   free (data);
    191 }
    192 
    193 
    194 /* end of midi_extractor.c */