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