Example #1
0
 /**
  * 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);
 }
Example #2
0
 /**
  * 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 ' . 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);
 }
Example #3
0
 /**
  * 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;
 }
Example #4
0
 /**
  * Parses the buffer stream for a meta event
  *
  * @since 1.0
  * @uses  read()
  * @uses  Util::unpack()
  * @uses  getDelta()
  * @uses  EventFactory::createMetaEvent()
  * 
  * @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->eventFactory->createMetaEvent($metaEventType, $data);
 }
 /**
  * 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);
 }
Example #6
0
 /**
  * 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);
     $binary .= Util::pack($this->param1, $this->param2);
     return $binary;
 }
Example #7
0
 /**
  * @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);
     // -- all of this goofy looking math just formats everything prettily -- //
     $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 />');
     }
     // -- end goofiness -- //
     $text .= '<td><tt>' . $delta . ' ' . $eventSegment . '</tt></td>';
     $this->offset += $event->getLength() + $this->delta->getLength();
     return $text;
 }
Example #8
0
 /**
  * Creates a meta event, or returns an {@link UnknownMetaEvent} if the specified
  * event type is not supported
  *
  * @since 1.1
  * @uses  Util::unpack()
  * 
  * @param  int    $eventType See {@link MetaEventType}
  * @param  binary $data      Binary data associated with the event
  * @return MetaEvent
  */
 public function createMetaEvent($eventType, $data)
 {
     switch ($eventType) {
         case MetaEventType::SEQUENCE_NUMBER:
             $data = Util::unpack($data);
             return new SequenceNumberEvent($data[0], $data[1]);
         case MetaEventType::TEXT_EVENT:
             return new TextEvent($data);
         case MetaEventType::COPYRIGHT_NOTICE:
             return new CopyrightNoticeEvent($data);
         case MetaEventType::TRACK_NAME:
             return new TrackNameEvent($data);
         case MetaEventType::INSTRUMENT_NAME:
             return new InstrumentNameEvent($data);
         case MetaEventType::LYRICS:
             return new LyricsEvent($data);
         case MetaEventType::MARKER:
             return new MarkerEvent($data);
         case MetaEventType::CUE_POINT:
             return new CuePointEvent($data);
         case MetaEventType::END_OF_TRACK:
             return new EndOfTrackEvent();
         case MetaEventType::CHANNEL_PREFIX:
             $data = Util::unpack($data);
             return new ChannelPrefixEvent($data[0]);
         case MetaEventType::SET_TEMPO:
             $data = Util::unpack($data);
             $mpqn = $data[0] << 16 | $data[1] << 8 | $data[2];
             return new SetTempoEvent($mpqn);
         case MetaEventType::SMPTE_OFFSET:
             $data = Util::unpack($data);
             $frameRate = $data[0] >> 5 & 0xff;
             $hour = $data[0] & 0x1f;
             list(, $minute, $second, $frame, $subFrame) = $data;
             return new SmpteOffsetEvent($frameRate, $hour, $minute, $second, $frame, $subFrame);
         case MetaEventType::TIME_SIGNATURE:
             $data = Util::unpack($data);
             return new TimeSignatureEvent($data[0], pow(2, $data[1]), $data[2], $data[3]);
         case MetaEventType::KEY_SIGNATURE:
             $data = Util::unpack($data);
             return new KeySignatureEvent($data[0], $data[1]);
         case MetaEventType::SEQUENCER_SPECIFIC:
             return new SequencerSpecificEvent($data);
         default:
             return new UnknownMetaEvent($data);
     }
 }
Example #9
0
 public function testPackWithNullValues()
 {
     $this->assertSame(pack('C2', 0x30, 0x20), Util::pack(0x30, 0x20, null));
 }
Example #10
0
 /**
  * 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);
 }
Example #11
0
 /**
  * @since 1.0
  * @uses  Util::getDeltaByteSequence()
  * 
  * @return binary
  */
 public function toBinary()
 {
     return Util::getDeltaByteSequence($this->ticks);
 }
Example #12
0
 /**
  * @since 1.0
  * @uses  Util::pack()
  * 
  * @return binary
  */
 public function toBinary()
 {
     return Util::pack(0x4d, 0x54, 0x68, 0x64) . Util::pack(0x0, 0x0, 0x0, 0x6) . Util::pack(0x0, $this->midiFormat) . Util::pack($this->numTracks >> 8, $this->numTracks & 0xff) . Util::pack($this->timeDivision >> 8, $this->timeDivision & 0xff);
 }
 public function testToBinary()
 {
     $binary = Util::pack(EventType::SYSTEM_EXCLUSIVE) . Util::getDeltaByteSequence(255) . str_repeat('x', 255);
     $this->assertEquals($binary, $this->obj->toBinary());
 }