Example #1
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 #2
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 #3
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 #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);
 }
Example #5
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);
 }