/*
 *	LoopingMidiPlayer14.java
 *
 *	This file is part of jsresources.org
 */

/*
 * Copyright (c) 1999 - 2001 by Matthias Pfisterer
 * 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.
 *
 * 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.
 */

/*
|<---            this code is formatted to fit into 80 columns             --->|
*/

import java.io.File;
import java.io.IOException;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.Track;



/**	<titleabbrev>LoopingMidiPlayer14</titleabbrev>
	<title>Looping a MIDI file (JDK1.4 and earlier)</title>

	<formalpara><title>Purpose</title>

	<para>Loops a MIDI file using loopstart/loopend meta messages
	(JDK1.4 and earlier).</para></formalpara>

	<formalpara><title>Usage</title>
	<para>
	<cmdsynopsis>
	<command>java LoopingMidiPlayer14</command>
	<arg choice="plain"><replaceable>midifile</replaceable></arg>
	</cmdsynopsis>
	</para></formalpara>

	<formalpara><title>Parameters</title>
	<variablelist>
	<varlistentry>
	<term><option><replaceable>midifile</replaceable></option></term>
	<listitem><para>the name of the MIDI file that should be
	played</para></listitem>
	</varlistentry>
	</variablelist>
	</formalpara>

	<formalpara><title>Bugs, limitations</title>

	<para>This program always uses the default Sequencer and the default
	Synthesizer to play on. For using non-default sequencers,
	synthesizers or to play on an external MIDI port, see
	<olink targetdoc="MidiPlayer"
	targetptr="MidiPlayer">MidiPlayer</olink>.</para>

	<para>This program does not work with the JDK 1.5. For looping
	using the JDK 1.5, see <olink targetdoc="LoopingMidiPlayer15"
	targetptr="LoopingMidiPlayer15">LoopingMidiPlayer15</olink>.</para>

	</formalpara>

	<formalpara><title>Source code</title>
	<para>
	<ulink url="LoopingMidiPlayer14.java.html">LoopingMidiPlayer14.java</ulink>
	</para>
	</formalpara>

*/
public class LoopingMidiPlayer14
{
	public static void main(String[] args)
		throws MidiUnavailableException, InvalidMidiDataException, IOException
	{
		final Sequencer sequencer;

		/* We check if there is no command-line argument at all or the
		 * first one is '-h'.  If so, we display the usage message and
		 * exit.
		 */
		if (args.length == 0 || args[0].equals("-h"))
		{
			printUsageAndExit();
		}

		String	strFilename = args[0];
		File	midiFile = new File(strFilename);

		/* We read in the MIDI file to a Sequence object.  This object
		 * is set at the Sequencer later.
		 */
		Sequence sequence = MidiSystem.getSequence(midiFile);

		/* Here, we set the loop points to loop over the whole
		 * sequence. In order to do so, we insert loopstart and loopend
		 * meta messages into the sequence.
		 */

		Track track = sequence.getTracks()[0];
		final int MARKER = 6;
		long loopStartTick = 0;
		long loopEndTick = sequence.getTickLength();
		addMetaEvent(track, MARKER, "loopstart".getBytes(), loopStartTick);
		addMetaEvent(track, MARKER, "loopend".getBytes(), loopEndTick);

		/* Now, we need a Sequencer to play the sequence.  Here, we
		 * simply request the default sequencer with an implicitly
		 * connected synthesizer
		 */
		sequencer = MidiSystem.getSequencer();

		/* The Sequencer is still a dead object.  We have to open() it
		 * to become live.  This is necessary to allocate some
		 * ressources in the native part.
		 */
		sequencer.open();

		/* Next step is to tell the Sequencer which Sequence it has to
		 * play. In this case, we set it as the Sequence object
		 * created above.
		 */
		sequencer.setSequence(sequence);

		/* To free system resources, it is recommended to close the
		 * synthesizer and sequencer properly.
		 *
		 * To accomplish this, we register a Listener to the
		 * Sequencer. It is called when there are "meta" events. Meta
		 * event 47 is end of track.
		 *
		 * Thanks to Espen Riskedal for finding this trick.
		 */
		sequencer.addMetaEventListener(new MetaEventListener()
			{
				public void meta(MetaMessage event)
				{
					if (event.getType() == 47)
					{
						sequencer.close();
						System.exit(0);
					}
				}
			});

		/* Now, we can start over.
		 */
		sequencer.start();
	}



	private static void addMetaEvent(Track track, int type,
									 byte[] data, long tick)
	{
		MetaMessage message = new MetaMessage();
		try
		{
			message.setMessage(type, data, data.length);
			MidiEvent event = new MidiEvent( message, tick );
			track.add(event);
		}
		catch (InvalidMidiDataException e)
		{
			e.printStackTrace();
		}
	}


	private static void printUsageAndExit()
	{
		out("LoopingMidiPlayer14: usage:");
		out("\tjava LoopingMidiPlayer14 <midifile>");
		System.exit(1);
	}



	private static void out(String strMessage)
	{
		System.out.println(strMessage);
	}
}



/*** LoopingMidiPlayer14.java ***/