public function notifyDiff(SSLHistoryDiffDom $dom)
 {
     $tracks = $dom->getTracks();
     foreach ($tracks as $track) {
         if ($track->isPlayed()) {
             $this->notifyScrobbleObservers($track);
         }
     }
 }
 /**
  * Notify the deck of a group of changes written to the History File.
  * 
  * SSL batches writes of track info, but doesn't output them in the 
  * natural transition order - that is, sometimes information about the following
  * song appears in the log before closing info on the previous song, as the
  * History File is track oriented, not deck oriented.
  * 
  * During notify(), we reorder this information into an order that's
  * transition compatible (that is, row ID ascending order).
  * 
  * The implication of sending a bunch of track notifications together (rather
  * than one by one) is that they happen simultaneously, and the end result
  * is what's important rather than every step to get there.
  * 
  * As diffs usually only come during track load, change or eject, it would be
  * abnormal to see information about more than 2 tracks on a single deck here,
  * and abnormal for neither of them to be the one currently on the deck.
  * 
  * However, it can happen - for example, loading a historical file or starting
  * the monitor half way through a session.
  * 
  * @param SSLHistoryDiffDom $diff
  */
 public function notify(SSLHistoryDiffDom $diff)
 {
     $this->resetFlags();
     $starting_track = $this->track;
     if (isset($starting_track)) {
         $starting_track_row = $starting_track->getRow();
     }
     // filter out tracks that are not for this deck, or that are too old
     $my_tracks = array();
     foreach ($diff->getTracks() as $track) {
         /* @var $track SSLTrack */
         if ($track->getDeck() == $this->deck_number && $track->getRow() >= $this->max_row) {
             // track notification for this deck!
             $my_tracks[$track->getRow()] = $track;
             L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Saw %s in diff (row %s)", array($track->getTitle(), $track->getRow()));
         }
     }
     // sort into natural 'history' order (that is, by row ID ascending)
     ksort($my_tracks);
     foreach ($my_tracks as $track) {
         try {
             $this->transitionTo($track);
         } catch (SSLInvalidTransitionException $e) {
             L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, "Invalid Transition: %s", array($e->getMessage()));
         }
     }
     // set status flags
     if ($this->track && (!$starting_track || $this->track->getRow() != $starting_track_row)) {
         // There is now a track where there was none.
         $this->track_started = $this->track;
     }
     if ($starting_track && (!$this->track || $this->track->getRow() != $starting_track_row)) {
         // There is now no track where there was one.
         // Make sure we're using the newest track object from the file.
         // If we've changed file since the last playing track (i.e. End Session or
         // Serato restart) then this won't exist.
         if (isset($my_tracks[$starting_track->getRow()])) {
             $this->track_stopped = $my_tracks[$starting_track->getRow()];
         }
     }
     if ($this->track && $starting_track && $this->track->getRow() == $starting_track_row && $this->track !== $starting_track) {
         // The track on the deck is the same as before, but the object has been replaced.
         // (We signal this as an update on the principle that there's absolutely no reason
         // that SSL would log the same row twice unless there was new information in the new
         // row).
         $this->track_updated = $this->track;
     }
 }
 /**
  * Update model information based on changes to the SSL History.
  * 
  * @param SSLHistoryDiffDom $diff
  */
 public function notifyDiff(SSLHistoryDiffDom $diff)
 {
     foreach ($diff->getTracks() as $track) {
         /* @var $track SSLTrack */
         // create track deck on demand
         $this->getDeck($track->getDeck());
     }
     $events = array();
     foreach ($this->decks as $deck_number => $deck) {
         /* @var $deck SSLRealtimeModelDeck */
         $deck->notify($diff);
         $stopped_track = $deck->trackStopped();
         if ($stopped_track) {
             $events[] = $this->factory->newTrackStoppedEvent($stopped_track);
         }
         $started_track = $deck->trackStarted();
         if ($started_track) {
             $events[] = $this->factory->newTrackStartedEvent($started_track);
         }
         $updated_track = $deck->trackUpdated();
         if ($updated_track) {
             $events[] = $this->factory->newTrackUpdatedEvent($updated_track);
         }
     }
     if (count($events)) {
         $events = $this->factory->newTrackChangeEventList($events);
         L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "notifying %s", array($events));
         $this->notifyTrackChangeObservers($events);
     }
 }