All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openimaj.time.Sequencer Maven / Gradle / Ivy

Go to download

Core library functionality concerned with general programming problems rather than multimedia specific functionality. Includes I/O utilities, randomisation, hashing and type conversion.

The newest version!
/**
 * Copyright (c) 2011, The University of Southampton and the individual contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *   * 	Redistributions of source code must retain the above copyright notice,
 * 	this list of conditions and the following disclaimer.
 *
 *   *	Redistributions in binary form must reproduce the above copyright notice,
 * 	this list of conditions and the following disclaimer in the documentation
 * 	and/or other materials provided with the distribution.
 *
 *   *	Neither the name of the University of Southampton nor the names of its
 * 	contributors may be used to endorse or promote products derived from this
 * 	software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 *
 */
package org.openimaj.time;

import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.TreeSet;

/**
 *	An object that will fire events at specific times thereby sequencing
 *	objects into a stream.  Can be used to trigger anything, such as animations
 *	on a slideshow or sequencing audio samples.
 *	

* The class is parameterised on a {@link Timecode} object which will be used * to determine whether actions should be triggered. The accuracy of the * triggers can be determined by changing the internal timer tick of the * sequencer. For example, if you know that actions will never occur more * than once a second, you can set the tick to something near a second. *

* This class will automatically start the {@link TimeKeeper} running when * it is run. The time of firing of an event cannot be guaranteed and an event * will always be fired if * * @author David Dupplaw ([email protected]) * @created 27 Nov 2011 */ public class Sequencer implements Runnable { /** * A class that can be sequenced by the sequencer can implement this * interface. The only method, {@link #performAction()}, should * execute the desired action. * * @author David Dupplaw ([email protected]) * @created 29 Nov 2011 */ static public interface SequencedAction { /** * Perform the sequenced action. * @return TRUE if the action trigger succeeded; FALSE otherwise. */ public boolean performAction(); } /** * An event in the sequencer, this represents an action occurring at a * specific time. * * @author David Dupplaw ([email protected]) * * @created 29 Nov 2011 */ static public class SequencerEvent implements Comparable { /** The sequenced action */ public SequencedAction action = null; /** The time at which the sequenced action should happen */ public long timestamp = 0; /** Whether the event has already been fired. */ public boolean fired = false; /** Whether the event failed to fire */ public boolean failed = false; /** * Create a new sequencer event that occurs at a specific time. * @param timestamp The time the sequencer event should occur. * @param action The action that should happen at the given time. */ public SequencerEvent( final long timestamp, final SequencedAction action ) { this.timestamp = timestamp; this.action = action; } /** * Create a new sequencer event that occurs at a specific time. * @param tc The time the sequencer event should occur. * @param action The action that should happen at the given time. */ public SequencerEvent( final Timecode tc, final SequencedAction action ) { this.timestamp = tc.getTimecodeInMilliseconds(); this.action = action; } /** * {@inheritDoc} * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo( final SequencerEvent event ) { final int v = (int)(this.timestamp - event.timestamp); if( v == 0 && event != this ) return -1; else return v; } /** * {@inheritDoc} * @see java.lang.Object#toString() */ @Override public String toString() { return "@"+this.timestamp; } } /** * A simple {@link TimerTask} that calls the private method checkForActions() * to check whether there are any actions that should be executed. * * @author David Dupplaw ([email protected]) * * @created 29 Nov 2011 */ private class CheckActionTask extends TimerTask { @Override public void run() { Sequencer.this.checkForActions(); } } /** The timekeeper that can provide the current time */ private TimeKeeper timeKeeper = null; /** Check for action triggers every 1000 milliseconds by default */ private long tickAccuracyMillis = 1000; /** The set of events - using a {@link TreeSet} so that they are ordered */ private final TreeSet events = new TreeSet(); /** Whether to remove the events from the sequencer when they are complete. */ private boolean removeEventsWhenComplete = true; /** Whether to retry failed events */ private boolean retryFailedEvents = false; /** The timer to use for event scheduling */ private Timer timer = null; /** * Default constructor that instantiates a sequencer that will check * for actions every 10 milliseconds using the given time keeper. * * @param timeKeeper The timekeeper to use */ public Sequencer( final TimeKeeper timeKeeper ) { this.timeKeeper = timeKeeper; } /** * Constructor that instantiates a sequencer that will check for actions * at the given rate using the given time keeper. * * @param timeKeeper The timekeeper to use * @param tickAccuracyMillis How often the sequencer will check for events. */ public Sequencer( final TimeKeeper timeKeeper, final long tickAccuracyMillis ) { this.timeKeeper = timeKeeper; this.tickAccuracyMillis = tickAccuracyMillis; } /** * Add an event to the sequencer. * @param event The event to add. */ public void addEvent( final SequencerEvent event ) { this.events.add( event ); } /** * {@inheritDoc} * @see java.lang.Runnable#run() */ @Override public void run() { new Thread( this.timeKeeper ).start(); this.timer = new Timer(); this.timer.scheduleAtFixedRate( new CheckActionTask(), 0, this.tickAccuracyMillis ); } /** * Returns the set of events in this sequencer. * @return The set of events in this sequencer. */ public TreeSet getEvents() { return this.events; } /** * Check whether any actions should be run. */ private void checkForActions() { // Time how long it takes to do the processing, so we can // subtract this time from the next timer final long startProcessingTime = System.currentTimeMillis(); // Get the current time final Timecode tc = this.timeKeeper.getTime(); final long t = tc.getTimecodeInMilliseconds(); final Iterator eventIterator = this.events.iterator(); while( eventIterator.hasNext() ) { // Get the next event. final SequencerEvent event = eventIterator.next(); // If the even was supposed to be fired in the past or now, // then we better get on and fire it. if( !event.fired && event.timestamp <= t ) { // Perform the action final boolean success = event.action.performAction(); // Remove the event if that's what we're to do... if( (success || !this.retryFailedEvents) && this.removeEventsWhenComplete ) eventIterator.remove(); else { // Set the event information if( this.retryFailedEvents ) event.fired = success; else event.fired = true; event.failed = !success; } } } // Set a new timer final long processingTime = System.currentTimeMillis() - startProcessingTime; long nextTime = this.tickAccuracyMillis - processingTime; while( nextTime < 0 ) nextTime += this.tickAccuracyMillis; } /** * Sets whether failed events will be retried at the next processing * time. * * @param rfe TRUE to retry failed events. */ public void setRetryFailedEvents( final boolean rfe ) { this.retryFailedEvents = rfe; } /** * Sets whether to remove events from the event list when they have * been completed. Doing so will speed up the processing * at each event check but events will be lost. A way around this is to * set up all your events then use {@link #getEvents()} to retrieve the * list of events and clone it. Failed events will be removed from * the list only if retryFailedEvents is set to false. * * @param rewc TRUE to remove successfully completed events. */ public void setRemoveEventsWhenComplete( final boolean rewc ) { this.removeEventsWhenComplete = rewc; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy