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 */