| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 | <?php//////////////////////////////////////////////////////////////////// getID3() by James Heinrich <info@getid3.org>               ////  available at http://getid3.sourceforge.net                 ////            or http://www.getid3.org                         ///////////////////////////////////////////////////////////////////// See readme.txt for more details                             /////////////////////////////////////////////////////////////////////                                                             //// module.audio.midi.php                                       //// module for Midi Audio files                                 //// dependencies: NONE                                          ////                                                            ////////////////////////////////////////////////////////////////////class getid3_midi{	function getid3_midi(&$fd, &$ThisFileInfo, $scanwholefile=true) {		// shortcut		$ThisFileInfo['midi']['raw'] = array();		$thisfile_midi               = &$ThisFileInfo['midi'];		$thisfile_midi_raw           = &$thisfile_midi['raw'];		$ThisFileInfo['fileformat']          = 'midi';		$ThisFileInfo['audio']['dataformat'] = 'midi';		fseek($fd, $ThisFileInfo['avdataoffset'], SEEK_SET);		$MIDIdata = fread($fd, GETID3_FREAD_BUFFER_SIZE);		$offset = 0;		$MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd'		if ($MIDIheaderID != 'MThd') {			$ThisFileInfo['error'][] = 'Expecting "MThd" at offset '.$ThisFileInfo['avdataoffset'].', found "'.$MIDIheaderID.'"';			unset($ThisFileInfo['fileformat']);			return false;		}		$offset += 4;		$thisfile_midi_raw['headersize']    = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));		$offset += 4;		$thisfile_midi_raw['fileformat']    = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));		$offset += 2;		$thisfile_midi_raw['tracks']        = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));		$offset += 2;		$thisfile_midi_raw['ticksperqnote'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));		$offset += 2;		for ($i = 0; $i < $thisfile_midi_raw['tracks']; $i++) {			if ((strlen($MIDIdata) - $offset) < 8) {				$MIDIdata .= fread($fd, GETID3_FREAD_BUFFER_SIZE);			}			$trackID = substr($MIDIdata, $offset, 4);			$offset += 4;			if ($trackID == 'MTrk') {				$tracksize = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));				$offset += 4;				// $thisfile_midi['tracks'][$i]['size'] = $tracksize;				$trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);				$offset += $tracksize;			} else {				$ThisFileInfo['error'][] = 'Expecting "MTrk" at '.$offset.', found '.$trackID.' instead';				return false;			}		}		if (!isset($trackdataarray) || !is_array($trackdataarray)) {			$ThisFileInfo['error'][] = 'Cannot find MIDI track information';			unset($thisfile_midi);			unset($ThisFileInfo['fileformat']);			return false;		}		if ($scanwholefile) { // this can take quite a long time, so have the option to bypass it if speed is very important			$thisfile_midi['totalticks']      = 0;			$ThisFileInfo['playtime_seconds'] = 0;			$CurrentMicroSecondsPerBeat       = 500000; // 120 beats per minute;  60,000,000 microseconds per minute -> 500,000 microseconds per beat			$CurrentBeatsPerMinute            = 120;    // 120 beats per minute;  60,000,000 microseconds per minute -> 500,000 microseconds per beat			$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) {							// another byte follows						} else {							break;						}					}					$CumulativeDeltaTime += $deltatime;					$TicksAtCurrentBPM   += $deltatime;					$MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime;					$MIDI_event_channel                                  = ord(substr($trackdata, $eventsoffset++, 1));					if ($MIDI_event_channel & 0x80) {						// OK, normal event - MIDI command has MSB set						$LastIssuedMIDIcommand = $MIDI_event_channel >> 4;						$LastIssuedMIDIchannel = $MIDI_event_channel & 0x0F;					} else {						// running event - assume last command						$eventsoffset--;					}					$MIDIevents[$tracknumber][$eventid]['eventid']   = $LastIssuedMIDIcommand;					$MIDIevents[$tracknumber][$eventid]['channel']   = $LastIssuedMIDIchannel;					if ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x08) { // Note off (key is released)						$notenumber = ord(substr($trackdata, $eventsoffset++, 1));						$velocity   = ord(substr($trackdata, $eventsoffset++, 1));					} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x09) { // Note on (key is pressed)						$notenumber = ord(substr($trackdata, $eventsoffset++, 1));						$velocity   = ord(substr($trackdata, $eventsoffset++, 1));					} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0A) { // Key after-touch						$notenumber = ord(substr($trackdata, $eventsoffset++, 1));						$velocity   = ord(substr($trackdata, $eventsoffset++, 1));					} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0B) { // Control Change						$controllernum = ord(substr($trackdata, $eventsoffset++, 1));						$newvalue      = ord(substr($trackdata, $eventsoffset++, 1));					} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0C) { // Program (patch) change						$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) { // Channel after-touch						$channelnumber = ord(substr($trackdata, $eventsoffset++, 1));					} elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0E) { // Pitch wheel change (2000H is normal or no change)						$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: // Set track sequence number								$track_sequence_number = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['seqno'] = $track_sequence_number;								break;							case 0x01: // Text: generic								$text_generic = substr($METAeventData, 0, $METAeventLength);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['text'] = $text_generic;								$thisfile_midi['comments']['comment'][] = $text_generic;								break;							case 0x02: // Text: copyright								$text_copyright = substr($METAeventData, 0, $METAeventLength);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['copyright'] = $text_copyright;								$thisfile_midi['comments']['copyright'][] = $text_copyright;								break;							case 0x03: // Text: track name								$text_trackname = substr($METAeventData, 0, $METAeventLength);								$thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname;								break;							case 0x04: // Text: track instrument name								$text_instrument = substr($METAeventData, 0, $METAeventLength);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['instrument'] = $text_instrument;								break;							case 0x05: // Text: lyrics								$text_lyrics  = substr($METAeventData, 0, $METAeventLength);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['lyrics'] = $text_lyrics;								if (!isset($thisfile_midi['lyrics'])) {									$thisfile_midi['lyrics'] = '';								}								$thisfile_midi['lyrics'] .= $text_lyrics."\n";								break;							case 0x06: // Text: marker								$text_marker = substr($METAeventData, 0, $METAeventLength);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['marker'] = $text_marker;								break;							case 0x07: // Text: cue point								$text_cuepoint = substr($METAeventData, 0, $METAeventLength);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['cuepoint'] = $text_cuepoint;								break;							case 0x2F: // End Of Track								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['EOT'] = $CumulativeDeltaTime;								break;							case 0x51: // Tempo: microseconds / quarter note								$CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));								if ($CurrentMicroSecondsPerBeat == 0) {									$ThisFileInfo['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: // Time signature								$timesig_numerator   = getid3_lib::BigEndian2Int($METAeventData{0});								$timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData{1})); // $02 -> x/4, $03 -> x/8, etc								$timesig_32inqnote   = getid3_lib::BigEndian2Int($METAeventData{2});         // number of 32nd notes to the quarter note								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote']   = $timesig_32inqnote;								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator']   = $timesig_numerator;								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator;								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_text']        = $timesig_numerator.'/'.$timesig_denominator;								$thisfile_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator;								break;							case 0x59: // Keysignature								$keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData{0});								if ($keysig_sharpsflats & 0x80) {									// (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps)									$keysig_sharpsflats -= 256;								}								$keysig_majorminor  = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor								$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_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats']  = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0);								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor']  = (bool) $keysig_majorminor;								//$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_text']   = $keysigs[$keysig_sharpsflats].' '.($thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] ? 'minor' : 'major');								// $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect)								$thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool) $keysig_majorminor ? 'minor' : 'major');								break;							case 0x7F: // Sequencer specific information								$custom_data = substr($METAeventData, 0, $METAeventLength);								break;							default:								$ThisFileInfo['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand;								break;						}					} else {						$ThisFileInfo['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) {						$ThisFileInfo['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';						return false;					}					$ThisFileInfo['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) {					$ThisFileInfo['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';					return false;				}				$ThisFileInfo['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000);			}		}				if (@$ThisFileInfo['playtime_seconds'] > 0) {			$ThisFileInfo['bitrate'] = (($ThisFileInfo['avdataend'] - $ThisFileInfo['avdataoffset']) * 8) / $ThisFileInfo['playtime_seconds'];		}		if (!empty($thisfile_midi['lyrics'])) {			$thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics'];		}		return true;	}	function GeneralMIDIinstrumentLookup($instrumentid) {		$begin = __LINE__;		/** This is not a comment!			0	Acoustic Grand			1	Bright Acoustic			2	Electric Grand			3	Honky-Tonk			4	Electric Piano 1			5	Electric Piano 2			6	Harpsichord			7	Clavier			8	Celesta			9	Glockenspiel			10	Music Box			11	Vibraphone			12	Marimba			13	Xylophone			14	Tubular Bells			15	Dulcimer			16	Drawbar Organ			17	Percussive Organ			18	Rock Organ			19	Church Organ			20	Reed Organ			21	Accordian			22	Harmonica			23	Tango Accordian			24	Acoustic Guitar (nylon)			25	Acoustic Guitar (steel)			26	Electric Guitar (jazz)			27	Electric Guitar (clean)			28	Electric Guitar (muted)			29	Overdriven Guitar			30	Distortion Guitar			31	Guitar Harmonics			32	Acoustic Bass			33	Electric Bass (finger)			34	Electric Bass (pick)			35	Fretless Bass			36	Slap Bass 1			37	Slap Bass 2			38	Synth Bass 1			39	Synth Bass 2			40	Violin			41	Viola			42	Cello			43	Contrabass			44	Tremolo Strings			45	Pizzicato Strings			46	Orchestral Strings			47	Timpani			48	String Ensemble 1			49	String Ensemble 2			50	SynthStrings 1			51	SynthStrings 2			52	Choir Aahs			53	Voice Oohs			54	Synth Voice			55	Orchestra Hit			56	Trumpet			57	Trombone			58	Tuba			59	Muted Trumpet			60	French Horn			61	Brass Section			62	SynthBrass 1			63	SynthBrass 2			64	Soprano Sax			65	Alto Sax			66	Tenor Sax			67	Baritone Sax			68	Oboe			69	English Horn			70	Bassoon			71	Clarinet			72	Piccolo			73	Flute			74	Recorder			75	Pan Flute			76	Blown Bottle			77	Shakuhachi			78	Whistle			79	Ocarina			80	Lead 1 (square)			81	Lead 2 (sawtooth)			82	Lead 3 (calliope)			83	Lead 4 (chiff)			84	Lead 5 (charang)			85	Lead 6 (voice)			86	Lead 7 (fifths)			87	Lead 8 (bass + lead)			88	Pad 1 (new age)			89	Pad 2 (warm)			90	Pad 3 (polysynth)			91	Pad 4 (choir)			92	Pad 5 (bowed)			93	Pad 6 (metallic)			94	Pad 7 (halo)			95	Pad 8 (sweep)			96	FX 1 (rain)			97	FX 2 (soundtrack)			98	FX 3 (crystal)			99	FX 4 (atmosphere)			100	FX 5 (brightness)			101	FX 6 (goblins)			102	FX 7 (echoes)			103	FX 8 (sci-fi)			104	Sitar			105	Banjo			106	Shamisen			107	Koto			108	Kalimba			109	Bagpipe			110	Fiddle			111	Shanai			112	Tinkle Bell			113	Agogo			114	Steel Drums			115	Woodblock			116	Taiko Drum			117	Melodic Tom			118	Synth Drum			119	Reverse Cymbal			120	Guitar Fret Noise			121	Breath Noise			122	Seashore			123	Bird Tweet			124	Telephone Ring			125	Helicopter			126	Applause			127	Gunshot		*/		return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument');	}	function GeneralMIDIpercussionLookup($instrumentid) {		$begin = __LINE__;		/** This is not a comment!			35	Acoustic Bass Drum			36	Bass Drum 1			37	Side Stick			38	Acoustic Snare			39	Hand Clap			40	Electric Snare			41	Low Floor Tom			42	Closed Hi-Hat			43	High Floor Tom			44	Pedal Hi-Hat			45	Low Tom			46	Open Hi-Hat			47	Low-Mid Tom			48	Hi-Mid Tom			49	Crash Cymbal 1			50	High Tom			51	Ride Cymbal 1			52	Chinese Cymbal			53	Ride Bell			54	Tambourine			55	Splash Cymbal			56	Cowbell			57	Crash Cymbal 2			59	Ride Cymbal 2			60	Hi Bongo			61	Low Bongo			62	Mute Hi Conga			63	Open Hi Conga			64	Low Conga			65	High Timbale			66	Low Timbale			67	High Agogo			68	Low Agogo			69	Cabasa			70	Maracas			71	Short Whistle			72	Long Whistle			73	Short Guiro			74	Long Guiro			75	Claves			76	Hi Wood Block			77	Low Wood Block			78	Mute Cuica			79	Open Cuica			80	Mute Triangle			81	Open Triangle		*/		return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIpercussion');	}}?>
 |