<Website>

getID3

PHK Home

File: /lib/module.audio.midi.php

Size:10512
Storage flags:strip

<?php















define
('GETID3_MIDI_MAGIC_MTHD''MThd'); 
define('GETID3_MIDI_MAGIC_MTRK''MTrk'); 

class 
getid3_midi extends getid3_handler
{
public 
$scanwholefile true;

public function 
Analyze() {
$info = &$this->getid3->info;


 
$info['midi']['raw'] = array();
$thisfile_midi = &$info['midi'];
$thisfile_midi_raw = &$thisfile_midi['raw'];

$info['fileformat'] = 'midi';
$info['audio']['dataformat'] = 'midi';

$this->fseek($info['avdataoffset']);
$MIDIdata $this->fread($this->getid3->fread_buffer_size());
$offset 0;
$MIDIheaderID substr($MIDIdata$offset4); 
 if (
$MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) {
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"';
unset(
$info['fileformat']);
return 
false;
}
$offset += 4;
$thisfile_midi_raw['headersize'] = getid3_lib::BigEndian2Int(substr($MIDIdata$offset4));
$offset += 4;
$thisfile_midi_raw['fileformat'] = getid3_lib::BigEndian2Int(substr($MIDIdata$offset2));
$offset += 2;
$thisfile_midi_raw['tracks'] = getid3_lib::BigEndian2Int(substr($MIDIdata$offset2));
$offset += 2;
$thisfile_midi_raw['ticksperqnote'] = getid3_lib::BigEndian2Int(substr($MIDIdata$offset2));
$offset += 2;

for (
$i 0$i $thisfile_midi_raw['tracks']; $i++) {
while ((
strlen($MIDIdata) - $offset) < 8) {
if (
$buffer $this->fread($this->getid3->fread_buffer_size())) {
$MIDIdata .= $buffer;
} else {
$info['warning'][] = 'only processed '.($i 1).' of '.$thisfile_midi_raw['tracks'].' tracks';
$info['error'][] = 'Unabled to read more file data at '.$this->ftell().' (trying to seek to : '.$offset.'), was expecting at least 8 more bytes';
return 
false;
}
}
$trackID substr($MIDIdata$offset4);
$offset += 4;
if (
$trackID == GETID3_MIDI_MAGIC_MTRK) {
$tracksize getid3_lib::BigEndian2Int(substr($MIDIdata$offset4));
$offset += 4;

 
$trackdataarray[$i] = substr($MIDIdata$offset$tracksize);
$offset += $tracksize;
} else {
$info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTRK).'" at '.($offset 4).', found "'.getid3_lib::PrintHexBytes($trackID).'" instead';
return 
false;
}
}

if (!isset(
$trackdataarray) || !is_array($trackdataarray)) {
$info['error'][] = 'Cannot find MIDI track information';
unset(
$thisfile_midi);
unset(
$info['fileformat']);
return 
false;
}

if (
$this->scanwholefile) { 
 
$thisfile_midi['totalticks'] = 0;
$info['playtime_seconds'] = 0;
$CurrentMicroSecondsPerBeat 500000
 
$CurrentBeatsPerMinute 120
 
$MicroSecondsPerQuarterNoteAfter = array ();

foreach (
$trackdataarray as $tracknumber => $trackdata) {

$eventsoffset 0;
$LastIssuedMIDIcommand 0;
$LastIssuedMIDIchannel 0;
$CumulativeDeltaTime 0;
$TicksAtCurrentBPM 0;
while (
$eventsoffset strlen($trackdata)) {
$eventid 0;
if (isset(
$MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) {
$eventid count($MIDIevents[$tracknumber]);
}
$deltatime 0;
for (
$i 0$i 4$i++) {
$deltatimebyte ord(substr($trackdata$eventsoffset++, 1));
$deltatime = ($deltatime << 7) + ($deltatimebyte 0x7F);
if (
$deltatimebyte 0x80) {

 } else {
break;
}
}
$CumulativeDeltaTime += $deltatime;
$TicksAtCurrentBPM += $deltatime;
$MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime;
$MIDI_event_channel ord(substr($trackdata$eventsoffset++, 1));
if (
$MIDI_event_channel 0x80) {

 
$LastIssuedMIDIcommand $MIDI_event_channel >> 4;
$LastIssuedMIDIchannel $MIDI_event_channel 0x0F;
} else {

 
$eventsoffset--;
}
$MIDIevents[$tracknumber][$eventid]['eventid'] = $LastIssuedMIDIcommand;
$MIDIevents[$tracknumber][$eventid]['channel'] = $LastIssuedMIDIchannel;
if (
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x08) { 

$notenumber ord(substr($trackdata$eventsoffset++, 1));
$velocity ord(substr($trackdata$eventsoffset++, 1));

} elseif (
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x09) { 

$notenumber ord(substr($trackdata$eventsoffset++, 1));
$velocity ord(substr($trackdata$eventsoffset++, 1));

} elseif (
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0A) { 

$notenumber ord(substr($trackdata$eventsoffset++, 1));
$velocity ord(substr($trackdata$eventsoffset++, 1));

} elseif (
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0B) { 

$controllernum ord(substr($trackdata$eventsoffset++, 1));
$newvalue ord(substr($trackdata$eventsoffset++, 1));

} elseif (
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0C) { 

$newprogramnum ord(substr($trackdata$eventsoffset++, 1));

$thisfile_midi_raw['track'][$tracknumber]['instrumentid'] = $newprogramnum;
if (
$tracknumber == 10) {
$thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIpercussionLookup($newprogramnum);
} else {
$thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIinstrumentLookup($newprogramnum);
}

} elseif (
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0D) { 

$channelnumber ord(substr($trackdata$eventsoffset++, 1));

} elseif (
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0E) { 

$changeLSB ord(substr($trackdata$eventsoffset++, 1));
$changeMSB ord(substr($trackdata$eventsoffset++, 1));
$pitchwheelchange = (($changeMSB 0x7F) << 7) & ($changeLSB 0x7F);

} elseif ((
$MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0F) && ($MIDIevents[$tracknumber][$eventid]['channel'] == 0x0F)) {

$METAeventCommand ord(substr($trackdata$eventsoffset++, 1));
$METAeventLength ord(substr($trackdata$eventsoffset++, 1));
$METAeventData substr($trackdata$eventsoffset$METAeventLength);
$eventsoffset += $METAeventLength;
switch (
$METAeventCommand) {
case 
0x00
 
$track_sequence_number getid3_lib::BigEndian2Int(substr($METAeventData0$METAeventLength));

 break;

case 
0x01
 
$text_generic substr($METAeventData0$METAeventLength);

 
$thisfile_midi['comments']['comment'][] = $text_generic;
break;

case 
0x02
 
$text_copyright substr($METAeventData0$METAeventLength);

 
$thisfile_midi['comments']['copyright'][] = $text_copyright;
break;

case 
0x03
 
$text_trackname substr($METAeventData0$METAeventLength);
$thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname;
break;

case 
0x04
 
$text_instrument substr($METAeventData0$METAeventLength);

 break;

case 
0x05
 
$text_lyrics substr($METAeventData0$METAeventLength);

 if (!isset(
$thisfile_midi['lyrics'])) {
$thisfile_midi['lyrics'] = '';
}
$thisfile_midi['lyrics'] .= $text_lyrics."\n";
break;

case 
0x06
 
$text_marker substr($METAeventData0$METAeventLength);

 break;

case 
0x07
 
$text_cuepoint substr($METAeventData0$METAeventLength);

 break;

case 
0x2F
 
 break;

case 
0x51
 
$CurrentMicroSecondsPerBeat getid3_lib::BigEndian2Int(substr($METAeventData0$METAeventLength));
if (
$CurrentMicroSecondsPerBeat == 0) {
$info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
return 
false;
}
$thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
$CurrentBeatsPerMinute = (1000000 $CurrentMicroSecondsPerBeat) * 60;
$MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat;
$TicksAtCurrentBPM 0;
break;

case 
0x58
 
$timesig_numerator getid3_lib::BigEndian2Int($METAeventData{0});
$timesig_denominator pow(2getid3_lib::BigEndian2Int($METAeventData{1})); 
 
$timesig_32inqnote getid3_lib::BigEndian2Int($METAeventData{2}); 
 
 
 
 
 
$thisfile_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator;
break;

case 
0x59
 
$keysig_sharpsflats getid3_lib::BigEndian2Int($METAeventData{0});
if (
$keysig_sharpsflats 0x80) {

 
$keysig_sharpsflats -= 256;
}

$keysig_majorminor getid3_lib::BigEndian2Int($METAeventData{1}); 
 
$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#');

 
 
 


 
$thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool) $keysig_majorminor 'minor' 'major');
break;

case 
0x7F
 
$custom_data substr($METAeventData0$METAeventLength);
break;

default:
$info['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand;
break;
}

} else {

$info['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel'];

}
}
if ((
$tracknumber 0) || (count($trackdataarray) == 1)) {
$thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime);
}
}
$previoustickoffset null;

ksort($MicroSecondsPerQuarterNoteAfter);
foreach (
$MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
if (
is_null($previoustickoffset)) {
$prevmicrosecondsperbeat $microsecondsperbeat;
$previoustickoffset $tickoffset;
continue;
}
if (
$thisfile_midi['totalticks'] > $tickoffset) {

if (
$thisfile_midi_raw['ticksperqnote'] == 0) {
$info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
return 
false;
}

$info['playtime_seconds'] += (($tickoffset $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($prevmicrosecondsperbeat 1000000);

$prevmicrosecondsperbeat $microsecondsperbeat;
$previoustickoffset $tickoffset;
}
}
if (
$thisfile_midi['totalticks'] > $previoustickoffset) {

if (
$thisfile_midi_raw['ticksperqnote'] == 0) {
$info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
return 
false;
}

$info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat 1000000);

}
}


if (!empty(
$info['playtime_seconds'])) {
$info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
}

if (!empty(
$thisfile_midi['lyrics'])) {
$thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics'];
}

return 
true;
}

public function 
GeneralMIDIinstrumentLookup($instrumentid) {

$begin __LINE__;






































































































































return 
getid3_lib::EmbeddedLookup($instrumentid$begin__LINE____FILE__'GeneralMIDIinstrument');
}

public function 
GeneralMIDIpercussionLookup($instrumentid) {

$begin __LINE__;




















































return 
getid3_lib::EmbeddedLookup($instrumentid$begin__LINE____FILE__'GeneralMIDIpercussion');
}

}

For more information about the PHK package format: http://phk.tekwire.net