function _parseTrack($binStr, $tn) { //$trackLen2 = ((( (( (ord($binStr[0]) << 8) | ord($binStr[1]))<<8) | ord($binStr[2]) ) << 8 ) | ord($binStr[3]) ); //$trackLen2 += 4; $trackLen = strlen($binStr); // MM: ToDo: Warn if trackLen and trackLen2 are different!!! // if ($trackLen != $trackLen2) { echo "Warning: TrackLength is corrupt ($trackLen != $trackLen2)! \n"; } $p = 4; $time = 0; $track = array(); while ($p < $trackLen) { // timedelta $dt = _readVarLen($binStr, $p); $time += $dt; $byte = ord($binStr[$p]); $high = $byte >> 4; $low = $byte - $high * 16; switch ($high) { case 0xc: //PrCh = ProgramChange $chan = $low + 1; $prog = ord($binStr[$p + 1]); $last = 'PrCh'; $track[] = "{$time} PrCh ch={$chan} p={$prog}"; $p += 2; break; case 0x9: //On $chan = $low + 1; $note = ord($binStr[$p + 1]); $vel = ord($binStr[$p + 2]); $last = 'On'; $track[] = "{$time} On ch={$chan} n={$note} v={$vel}"; $p += 3; break; case 0x8: //Off $chan = $low + 1; $note = ord($binStr[$p + 1]); $vel = ord($binStr[$p + 2]); $last = 'Off'; $track[] = "{$time} Off ch={$chan} n={$note} v={$vel}"; $p += 3; break; case 0xa: //PoPr = PolyPressure $chan = $low + 1; $note = ord($binStr[$p + 1]); $val = ord($binStr[$p + 2]); $last = 'PoPr'; $track[] = "{$time} PoPr ch={$chan} n={$note} v={$val}"; $p += 3; break; case 0xb: //Par = ControllerChange $chan = $low + 1; $c = ord($binStr[$p + 1]); $val = ord($binStr[$p + 2]); $last = 'Par'; $track[] = "{$time} Par ch={$chan} c={$c} v={$val}"; $p += 3; break; case 0xd: //ChPr = ChannelPressure $chan = $low + 1; $val = ord($binStr[$p + 1]); $last = 'ChPr'; $track[] = "{$time} ChPr ch={$chan} v={$val}"; $p += 2; break; case 0xe: //Pb = PitchBend $chan = $low + 1; $val = ord($binStr[$p + 1]) & 0x7f | (ord($binStr[$p + 2]) & 0x7f) << 7; $last = 'Pb'; $track[] = "{$time} Pb ch={$chan} v={$val}"; $p += 3; break; default: switch ($byte) { case 0xff: // Meta $meta = ord($binStr[$p + 1]); switch ($meta) { case 0x0: // sequence_number $tmp = ord($binStr[$p + 2]); if ($tmp == 0x0) { $num = $tn; $p += 3; } else { $num = 1; $p += 5; } $track[] = "{$time} Seqnr {$num}"; break; case 0x1: // Meta Text // Meta Text case 0x2: // Meta Copyright // Meta Copyright case 0x3: // Meta TrackName ???sequence_name??? // Meta TrackName ???sequence_name??? case 0x4: // Meta InstrumentName // Meta InstrumentName case 0x5: // Meta Lyrics // Meta Lyrics case 0x6: // Meta Marker // Meta Marker case 0x7: // Meta Cue $texttypes = array('Text', 'Copyright', 'TrkName', 'InstrName', 'Lyric', 'Marker', 'Cue'); $type = $texttypes[$meta - 1]; $p += 2; $len = _readVarLen($binStr, $p); if ($len + $p > $trackLen) { _err("Meta {$type} has corrupt variable length field ({$len}) [track: {$tn} dt: {$dt}]"); } $txt = substr($binStr, $p, $len); $track[] = "{$time} Meta {$type} \"{$txt}\""; $p += $len; break; case 0x20: // ChannelPrefix $chan = ord($binStr[$p + 3]); if ($chan < 10) { $chan = '0' . $chan; } //??? $track[] = "{$time} Meta 0x20 {$chan}"; $p += 4; break; case 0x21: // ChannelPrefixOrPort $chan = ord($binStr[$p + 3]); if ($chan < 10) { $chan = '0' . $chan; } //??? $track[] = "{$time} Meta 0x21 {$chan}"; $p += 4; break; case 0x2f: // Meta TrkEnd $track[] = "{$time} Meta TrkEnd"; return $track; //ignore rest break; case 0x51: // Tempo $tempo = ord($binStr[$p + 3]) * 256 * 256 + ord($binStr[$p + 4]) * 256 + ord($binStr[$p + 5]); $track[] = "{$time} Tempo {$tempo}"; if ($tn == 0 && $time == 0) { $this->tempo = $tempo; // ??? $this->tempoMsgNum = count($track) - 1; } $p += 6; break; case 0x54: // SMPTE offset $h = ord($binStr[$p + 3]); $m = ord($binStr[$p + 4]); $s = ord($binStr[$p + 5]); $f = ord($binStr[$p + 6]); $fh = ord($binStr[$p + 7]); $track[] = "{$time} SMPTE {$h} {$m} {$s} {$f} {$fh}"; $p += 8; break; case 0x58: // TimeSig $z = ord($binStr[$p + 3]); $t = pow(2, ord($binStr[$p + 4])); $mc = ord($binStr[$p + 5]); $c = ord($binStr[$p + 6]); $track[] = "{$time} TimeSig {$z}/{$t} {$mc} {$c}"; $p += 7; break; case 0x59: // KeySig $vz = ord($binStr[$p + 3]); $g = ord($binStr[$p + 4]) == 0 ? 'major' : 'minor'; $track[] = "{$time} KeySig {$vz} {$g}"; $p += 5; break; case 0x7f: // Sequencer specific data (string or hexString???) $p += 2; $len = _readVarLen($binStr, $p); if ($len + $p > $trackLen) { _err("SeqSpec has corrupt variable length field ({$len}) [track: {$tn} dt: {$dt}]"); } $p -= 3; $data = ''; for ($i = 0; $i < $len; $i++) { $data .= ' ' . sprintf("%02x", ord($binStr[$p + 3 + $i])); } $track[] = "{$time} SeqSpec{$data}"; $p += $len + 3; break; default: // MM added: accept "unknown" Meta-Events $metacode = sprintf("%02x", ord($binStr[$p + 1])); $p += 2; $len = _readVarLen($binStr, $p); if ($len + $p > $trackLen) { _err("Meta {$metacode} has corrupt variable length field ({$len}) [track: {$tn} dt: {$dt}]"); } $p -= 3; $data = ''; for ($i = 0; $i < $len; $i++) { $data .= ' ' . sprintf("%02x", ord($binStr[$p + 3 + $i])); } $track[] = "{$time} Meta 0x{$metacode} {$data}"; $p += $len + 3; break; } // switch ($meta) break; // Ende Meta // Ende Meta case 0xf0: // SysEx $p += 1; $len = _readVarLen($binStr, $p); if ($len + $p > $trackLen) { _err("SysEx has corrupt variable length field ({$len}) [track: {$tn} dt: {$dt} p: {$p}]"); } $str = 'f0'; for ($i = 0; $i < $len; $i++) { $str .= ' ' . sprintf("%02x", ord($binStr[$p + $i])); } # FIXED $track[] = "{$time} SysEx {$str}"; $p += $len; break; default: // Repetition of last event? switch ($last) { case 'On': case 'Off': $note = ord($binStr[$p]); $vel = ord($binStr[$p + 1]); $track[] = "{$time} {$last} ch={$chan} n={$note} v={$vel}"; $p += 2; break; case 'PrCh': $prog = ord($binStr[$p]); $track[] = "{$time} PrCh ch={$chan} p={$prog}"; $p += 1; break; case 'PoPr': $note = ord($binStr[$p + 1]); $val = ord($binStr[$p + 2]); $track[] = "{$time} PoPr ch={$chan} n={$note} v={$val}"; $p += 2; break; case 'ChPr': $val = ord($binStr[$p]); $track[] = "{$time} ChPr ch={$chan} v={$val}"; $p += 1; break; case 'Par': $c = ord($binStr[$p]); $val = ord($binStr[$p + 1]); $track[] = "{$time} Par ch={$chan} c={$c} v={$val}"; $p += 2; break; case 'Pb': $val = ord($binStr[$p]) & 0x7f | (ord($binStr[$p + 1]) & 0x7f) << 7; $track[] = "{$time} Pb ch={$chan} v={$val}"; $p += 2; break; default: // MM: ToDo: Repetition of SysEx and META-events? with <last>?? \n"; _err("unknown repetition: {$last}"); } // switch ($last) } // switch ($byte) } // switch ($high) } // while return $track; }
function _parseTrack($binStr, $tn) { $trackLen = strlen($binStr); $p = 4; $time = 0; $track = array(); while ($p < $trackLen) { // timedelta $dt = _readVarLen($binStr, $p); $time += $dt; $byte = ord($binStr[$p]); $high = $byte >> 4; $low = $byte - $high * 16; switch ($high) { case 0xc: //PrCh = ProgramChange $chan = $low + 1; $prog = ord($binStr[$p + 1]); $track[] = "{$time} PrCh ch={$chan} p={$prog}"; $p += 2; break; case 0x9: //On $chan = $low + 1; $note = ord($binStr[$p + 1]); $vel = ord($binStr[$p + 2]); $last = 'On'; $track[] = "{$time} On ch={$chan} n={$note} v={$vel}"; $p += 3; break; case 0x8: //Off $chan = $low + 1; $note = ord($binStr[$p + 1]); $vel = ord($binStr[$p + 2]); $last = 'Off'; $track[] = "{$time} Off ch={$chan} n={$note} v={$vel}"; $p += 3; break; case 0xa: //PoPr = PolyPressure $chan = $low + 1; $note = ord($binStr[$p + 1]); $val = ord($binStr[$p + 2]); $last = 'PoPr'; $track[] = "{$time} PoPr ch={$chan} n={$note} v={$val}"; $p += 3; break; case 0xb: //Par = ControllerChange $chan = $low + 1; $c = ord($binStr[$p + 1]); $val = ord($binStr[$p + 2]); $last = 'Par'; $track[] = "{$time} Par ch={$chan} c={$c} v={$val}"; $p += 3; break; case 0xd: //ChPr = ChannelPressure $chan = $low + 1; $val = ord($binStr[$p + 1]); $last = 'ChPr'; $track[] = "{$time} ChPr ch={$chan} v={$val}"; $p += 2; break; case 0xe: //Pb = PitchBend $chan = $low + 1; $val = ord($binStr[$p + 1]) + (ord($binStr[$p + 2]) - 64) * 128; $last = 'Pb'; $track[] = "{$time} Pb ch={$chan} v={$val}"; $p += 3; break; default: switch ($byte) { case 0xff: // Meta $meta = ord($binStr[$p + 1]); switch ($meta) { case 0x0: // sequence_number $num = ord($binStr[$p + 2]); $track[] = "{$time} Seqnr {$num}"; $p += 2; break; case 0x1: // Meta Text // Meta Text case 0x2: // Meta Copyright // Meta Copyright case 0x3: // Meta TrackName ???sequence_name??? // Meta TrackName ???sequence_name??? case 0x4: // Meta InstrumentName // Meta InstrumentName case 0x5: // Meta Lyrics // Meta Lyrics case 0x6: // Meta Marker // Meta Marker case 0x7: // Meta Cue $texttypes = array('Text', 'Copyright', 'TrkName', 'InstrName', 'Lyric', 'Marker', 'Cue'); $type = $texttypes[$meta - 1]; $len = ord($binStr[$p + 2]); $txt = substr($binStr, $p + 3, $len); $track[] = "{$time} Meta {$type} \"{$txt}\""; $p += $len + 3; break; case 0x20: // ChannelPrefix $chan = ord($binStr[$p + 3]); if ($chan < 10) { $chan = '0' . $chan; } //??? $track[] = "{$time} Meta 0x20 {$chan}"; $p += 4; break; case 0x21: // ChannelPrefixOrPort $chan = ord($binStr[$p + 3]); if ($chan < 10) { $chan = '0' . $chan; } //??? $track[] = "{$time} Meta 0x21 {$chan}"; $p += 4; break; case 0x2f: // Meta TrkEnd $track[] = "{$time} Meta TrkEnd"; $p += 3; break; case 0x51: // Tempo $tempo = ord($binStr[$p + 3]) * 256 * 256 + ord($binStr[$p + 4]) * 256 + ord($binStr[$p + 5]); $track[] = "{$time} Tempo {$tempo}"; if ($tn == 0 && $time == 0) { $this->tempo = $tempo; // ??? $this->tempoMsgNum = count($track) - 1; } $p += 6; break; case 0x54: // SMPTE offset $h = ord($binStr[$p + 3]); $m = ord($binStr[$p + 4]); $s = ord($binStr[$p + 5]); $f = ord($binStr[$p + 6]); $fh = ord($binStr[$p + 7]); $track[] = "{$time} SMPTE {$h} {$m} {$s} {$f} {$fh}"; $p += 8; break; case 0x58: // TimeSig $z = ord($binStr[$p + 3]); $t = pow(2, ord($binStr[$p + 4])); $mc = ord($binStr[$p + 5]); $c = ord($binStr[$p + 6]); $track[] = "{$time} TimeSig {$z}/{$t} {$mc} {$c}"; $p += 7; break; case 0x59: // KeySig $vz = ord($binStr[$p + 3]); $g = ord($binStr[$p + 4]) == 0 ? 'major' : 'minor'; $track[] = "{$time} KeySig {$vz} {$g}"; $p += 5; break; case 0x7f: // Sequencer specific data (string or hexString???) $len = ord($binStr[$p + 2]); $data = substr($binStr, $p + 3, $len); $track[] = "{$time} SeqSpec \"{$data}\""; $p += $len + 3; break; default: _err(">>> unknown meta event: {$time} {$byte} {$meta}"); } break; // Ende Meta // Ende Meta case 0xf0: // SysEx $len = ord($binStr[$p + 1]); $str = 'f0'; for ($i = 0; $i < $len; $i++) { $str .= ' ' . sprintf("%02x", ord($binStr[$p + 2 + $i])); } $track[] = "{$time} SysEx {$str}"; $p += $len + 2; break; default: //Repetition of last event? switch ($last) { case 'On': case 'Off': $note = ord($binStr[$p]); $vel = ord($binStr[$p + 1]); $track[] = "{$time} {$last} ch={$chan} n={$note} v={$vel}"; $p += 2; break; case 'PoPr': $note = ord($binStr[$p + 1]); $val = ord($binStr[$p + 2]); $track[] = "{$time} PoPr ch={$chan} n={$note} v={$val}"; $p += 2; break; case 'ChPr': $val = ord($binStr[$p]); $track[] = "{$time} ChPr ch={$chan} v={$val}"; $p += 1; break; case 'Par': $c = ord($binStr[$p]); $val = ord($binStr[$p + 1]); $track[] = "{$time} Par ch={$chan} c={$c} v={$val}"; $p += 2; break; case 'Pb': $val = ord($binStr[$p]) + ord($binStr[$p + 1]) * 128; $track[] = "{$time} Pb ch={$chan} v={$val}"; $p += 2; break; default: _err(">>> unknown repetition: {$last}"); } } } } return $track; }