/** * Parses the buffer stream for a meta event * * @since 1.0 * @uses read() * @uses Util::unpack() * @uses getDelta() * @uses getMetaEvent() * * @return MetaEvent */ protected function parseMetaEvent() { $metaEventType = Util::unpack($this->read(1, true)); $metaEventType = $metaEventType[0]; $length = $this->getDelta(); $data = $this->read($length, true); return $this->getMetaEvent($metaEventType, $data); }
/** * @since 1.0 * @uses getChunkClass() * @uses formatOffset() * @uses Delta::toBinary() * @uses Util::binaryToHex() * @uses Event::toBinary() * @uses Event::getLength() * @uses Delta::getLength() * * @param Event $event * @return string */ public function beforeEvent(Event $event) { if ($this->delta === null) { return ''; } $class = $this->getChunkClass($event); $text = "<tr class=\"{$class}\">" . $this->formatOffset($this->offset); $deltaHex = Util::binaryToHex($this->delta->toBinary()); $delta = '<span class="delta">' . wordwrap(implode(' ', $deltaHex), 23, '<br />') . '</span>'; $eventHex = Util::binaryToHex($event->toBinary()); $lineLength = 23 - strlen(implode(' ', $deltaHex)) % 23; $eventSegment = wordwrap(implode(' ', $eventHex), $lineLength, '|'); $bar = strpos($eventSegment, '|'); if ($bar !== false) { $eventSegment = substr($eventSegment, 0, $bar) . '<br />' . wordwrap(substr($eventSegment, $bar + 1), 23, '<br />'); } $text .= '<td><tt>' . $delta . ' ' . $eventSegment . '</tt></td>'; $this->offset += $event->getLength() + $this->delta->getLength(); return $text; }
/** * Gets a binary representation of this event * * @since 1.0 * @uses Util::pack() * * @return binary */ public function toBinary() { $binary = $this->isContinuation() ? '' : Util::pack($this->getType() | $this->channel); if ($this->param2 !== null) { $binary .= Util::pack($this->param1, $this->param2); } else { $binary .= Util::pack($this->param1); } return $binary; }
/** * Reads a delta time from the buffer stream * * @since 1.0 * @uses read() * @uses Util::unpack() * @uses Util::getTicksFromDeltaByteSequence() * * @return int The number of clock ticks in the delta time */ protected function getDelta() { $byte = $this->read(1, true); $value = Util::unpack($byte); $delta = ''; while ($this->file->valid() && $value[0] > 0x7f) { $delta .= $byte; $byte = $this->read(1); $value = Util::unpack($byte); } if ($byte !== null) { $delta .= $byte; } return Util::getTicksFromDeltaByteSequence($delta); }
/** * Gets whether this is a normal system exclusive event * * Normal sysex events are signified by the last byte of data * being 0xF7. * * @since 1.0 * @uses Util::pack() * @see isDivided() * * @return bool */ public function isNormal() { $byte = end($this->data); reset($this->data); return $byte === Util::pack(0xf7); }
/** * Gets the binary representation of this meta event * * @since 1.0 * @uses Util::pack() * @uses Util::getDeltaByteSequence() * @uses getSubtype() * * @return binary */ public function toBinary() { if (is_array($this->data)) { $data = ''; foreach ($this->data as $datum) { $data .= Util::pack($datum); } } else { $data = $this->data; } return Util::pack($this->getType(), $this->getSubtype()) . Util::getDeltaByteSequence($this->length) . $data; }
/** * Parses the given track header * * @since 1.0 * @uses TrackHeader::LENGTH * @uses Util::unpack() * * @param binary $header * @throws InvalidArgumentException * @throws {@link ParseException} if the header is invalid * @return TrackHeader */ public function parseTrackHeader($header) { /*if (strlen($header) !== TrackHeader::LENGTH) { throw new \InvalidArgumentException('Track header must be ' . \Midi\TrackHeader::LENGTH . ' bytes'); }*/ $id = Util::unpack(substr($header, 0, 4)); $size = array_reverse(Util::unpack(substr($header, 4))); if ($id !== array(0x4d, 0x54, 0x72, 0x6b)) { throw new ParseException('Invalid track header, expected [4D 54 72 6B]'); } $shift = 0; $trackSize = 0; foreach ($size as $byte) { $trackSize |= $byte << $shift; $shift += 8; } return new TrackHeader($trackSize); }
/** * Parses the given file header * * @since 1.0 * @uses FileHeader::LENGTH * @uses Util::unpack() * * @param binary $header * @throws InvalidArgumentException * @throws {@link ParseException} if the file header is not a valid MIDI file header * @return FileHeader */ public function parseFileHeader($header) { if (strlen($header) !== FileHeader::LENGTH) { throw new \InvalidArgumentException('MIDI file header must be ' . FileHeader::LENGTH . ' bytes'); } $id = Util::unpack(substr($header, 0, 4)); $chunkSize = Util::unpack(substr($header, 4, 4)); $format = Util::unpack(substr($header, 8, 2)); $tracks = Util::unpack(substr($header, 10, 2)); $timeDivision = Util::unpack(substr($header, 12, 2)); if ($id !== array(0x4d, 0x54, 0x68, 0x64)) { throw new ParseException('Invalid file header, expected byte sequence [4D 54 68 64]'); } if ($chunkSize !== array(0x0, 0x0, 0x0, 0x6)) { throw new ParseException('File header chunk size must be [00 00 00 06]'); } $format = $format[0] << 8 | $format[1]; $timeDivision = $timeDivision[0] << 8 | $timeDivision[1]; $tracks = $tracks[0] << 8 | $tracks[1]; if ($format !== 0 && $format !== 1 && $format !== 2) { throw new ParseException('MIDI file format must be 0, 1 or 2 (got ' . $format . ')'); } return new FileHeader($format, $tracks, $timeDivision); }