PageRenderTime 28ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/getid3/module.audio.midi.php

https://bitbucket.org/holyfield/getid3
PHP | 525 lines | 240 code | 67 blank | 218 comment | 50 complexity | 0730c20ee7f29ac1f7c81c84eedbdd5b MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /////////////////////////////////////////////////////////////////
  3. /// getID3() by James Heinrich <info@getid3.org> //
  4. // available at http://getid3.sourceforge.net //
  5. // or http://www.getid3.org //
  6. /////////////////////////////////////////////////////////////////
  7. // See readme.txt for more details //
  8. /////////////////////////////////////////////////////////////////
  9. // //
  10. // module.audio.midi.php //
  11. // module for Midi Audio files //
  12. // dependencies: NONE //
  13. // ///
  14. /////////////////////////////////////////////////////////////////
  15. define('GETID3_MIDI_MAGIC_MTHD', 'MThd'); // MIDI file header magic
  16. define('GETID3_MIDI_MAGIC_MTRK', 'MTrk'); // MIDI track header magic
  17. class getid3_midi extends getid3_handler
  18. {
  19. var $scanwholefile = true;
  20. function Analyze() {
  21. $info = &$this->getid3->info;
  22. // shortcut
  23. $info['midi']['raw'] = array();
  24. $thisfile_midi = &$info['midi'];
  25. $thisfile_midi_raw = &$thisfile_midi['raw'];
  26. $info['fileformat'] = 'midi';
  27. $info['audio']['dataformat'] = 'midi';
  28. fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
  29. $MIDIdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size());
  30. $offset = 0;
  31. $MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd'
  32. if ($MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) {
  33. $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"';
  34. unset($info['fileformat']);
  35. return false;
  36. }
  37. $offset += 4;
  38. $thisfile_midi_raw['headersize'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));
  39. $offset += 4;
  40. $thisfile_midi_raw['fileformat'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
  41. $offset += 2;
  42. $thisfile_midi_raw['tracks'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
  43. $offset += 2;
  44. $thisfile_midi_raw['ticksperqnote'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2));
  45. $offset += 2;
  46. for ($i = 0; $i < $thisfile_midi_raw['tracks']; $i++) {
  47. while ((strlen($MIDIdata) - $offset) < 8) {
  48. $MIDIdata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size());
  49. }
  50. $trackID = substr($MIDIdata, $offset, 4);
  51. $offset += 4;
  52. if ($trackID == GETID3_MIDI_MAGIC_MTRK) {
  53. $tracksize = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4));
  54. $offset += 4;
  55. // $thisfile_midi['tracks'][$i]['size'] = $tracksize;
  56. $trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize);
  57. $offset += $tracksize;
  58. } else {
  59. $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTRK).'" at '.($offset - 4).', found "'.getid3_lib::PrintHexBytes($trackID).'" instead';
  60. return false;
  61. }
  62. }
  63. if (!isset($trackdataarray) || !is_array($trackdataarray)) {
  64. $info['error'][] = 'Cannot find MIDI track information';
  65. unset($thisfile_midi);
  66. unset($info['fileformat']);
  67. return false;
  68. }
  69. if ($this->scanwholefile) { // this can take quite a long time, so have the option to bypass it if speed is very important
  70. $thisfile_midi['totalticks'] = 0;
  71. $info['playtime_seconds'] = 0;
  72. $CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
  73. $CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat
  74. $MicroSecondsPerQuarterNoteAfter = array ();
  75. foreach ($trackdataarray as $tracknumber => $trackdata) {
  76. $eventsoffset = 0;
  77. $LastIssuedMIDIcommand = 0;
  78. $LastIssuedMIDIchannel = 0;
  79. $CumulativeDeltaTime = 0;
  80. $TicksAtCurrentBPM = 0;
  81. while ($eventsoffset < strlen($trackdata)) {
  82. $eventid = 0;
  83. if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) {
  84. $eventid = count($MIDIevents[$tracknumber]);
  85. }
  86. $deltatime = 0;
  87. for ($i = 0; $i < 4; $i++) {
  88. $deltatimebyte = ord(substr($trackdata, $eventsoffset++, 1));
  89. $deltatime = ($deltatime << 7) + ($deltatimebyte & 0x7F);
  90. if ($deltatimebyte & 0x80) {
  91. // another byte follows
  92. } else {
  93. break;
  94. }
  95. }
  96. $CumulativeDeltaTime += $deltatime;
  97. $TicksAtCurrentBPM += $deltatime;
  98. $MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime;
  99. $MIDI_event_channel = ord(substr($trackdata, $eventsoffset++, 1));
  100. if ($MIDI_event_channel & 0x80) {
  101. // OK, normal event - MIDI command has MSB set
  102. $LastIssuedMIDIcommand = $MIDI_event_channel >> 4;
  103. $LastIssuedMIDIchannel = $MIDI_event_channel & 0x0F;
  104. } else {
  105. // running event - assume last command
  106. $eventsoffset--;
  107. }
  108. $MIDIevents[$tracknumber][$eventid]['eventid'] = $LastIssuedMIDIcommand;
  109. $MIDIevents[$tracknumber][$eventid]['channel'] = $LastIssuedMIDIchannel;
  110. if ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x08) { // Note off (key is released)
  111. $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
  112. $velocity = ord(substr($trackdata, $eventsoffset++, 1));
  113. } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x09) { // Note on (key is pressed)
  114. $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
  115. $velocity = ord(substr($trackdata, $eventsoffset++, 1));
  116. } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0A) { // Key after-touch
  117. $notenumber = ord(substr($trackdata, $eventsoffset++, 1));
  118. $velocity = ord(substr($trackdata, $eventsoffset++, 1));
  119. } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0B) { // Control Change
  120. $controllernum = ord(substr($trackdata, $eventsoffset++, 1));
  121. $newvalue = ord(substr($trackdata, $eventsoffset++, 1));
  122. } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0C) { // Program (patch) change
  123. $newprogramnum = ord(substr($trackdata, $eventsoffset++, 1));
  124. $thisfile_midi_raw['track'][$tracknumber]['instrumentid'] = $newprogramnum;
  125. if ($tracknumber == 10) {
  126. $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIpercussionLookup($newprogramnum);
  127. } else {
  128. $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIinstrumentLookup($newprogramnum);
  129. }
  130. } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0D) { // Channel after-touch
  131. $channelnumber = ord(substr($trackdata, $eventsoffset++, 1));
  132. } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0E) { // Pitch wheel change (2000H is normal or no change)
  133. $changeLSB = ord(substr($trackdata, $eventsoffset++, 1));
  134. $changeMSB = ord(substr($trackdata, $eventsoffset++, 1));
  135. $pitchwheelchange = (($changeMSB & 0x7F) << 7) & ($changeLSB & 0x7F);
  136. } elseif (($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0F) && ($MIDIevents[$tracknumber][$eventid]['channel'] == 0x0F)) {
  137. $METAeventCommand = ord(substr($trackdata, $eventsoffset++, 1));
  138. $METAeventLength = ord(substr($trackdata, $eventsoffset++, 1));
  139. $METAeventData = substr($trackdata, $eventsoffset, $METAeventLength);
  140. $eventsoffset += $METAeventLength;
  141. switch ($METAeventCommand) {
  142. case 0x00: // Set track sequence number
  143. $track_sequence_number = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
  144. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['seqno'] = $track_sequence_number;
  145. break;
  146. case 0x01: // Text: generic
  147. $text_generic = substr($METAeventData, 0, $METAeventLength);
  148. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['text'] = $text_generic;
  149. $thisfile_midi['comments']['comment'][] = $text_generic;
  150. break;
  151. case 0x02: // Text: copyright
  152. $text_copyright = substr($METAeventData, 0, $METAeventLength);
  153. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['copyright'] = $text_copyright;
  154. $thisfile_midi['comments']['copyright'][] = $text_copyright;
  155. break;
  156. case 0x03: // Text: track name
  157. $text_trackname = substr($METAeventData, 0, $METAeventLength);
  158. $thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname;
  159. break;
  160. case 0x04: // Text: track instrument name
  161. $text_instrument = substr($METAeventData, 0, $METAeventLength);
  162. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['instrument'] = $text_instrument;
  163. break;
  164. case 0x05: // Text: lyrics
  165. $text_lyrics = substr($METAeventData, 0, $METAeventLength);
  166. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['lyrics'] = $text_lyrics;
  167. if (!isset($thisfile_midi['lyrics'])) {
  168. $thisfile_midi['lyrics'] = '';
  169. }
  170. $thisfile_midi['lyrics'] .= $text_lyrics."\n";
  171. break;
  172. case 0x06: // Text: marker
  173. $text_marker = substr($METAeventData, 0, $METAeventLength);
  174. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['marker'] = $text_marker;
  175. break;
  176. case 0x07: // Text: cue point
  177. $text_cuepoint = substr($METAeventData, 0, $METAeventLength);
  178. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['cuepoint'] = $text_cuepoint;
  179. break;
  180. case 0x2F: // End Of Track
  181. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['EOT'] = $CumulativeDeltaTime;
  182. break;
  183. case 0x51: // Tempo: microseconds / quarter note
  184. $CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength));
  185. if ($CurrentMicroSecondsPerBeat == 0) {
  186. $info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero';
  187. return false;
  188. }
  189. $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat;
  190. $CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60;
  191. $MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat;
  192. $TicksAtCurrentBPM = 0;
  193. break;
  194. case 0x58: // Time signature
  195. $timesig_numerator = getid3_lib::BigEndian2Int($METAeventData{0});
  196. $timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData{1})); // $02 -> x/4, $03 -> x/8, etc
  197. $timesig_32inqnote = getid3_lib::BigEndian2Int($METAeventData{2}); // number of 32nd notes to the quarter note
  198. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote'] = $timesig_32inqnote;
  199. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator'] = $timesig_numerator;
  200. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator;
  201. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_text'] = $timesig_numerator.'/'.$timesig_denominator;
  202. $thisfile_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator;
  203. break;
  204. case 0x59: // Keysignature
  205. $keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData{0});
  206. if ($keysig_sharpsflats & 0x80) {
  207. // (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps)
  208. $keysig_sharpsflats -= 256;
  209. }
  210. $keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor
  211. $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#');
  212. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0);
  213. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats'] = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0);
  214. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] = (bool) $keysig_majorminor;
  215. //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_text'] = $keysigs[$keysig_sharpsflats].' '.($thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] ? 'minor' : 'major');
  216. // $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect)
  217. $thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool) $keysig_majorminor ? 'minor' : 'major');
  218. break;
  219. case 0x7F: // Sequencer specific information
  220. $custom_data = substr($METAeventData, 0, $METAeventLength);
  221. break;
  222. default:
  223. $info['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand;
  224. break;
  225. }
  226. } else {
  227. $info['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel'];
  228. }
  229. }
  230. if (($tracknumber > 0) || (count($trackdataarray) == 1)) {
  231. $thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime);
  232. }
  233. }
  234. $previoustickoffset = null;
  235. ksort($MicroSecondsPerQuarterNoteAfter);
  236. foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) {
  237. if (is_null($previoustickoffset)) {
  238. $prevmicrosecondsperbeat = $microsecondsperbeat;
  239. $previoustickoffset = $tickoffset;
  240. continue;
  241. }
  242. if ($thisfile_midi['totalticks'] > $tickoffset) {
  243. if ($thisfile_midi_raw['ticksperqnote'] == 0) {
  244. $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
  245. return false;
  246. }
  247. $info['playtime_seconds'] += (($tickoffset - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($prevmicrosecondsperbeat / 1000000);
  248. $prevmicrosecondsperbeat = $microsecondsperbeat;
  249. $previoustickoffset = $tickoffset;
  250. }
  251. }
  252. if ($thisfile_midi['totalticks'] > $previoustickoffset) {
  253. if ($thisfile_midi_raw['ticksperqnote'] == 0) {
  254. $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero';
  255. return false;
  256. }
  257. $info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000);
  258. }
  259. }
  260. if (!empty($info['playtime_seconds'])) {
  261. $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
  262. }
  263. if (!empty($thisfile_midi['lyrics'])) {
  264. $thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics'];
  265. }
  266. return true;
  267. }
  268. function GeneralMIDIinstrumentLookup($instrumentid) {
  269. $begin = __LINE__;
  270. /* This is not a comment!
  271. 0 Acoustic Grand
  272. 1 Bright Acoustic
  273. 2 Electric Grand
  274. 3 Honky-Tonk
  275. 4 Electric Piano 1
  276. 5 Electric Piano 2
  277. 6 Harpsichord
  278. 7 Clavier
  279. 8 Celesta
  280. 9 Glockenspiel
  281. 10 Music Box
  282. 11 Vibraphone
  283. 12 Marimba
  284. 13 Xylophone
  285. 14 Tubular Bells
  286. 15 Dulcimer
  287. 16 Drawbar Organ
  288. 17 Percussive Organ
  289. 18 Rock Organ
  290. 19 Church Organ
  291. 20 Reed Organ
  292. 21 Accordian
  293. 22 Harmonica
  294. 23 Tango Accordian
  295. 24 Acoustic Guitar (nylon)
  296. 25 Acoustic Guitar (steel)
  297. 26 Electric Guitar (jazz)
  298. 27 Electric Guitar (clean)
  299. 28 Electric Guitar (muted)
  300. 29 Overdriven Guitar
  301. 30 Distortion Guitar
  302. 31 Guitar Harmonics
  303. 32 Acoustic Bass
  304. 33 Electric Bass (finger)
  305. 34 Electric Bass (pick)
  306. 35 Fretless Bass
  307. 36 Slap Bass 1
  308. 37 Slap Bass 2
  309. 38 Synth Bass 1
  310. 39 Synth Bass 2
  311. 40 Violin
  312. 41 Viola
  313. 42 Cello
  314. 43 Contrabass
  315. 44 Tremolo Strings
  316. 45 Pizzicato Strings
  317. 46 Orchestral Strings
  318. 47 Timpani
  319. 48 String Ensemble 1
  320. 49 String Ensemble 2
  321. 50 SynthStrings 1
  322. 51 SynthStrings 2
  323. 52 Choir Aahs
  324. 53 Voice Oohs
  325. 54 Synth Voice
  326. 55 Orchestra Hit
  327. 56 Trumpet
  328. 57 Trombone
  329. 58 Tuba
  330. 59 Muted Trumpet
  331. 60 French Horn
  332. 61 Brass Section
  333. 62 SynthBrass 1
  334. 63 SynthBrass 2
  335. 64 Soprano Sax
  336. 65 Alto Sax
  337. 66 Tenor Sax
  338. 67 Baritone Sax
  339. 68 Oboe
  340. 69 English Horn
  341. 70 Bassoon
  342. 71 Clarinet
  343. 72 Piccolo
  344. 73 Flute
  345. 74 Recorder
  346. 75 Pan Flute
  347. 76 Blown Bottle
  348. 77 Shakuhachi
  349. 78 Whistle
  350. 79 Ocarina
  351. 80 Lead 1 (square)
  352. 81 Lead 2 (sawtooth)
  353. 82 Lead 3 (calliope)
  354. 83 Lead 4 (chiff)
  355. 84 Lead 5 (charang)
  356. 85 Lead 6 (voice)
  357. 86 Lead 7 (fifths)
  358. 87 Lead 8 (bass + lead)
  359. 88 Pad 1 (new age)
  360. 89 Pad 2 (warm)
  361. 90 Pad 3 (polysynth)
  362. 91 Pad 4 (choir)
  363. 92 Pad 5 (bowed)
  364. 93 Pad 6 (metallic)
  365. 94 Pad 7 (halo)
  366. 95 Pad 8 (sweep)
  367. 96 FX 1 (rain)
  368. 97 FX 2 (soundtrack)
  369. 98 FX 3 (crystal)
  370. 99 FX 4 (atmosphere)
  371. 100 FX 5 (brightness)
  372. 101 FX 6 (goblins)
  373. 102 FX 7 (echoes)
  374. 103 FX 8 (sci-fi)
  375. 104 Sitar
  376. 105 Banjo
  377. 106 Shamisen
  378. 107 Koto
  379. 108 Kalimba
  380. 109 Bagpipe
  381. 110 Fiddle
  382. 111 Shanai
  383. 112 Tinkle Bell
  384. 113 Agogo
  385. 114 Steel Drums
  386. 115 Woodblock
  387. 116 Taiko Drum
  388. 117 Melodic Tom
  389. 118 Synth Drum
  390. 119 Reverse Cymbal
  391. 120 Guitar Fret Noise
  392. 121 Breath Noise
  393. 122 Seashore
  394. 123 Bird Tweet
  395. 124 Telephone Ring
  396. 125 Helicopter
  397. 126 Applause
  398. 127 Gunshot
  399. */
  400. return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument');
  401. }
  402. function GeneralMIDIpercussionLookup($instrumentid) {
  403. $begin = __LINE__;
  404. /* This is not a comment!
  405. 35 Acoustic Bass Drum
  406. 36 Bass Drum 1
  407. 37 Side Stick
  408. 38 Acoustic Snare
  409. 39 Hand Clap
  410. 40 Electric Snare
  411. 41 Low Floor Tom
  412. 42 Closed Hi-Hat
  413. 43 High Floor Tom
  414. 44 Pedal Hi-Hat
  415. 45 Low Tom
  416. 46 Open Hi-Hat
  417. 47 Low-Mid Tom
  418. 48 Hi-Mid Tom
  419. 49 Crash Cymbal 1
  420. 50 High Tom
  421. 51 Ride Cymbal 1
  422. 52 Chinese Cymbal
  423. 53 Ride Bell
  424. 54 Tambourine
  425. 55 Splash Cymbal
  426. 56 Cowbell
  427. 57 Crash Cymbal 2
  428. 59 Ride Cymbal 2
  429. 60 Hi Bongo
  430. 61 Low Bongo
  431. 62 Mute Hi Conga
  432. 63 Open Hi Conga
  433. 64 Low Conga
  434. 65 High Timbale
  435. 66 Low Timbale
  436. 67 High Agogo
  437. 68 Low Agogo
  438. 69 Cabasa
  439. 70 Maracas
  440. 71 Short Whistle
  441. 72 Long Whistle
  442. 73 Short Guiro
  443. 74 Long Guiro
  444. 75 Claves
  445. 76 Hi Wood Block
  446. 77 Low Wood Block
  447. 78 Mute Cuica
  448. 79 Open Cuica
  449. 80 Mute Triangle
  450. 81 Open Triangle
  451. */
  452. return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIpercussion');
  453. }
  454. }