/*
 *	TPreloadingSequencer.java
 */

/*
 *  Copyright (c) 2003 by Matthias Pfisterer
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as published
 *   by the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package	org.tritonus.share.midi;

import	java.io.InputStream;
import	java.io.IOException;

import	java.util.BitSet;
import	java.util.Collection;
import	java.util.Iterator;
import	java.util.Set;

import	javax.sound.midi.MidiSystem;
import	javax.sound.midi.Sequencer;
import	javax.sound.midi.Sequence;
import	javax.sound.midi.InvalidMidiDataException;
import	javax.sound.midi.MetaMessage;
import	javax.sound.midi.MetaEventListener;
import	javax.sound.midi.MidiMessage;
import	javax.sound.midi.ShortMessage;
import	javax.sound.midi.ControllerEventListener;
import	javax.sound.midi.MidiDevice;

import	org.tritonus.share.TDebug;
import	org.tritonus.share.ArraySet;



/** Base class for sequencers that work with an internal queue.
	To be more precise, this is the base class for sequencers that
	do not load the complete Sequence to internal data structures before start,
	but take single events from the Sequence and put them to the sequencing
	queue while running.
 */
public abstract class TPreloadingSequencer
extends TSequencer
{
	/** The default value for {@link m_nLatency}.
		This default value is set in the constructor.
	 */
	private static final int DEFAULT_LATENCY = 100;

	/**
	 */
	private int m_nLatency;

	private Thread				m_loaderThread;

	/**
	   Sets the latency to the default value.
	 */
	protected TPreloadingSequencer(MidiDevice.Info info,
			     Collection masterSyncModes,
			     Collection slaveSyncModes)
	{
		super(info, masterSyncModes,
			  slaveSyncModes);
		if (TDebug.TraceSequencer) { TDebug.out("TPreloadingSequencer.<init>(): begin"); }
		m_nLatency = DEFAULT_LATENCY;
		if (TDebug.TraceSequencer) { TDebug.out("TPreloadingSequencer.<init>(): end"); }
	}






	/** Sets the preloading intervall.
		This is the time span between preloading events to an internal
		queue and playing them. This intervall should be kept constant
		by the implementation. However, this cannot be guaranteed.
	*/
	public void setLatency(int nLatency)
	{
		// TODO: preload if latency becomes shorter
		m_nLatency = nLatency;
	}



	/** Get the preloading intervall.

	@return the preloading intervall in milliseconds, or -1 if the sequencer
	doesn't repond to changes in the <code>Sequence</code> at all.
	*/
	public int getLatency()
	{
		return m_nLatency;
	}


	// currently not called by subclasses. order has to be assured (subclass first)
	protected void openImpl()
	{
		if (TDebug.TraceSequencer) { TDebug.out("AlsaSequencer.openImpl(): begin"); }
		// m_loaderThread = new LoaderThread();
		// m_loaderThread.start();
	}



	/**	Put a message into the queue.
		This is Claus-Dieter's special method: it puts the message to
		the ALSA queue for delivery at the specified time.
		The time has to be given in ticks according to the resolution
		of the currently active Sequence. For this method to work,
		the Sequencer has to be started. The message is delivered
		the same way as messages from a Sequence, i.e. to all
		registered Transmitters. If the current queue position (as
		returned by getTickPosition()) is
		already behind the desired schedule time, the message is
		ignored.

		@param message the MidiMessage to put into the queue.

		@param lTick the desired schedule time in ticks.
	*/
	public abstract void sendMessageTick(MidiMessage message, long lTick);

}



/*** TPreloadingSequencer.java ***/
