46 $info = &$this->getid3->info;
50 $thisfile_midi = &
$info[
'midi'];
51 $thisfile_midi_raw = &$thisfile_midi[
'raw'];
53 $info[
'fileformat'] =
'midi';
54 $info[
'audio'][
'dataformat'] =
'midi';
56 fseek($this->getid3->fp,
$info[
'avdataoffset'], SEEK_SET);
57 $MIDIdata =
fread($this->getid3->fp, $this->getid3->fread_buffer_size());
59 $MIDIheaderID = substr($MIDIdata, $offset, 4);
60 if ($MIDIheaderID != self::GETID3_MIDI_MAGIC_MTHD) {
61 $info[
'error'][] =
'Expecting "'.Helper::PrintHexBytes(self::GETID3_MIDI_MAGIC_MTHD).
'" at offset '.
$info[
'avdataoffset'].
', found "'.
Helper::PrintHexBytes($MIDIheaderID).
'"';
62 unset(
$info[
'fileformat']);
76 for ($i = 0; $i < $thisfile_midi_raw[
'tracks']; $i++) {
77 while ((strlen($MIDIdata) - $offset) < 8) {
78 $MIDIdata .=
fread($this->getid3->fp, $this->getid3->fread_buffer_size());
80 $trackID = substr($MIDIdata, $offset, 4);
82 if ($trackID == self::GETID3_MIDI_MAGIC_MTRK) {
86 $trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);
87 $offset += $tracksize;
89 $info[
'error'][] =
'Expecting "'.Helper::PrintHexBytes(self::GETID3_MIDI_MAGIC_MTRK).
'" at '.($offset - 4).
', found "'.
Helper::PrintHexBytes($trackID).
'" instead';
95 if (!isset($trackdataarray) || !is_array($trackdataarray)) {
96 $info[
'error'][] =
'Cannot find MIDI track information';
97 unset($thisfile_midi);
98 unset(
$info[
'fileformat']);
103 if ($this->scanwholefile) {
104 $thisfile_midi[
'totalticks'] = 0;
105 $info[
'playtime_seconds'] = 0;
106 $CurrentMicroSecondsPerBeat = 500000;
107 $CurrentBeatsPerMinute = 120;
108 $MicroSecondsPerQuarterNoteAfter =
array ();
110 foreach ($trackdataarray as $tracknumber => $trackdata) {
113 $LastIssuedMIDIcommand = 0;
114 $LastIssuedMIDIchannel = 0;
115 $CumulativeDeltaTime = 0;
116 $TicksAtCurrentBPM = 0;
117 while ($eventsoffset < strlen($trackdata)) {
119 if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) {
120 $eventid = count($MIDIevents[$tracknumber]);
123 for ($i = 0; $i < 4; $i++) {
124 $deltatimebyte = ord(substr($trackdata, $eventsoffset++, 1));
125 $deltatime = ($deltatime << 7) + ($deltatimebyte & 0x7F);
126 if ($deltatimebyte & 0x80) {
132 $CumulativeDeltaTime += $deltatime;
133 $TicksAtCurrentBPM += $deltatime;
134 $MIDIevents[$tracknumber][$eventid][
'deltatime'] = $deltatime;
135 $MIDI_event_channel = ord(substr($trackdata, $eventsoffset++, 1));
136 if ($MIDI_event_channel & 0x80) {
138 $LastIssuedMIDIcommand = $MIDI_event_channel >> 4;
139 $LastIssuedMIDIchannel = $MIDI_event_channel & 0x0F;
144 $MIDIevents[$tracknumber][$eventid][
'eventid'] = $LastIssuedMIDIcommand;
145 $MIDIevents[$tracknumber][$eventid][
'channel'] = $LastIssuedMIDIchannel;
146 if ($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x08) {
148 $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
149 $velocity = ord(substr($trackdata, $eventsoffset++, 1));
151 } elseif ($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x09) {
153 $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
154 $velocity = ord(substr($trackdata, $eventsoffset++, 1));
156 } elseif ($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x0A) {
158 $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
159 $velocity = ord(substr($trackdata, $eventsoffset++, 1));
161 } elseif ($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x0B) {
163 $controllernum = ord(substr($trackdata, $eventsoffset++, 1));
164 $newvalue = ord(substr($trackdata, $eventsoffset++, 1));
166 } elseif ($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x0C) {
168 $newprogramnum = ord(substr($trackdata, $eventsoffset++, 1));
170 $thisfile_midi_raw[
'track'][$tracknumber][
'instrumentid'] = $newprogramnum;
171 if ($tracknumber == 10) {
177 } elseif ($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x0D) {
179 $channelnumber = ord(substr($trackdata, $eventsoffset++, 1));
181 } elseif ($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x0E) {
183 $changeLSB = ord(substr($trackdata, $eventsoffset++, 1));
184 $changeMSB = ord(substr($trackdata, $eventsoffset++, 1));
185 $pitchwheelchange = (($changeMSB & 0x7F) << 7) & ($changeLSB & 0x7F);
187 } elseif (($MIDIevents[$tracknumber][$eventid][
'eventid'] == 0x0F) && ($MIDIevents[$tracknumber][$eventid][
'channel'] == 0x0F)) {
189 $METAeventCommand = ord(substr($trackdata, $eventsoffset++, 1));
190 $METAeventLength = ord(substr($trackdata, $eventsoffset++, 1));
191 $METAeventData = substr($trackdata, $eventsoffset, $METAeventLength);
192 $eventsoffset += $METAeventLength;
193 switch ($METAeventCommand) {
200 $text_generic = substr($METAeventData, 0, $METAeventLength);
202 $thisfile_midi[
'comments'][
'comment'][] = $text_generic;
206 $text_copyright = substr($METAeventData, 0, $METAeventLength);
208 $thisfile_midi[
'comments'][
'copyright'][] = $text_copyright;
212 $text_trackname = substr($METAeventData, 0, $METAeventLength);
213 $thisfile_midi_raw[
'track'][$tracknumber][
'name'] = $text_trackname;
217 $text_instrument = substr($METAeventData, 0, $METAeventLength);
222 $text_lyrics = substr($METAeventData, 0, $METAeventLength);
224 if (!isset($thisfile_midi[
'lyrics'])) {
225 $thisfile_midi[
'lyrics'] =
'';
227 $thisfile_midi[
'lyrics'] .= $text_lyrics.
"\n";
231 $text_marker = substr($METAeventData, 0, $METAeventLength);
236 $text_cuepoint = substr($METAeventData, 0, $METAeventLength);
246 if ($CurrentMicroSecondsPerBeat == 0) {
247 $info[
'error'][] =
'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
251 $thisfile_midi_raw[
'events'][$tracknumber][$CumulativeDeltaTime][
'us_qnote'] = $CurrentMicroSecondsPerBeat;
252 $CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60;
253 $MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat;
254 $TicksAtCurrentBPM = 0;
265 $thisfile_midi[
'timesignature'][] = $timesig_numerator.
'/'.$timesig_denominator;
270 if ($keysig_sharpsflats & 0x80) {
272 $keysig_sharpsflats -= 256;
276 $keysigs =
array(-7=>
'Cb', -6=>
'Gb', -5=>
'Db', -4=>
'Ab', -3=>
'Eb', -2=>
'Bb', -1=>
'F', 0=>
'C', 1=>
'G', 2=>
'D', 3=>
'A', 4=>
'E', 5=>
'B', 6=>
'F#', 7=>
'C#');
283 $thisfile_midi[
'keysignature'][] = $keysigs[$keysig_sharpsflats].
' '.((bool) $keysig_majorminor ?
'minor' :
'major');
287 $custom_data = substr($METAeventData, 0, $METAeventLength);
291 $info[
'warning'][] =
'Unhandled META Event Command: '.$METAeventCommand;
297 $info[
'warning'][] =
'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid][
'eventid'].
' + Channel ID: '.$MIDIevents[$tracknumber][$eventid][
'channel'];
301 if (($tracknumber > 0) || (count($trackdataarray) == 1)) {
302 $thisfile_midi[
'totalticks'] = max($thisfile_midi[
'totalticks'], $CumulativeDeltaTime);
305 $previoustickoffset = null;
307 ksort($MicroSecondsPerQuarterNoteAfter);
308 foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
309 if (is_null($previoustickoffset)) {
310 $prevmicrosecondsperbeat = $microsecondsperbeat;
311 $previoustickoffset = $tickoffset;
314 if ($thisfile_midi[
'totalticks'] > $tickoffset) {
316 if ($thisfile_midi_raw[
'ticksperqnote'] == 0) {
317 $info[
'error'][] =
'Corrupt MIDI file: ticksperqnote == zero';
322 $info[
'playtime_seconds'] += (($tickoffset - $previoustickoffset) / $thisfile_midi_raw[
'ticksperqnote']) * ($prevmicrosecondsperbeat / 1000000);
324 $prevmicrosecondsperbeat = $microsecondsperbeat;
325 $previoustickoffset = $tickoffset;
328 if ($thisfile_midi[
'totalticks'] > $previoustickoffset) {
330 if ($thisfile_midi_raw[
'ticksperqnote'] == 0) {
331 $info[
'error'][] =
'Corrupt MIDI file: ticksperqnote == zero';
336 $info[
'playtime_seconds'] += (($thisfile_midi[
'totalticks'] - $previoustickoffset) / $thisfile_midi_raw[
'ticksperqnote']) * ($microsecondsperbeat / 1000000);
341 if (!empty(
$info[
'playtime_seconds'])) {
342 $info[
'bitrate'] = ((
$info[
'avdataend'] -
$info[
'avdataoffset']) * 8) /
$info[
'playtime_seconds'];
345 if (!empty($thisfile_midi[
'lyrics'])) {
346 $thisfile_midi[
'comments'][
'lyrics'][] = $thisfile_midi[
'lyrics'];
GeneralMIDIinstrumentLookup($instrumentid)
static EmbeddedLookup($key, $begin, $end, $file, $name)
type $cache
static PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8')
GetId3() by James Heinrich info@getid3.org //.
const GETID3_MIDI_MAGIC_MTRK
const GETID3_MIDI_MAGIC_MTHD
fseek($bytes, $whence=SEEK_SET)
GetId3() by James Heinrich info@getid3.org //.
Create styles array
The data for the language used.
static BigEndian2Int($byteword, $synchsafe=false, $signed=false)
GeneralMIDIpercussionLookup($instrumentid)