/*
 *	AlsaSeq.java
 *
 *	This file is part of Tritonus: http://www.tritonus.org/
 */

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

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

package org.tritonus.lowlevel.alsa;

import java.lang.UnsupportedOperationException;
import java.util.Iterator;

import org.tritonus.share.TDebug;



public class AlsaSeq
{
/*                                   	*/
/* definition of sequencer event types 	*/
/*                                   	*/

// TODO: recheck numbers; enable automatic check

/* 0-4: system messages
 * event data type = snd_seq_result_t
 */
	public static final int	SND_SEQ_EVENT_SYSTEM =		0;
	public static final int	SND_SEQ_EVENT_RESULT =		1;
/* 2-4: reserved */

/* 5-9: note messages (channel specific)
 * event data type = snd_seq_ev_note
 */
	public static final int	SND_SEQ_EVENT_NOTE =		5;
	public static final int	SND_SEQ_EVENT_NOTEON =		6;
	public static final int	SND_SEQ_EVENT_NOTEOFF =		7;
	public static final int	SND_SEQ_EVENT_KEYPRESS =	8;
/* 9-10: reserved */

/* 10-19: control messages (channel specific)
 * event data type = snd_seq_ev_ctrl
 */
	public static final int	SND_SEQ_EVENT_CONTROLLER =	10;
	public static final int	SND_SEQ_EVENT_PGMCHANGE =	11;
	public static final int	SND_SEQ_EVENT_CHANPRESS =	12;
	public static final int	SND_SEQ_EVENT_PITCHBEND =	13;	/* from -8192 to 8191 */
	public static final int	SND_SEQ_EVENT_CONTROL14 =	14;	/* 14 bit controller value */
	public static final int	SND_SEQ_EVENT_NONREGPARAM =	15;	/* 14 bit NRPN */
	public static final int	SND_SEQ_EVENT_REGPARAM =	16;	/* 14 bit RPN */
/* 18-19: reserved */

/* 20-29: synchronisation messages
 * event data type = snd_seq_ev_ctrl
 */
	public static final int	SND_SEQ_EVENT_SONGPOS =		20;	/* Song Position Pointer with LSB and MSB values */
	public static final int	SND_SEQ_EVENT_SONGSEL =		21;	/* Song Select with song ID number */
	public static final int	SND_SEQ_EVENT_QFRAME =		22;	/* midi time code quarter frame */
	public static final int	SND_SEQ_EVENT_TIMESIGN =	23;	/* SMF Time Signature event */
	public static final int	SND_SEQ_EVENT_KEYSIGN =		24;	/* SMF Key Signature event */
/* 25-29: reserved */
	        
/* 30-39: timer messages
 * event data type = snd_seq_ev_queue_control_t
 */
	public static final int	SND_SEQ_EVENT_START =		30;	/* midi Real Time Start message */
	public static final int	SND_SEQ_EVENT_CONTINUE =	31;	/* midi Real Time Continue message */
	public static final int	SND_SEQ_EVENT_STOP =		32;	/* midi Real Time Stop message */	
	public static final int	SND_SEQ_EVENT_SETPOS_TICK =	33;	/* set tick queue position */
	public static final int	SND_SEQ_EVENT_SETPOS_TIME =	34;	/* set realtime queue position */
	public static final int	SND_SEQ_EVENT_TEMPO =		35;	/* (SMF) Tempo event */
	public static final int	SND_SEQ_EVENT_CLOCK =		36;	/* midi Real Time Clock message */
	public static final int	SND_SEQ_EVENT_TICK =		37;	/* midi Real Time Tick message */
/* 38-39: sync */
	public static final int	SND_SEQ_EVENT_SYNC =		38;
	public static final int	SND_SEQ_EVENT_SYNC_POS =	39;
/* 40-49: others
 * event data type = none
 */
	public static final int	SND_SEQ_EVENT_TUNE_REQUEST =	40;	/* tune request */
	public static final int	SND_SEQ_EVENT_RESET =		41;	/* reset to power-on state */
	public static final int	SND_SEQ_EVENT_SENSING =		42;	/* "active sensing" event */
/* 43-49: reserved */

/* 50-59: echo back, kernel private messages
 * event data type = any type
 */
	public static final int	SND_SEQ_EVENT_ECHO =		50;	/* echo event */
	public static final int	SND_SEQ_EVENT_OSS =		51;	/* OSS raw event */
/* 52-59: reserved */

/* 60-69: system status messages (broadcast for subscribers)
 * event data type = snd_seq_addr_t
 */
	public static final int	SND_SEQ_EVENT_CLIENT_START =	60;	/* new client has connected */
	public static final int	SND_SEQ_EVENT_CLIENT_EXIT =	61;	/* client has left the system */
	public static final int	SND_SEQ_EVENT_CLIENT_CHANGE =	62;	/* client status/info has changed */
	public static final int	SND_SEQ_EVENT_PORT_START =	63;	/* new port was created */
	public static final int	SND_SEQ_EVENT_PORT_EXIT =	64;	/* port was deleted from system */
	public static final int	SND_SEQ_EVENT_PORT_CHANGE =	65;	/* port status/info has changed */
	public static final int	SND_SEQ_EVENT_PORT_SUBSCRIBED =	66;	/* read port is subscribed */
	public static final int	SND_SEQ_EVENT_PORT_UNSUBSCRIBED =	67;	/* read port is released */

/* 70-79: synthesizer events
 * event data type = snd_seq_eve_sample_control_t
 */
	public static final int	SND_SEQ_EVENT_SAMPLE =		70;	/* sample select */
	public static final int	SND_SEQ_EVENT_SAMPLE_CLUSTER =	71;	/* sample cluster select */
	public static final int	SND_SEQ_EVENT_SAMPLE_START =	72;	/* voice start */
	public static final int	SND_SEQ_EVENT_SAMPLE_STOP =	73;	/* voice stop */
	public static final int	SND_SEQ_EVENT_SAMPLE_FREQ =	74;	/* playback frequency */
	public static final int	SND_SEQ_EVENT_SAMPLE_VOLUME =	75;	/* volume and balance */
	public static final int	SND_SEQ_EVENT_SAMPLE_LOOP =	76;	/* sample loop */
	public static final int	SND_SEQ_EVENT_SAMPLE_POSITION =	77;	/* sample position */
	public static final int	SND_SEQ_EVENT_SAMPLE_PRIVATE1 =	78;	/* private (hardware dependent) event */

/* 80-89: reserved */

/* 90-99: user-defined events with fixed length
 * event data type = any
 */
	public static final int	SND_SEQ_EVENT_USR0 =		90;
	public static final int	SND_SEQ_EVENT_USR1 =		91;
	public static final int	SND_SEQ_EVENT_USR2 =		92;
	public static final int	SND_SEQ_EVENT_USR3 =		93;
	public static final int	SND_SEQ_EVENT_USR4 =		94;
	public static final int	SND_SEQ_EVENT_USR5 =		95;
	public static final int	SND_SEQ_EVENT_USR6 =		96;
	public static final int	SND_SEQ_EVENT_USR7 =		97;
	public static final int	SND_SEQ_EVENT_USR8 =		98;
	public static final int	SND_SEQ_EVENT_USR9 =		99;

/* 100-129: instrument layer
 * variable length data can be passed directly to the driver
 */
	public static final int	SND_SEQ_EVENT_INSTR_BEGIN =	100;	/* begin of instrument management */
	public static final int	SND_SEQ_EVENT_INSTR_END =	101;	/* end of instrument management */
	public static final int	SND_SEQ_EVENT_INSTR_INFO =	102;	/* instrument interface info */
	public static final int	SND_SEQ_EVENT_INSTR_INFO_RESULT = 103;	/* result */
	public static final int	SND_SEQ_EVENT_INSTR_FINFO =	104;	/* get format info */
	public static final int	SND_SEQ_EVENT_INSTR_FINFO_RESULT = 105;	/* get format info */
	public static final int	SND_SEQ_EVENT_INSTR_RESET =	106;	/* reset instrument memory */
	public static final int	SND_SEQ_EVENT_INSTR_STATUS =	107;	/* instrument interface status */
	public static final int	SND_SEQ_EVENT_INSTR_STATUS_RESULT = 108;	/* result */
	public static final int	SND_SEQ_EVENT_INSTR_PUT =	109;	/* put instrument to port */
	public static final int	SND_SEQ_EVENT_INSTR_GET =	110;	/* get instrument from port */
	public static final int	SND_SEQ_EVENT_INSTR_GET_RESULT =	111;	/* result */
	public static final int	SND_SEQ_EVENT_INSTR_FREE =	112;	/* free instrument(s) */
	public static final int	SND_SEQ_EVENT_INSTR_LIST =	113;	/* instrument list */
	public static final int	SND_SEQ_EVENT_INSTR_LIST_RESULT = 114;	/* result */
	public static final int	SND_SEQ_EVENT_INSTR_CLUSTER =	115;	/* cluster parameters */
	public static final int	SND_SEQ_EVENT_INSTR_CLUSTER_GET =	116;	/* get cluster parameters */
	public static final int	SND_SEQ_EVENT_INSTR_CLUSTER_RESULT = 117;	/* result */
	public static final int	SND_SEQ_EVENT_INSTR_CHANGE =	118;	/* instrument change */
/* 119-129: reserved */

/* 130-139: variable length events
 * event data type = snd_seq_ev_ext
 * (SND_SEQ_EVENT_LENGTH_VARIABLE must be set)
 */
	public static final int	SND_SEQ_EVENT_SYSEX =		130;	/* system exclusive data (variable length) */
	public static final int	SND_SEQ_EVENT_BOUNCE =		131;	/* error event */
/* 132-134: reserved */
	public static final int	SND_SEQ_EVENT_USR_VAR0 =	135;
	public static final int	SND_SEQ_EVENT_USR_VAR1 =	136;
	public static final int	SND_SEQ_EVENT_USR_VAR2 =	137;
	public static final int	SND_SEQ_EVENT_USR_VAR3 =	138;
	public static final int	SND_SEQ_EVENT_USR_VAR4 =	139;


/* 255: special event */
	public static final int	SND_SEQ_EVENT_NONE =		255;


	public static final int	SND_SEQ_ADDRESS_UNKNOWN	 =	253;	/* unknown source */
	public static final int	SND_SEQ_ADDRESS_SUBSCRIBERS =	254;	/* send event to all subscribed ports */
	public static final int	SND_SEQ_ADDRESS_BROADCAST =	255;	/* send event to all queues/clients/ports/channels */
	public static final int	SND_SEQ_QUEUE_DIRECT =		253;	/* direct dispatch */

	/* event mode flag - NOTE: only 8 bits available! */
	public static final int	SND_SEQ_TIME_STAMP_TICK	 =	(0<<0); /* timestamp in clock ticks */
	public static final int	SND_SEQ_TIME_STAMP_REAL	 =	(1<<0); /* timestamp in real time */
	public static final int	SND_SEQ_TIME_STAMP_MASK	 =	(1<<0);

	public static final int	SND_SEQ_TIME_MODE_ABS =		(0<<1);	/* absolute timestamp */
	public static final int	SND_SEQ_TIME_MODE_REL =		(1<<1);	/* relative to current time */
	public static final int	SND_SEQ_TIME_MODE_MASK =	(1<<1);

	public static final int	SND_SEQ_EVENT_LENGTH_FIXED =	(0<<2);	/* fixed event size */
	public static final int	SND_SEQ_EVENT_LENGTH_VARIABLE =	(1<<2);	/* variable event size */
	public static final int	SND_SEQ_EVENT_LENGTH_VARUSR =	(2<<2);	/* variable event size - user memory space */
	public static final int	SND_SEQ_EVENT_LENGTH_VARIPC =	(3<<2);	/* variable event size - IPC */
	public static final int	SND_SEQ_EVENT_LENGTH_MASK =	(3<<2);

	public static final int	SND_SEQ_PRIORITY_NORMAL	 =	(0<<4);	/* normal priority */
	public static final int	SND_SEQ_PRIORITY_HIGH =		(1<<4);	/* event should be processed before others */
	public static final int	SND_SEQ_PRIORITY_MASK =		(1<<4);





	/* known client numbers */
	public static final int	SND_SEQ_CLIENT_SYSTEM =		0;
	public static final int	SND_SEQ_CLIENT_DUMMY =		62;	/* dummy ports */
	public static final int	SND_SEQ_CLIENT_OSS =		63;	/* oss sequencer emulator */

	/* event filter flags */
	public static final int	SND_SEQ_FILTER_BROADCAST =	(1<<0);	/* accept broadcast messages */
	public static final int	SND_SEQ_FILTER_MULTICAST =	(1<<1);	/* accept multicast messages */
	public static final int	SND_SEQ_FILTER_BOUNCE =		(1<<2);	/* accept bounce event in error */
	public static final long	SND_SEQ_FILTER_USE_EVENT =	(1L<<31);	/* use event filter */


/* Flush mode flags */
	public static final int	SND_SEQ_REMOVE_INPUT =		(1<<0);	/* Restrict by destination q:client:port */
	public static final int	SND_SEQ_REMOVE_OUTPUT =		(1<<1);	/* Restrict by channel */
	public static final int	SND_SEQ_REMOVE_DEST =		(1<<2);	/* Restrict by destination q:client:port */
	public static final int	SND_SEQ_REMOVE_DEST_CHANNEL =	(1<<3);	/* Restrict by channel */
	public static final int	SND_SEQ_REMOVE_TIME_BEFORE =	(1<<4);	/* Restrict to before time */
	public static final int	SND_SEQ_REMOVE_TIME_AFTER =	(1<<5);	/* Restrict to time or after */
	public static final int	SND_SEQ_REMOVE_TIME_TICK =	(1<<6);	/* Restrict to time or after */
	public static final int	SND_SEQ_REMOVE_EVENT_TYPE =	(1<<7);	/* Restrict to event type */
	public static final int	SND_SEQ_REMOVE_IGNORE_OFF = 	(1<<8);	/* Do not flush off events */
	public static final int	SND_SEQ_REMOVE_TAG_MATCH = 	(1<<9);	/* Restrict to events with given tag */

	/* known port numbers */
	public static final int SND_SEQ_PORT_SYSTEM_TIMER =	0;
	public static final int SND_SEQ_PORT_SYSTEM_ANNOUNCE =	1;

	/* port capabilities (32 bits) */
	public static final int	SND_SEQ_PORT_CAP_READ =		(1<<0);	/* readable from this port */
	public static final int	SND_SEQ_PORT_CAP_WRITE =	(1<<1);	/* writable to this port */

	public static final int	SND_SEQ_PORT_CAP_SYNC_READ =	(1<<2);
	public static final int	SND_SEQ_PORT_CAP_SYNC_WRITE =	(1<<3);

	public static final int	SND_SEQ_PORT_CAP_DUPLEX =	(1<<4);

	public static final int	SND_SEQ_PORT_CAP_SUBS_READ =	(1<<5);	/* allow read subscription */
	public static final int	SND_SEQ_PORT_CAP_SUBS_WRITE =	(1<<6);	/* allow write subscription */
	public static final int	SND_SEQ_PORT_CAP_NO_EXPORT =	(1<<7);	/* routing not allowed */

	/* port type */
	public static final int	SND_SEQ_PORT_TYPE_SPECIFIC =	(1<<0);	/* hardware specific */
	public static final int	SND_SEQ_PORT_TYPE_MIDI_GENERIC =(1<<1);	/* generic MIDI device */
	public static final int	SND_SEQ_PORT_TYPE_MIDI_GM =	(1<<2);	/* General MIDI compatible device */
	public static final int	SND_SEQ_PORT_TYPE_MIDI_GS =	(1<<3);	/* GS compatible device */
	public static final int	SND_SEQ_PORT_TYPE_MIDI_XG =	(1<<4);	/* XG compatible device */
	public static final int	SND_SEQ_PORT_TYPE_MIDI_MT32 =	(1<<5);	/* MT-32 compatible device */

/* other standards...*/
	public static final int	SND_SEQ_PORT_TYPE_SYNTH =	(1<<10);	/* Synth device */
	public static final int	SND_SEQ_PORT_TYPE_DIRECT_SAMPLE =(1<<11);	/* Sampling device (support sample download) */
	public static final int	SND_SEQ_PORT_TYPE_SAMPLE =	(1<<12);	/* Sampling device (sample can be downloaded at any time) */
/*...*/
	public static final int	SND_SEQ_PORT_TYPE_APPLICATION =	(1<<20);	/* application (sequencer/editor) */

/* standard group names */
	public static final String SND_SEQ_GROUP_SYSTEM =	"system";
	public static final String SND_SEQ_GROUP_DEVICE =	"device";
	public static final String SND_SEQ_GROUP_APPLICATION =	"application";

/* misc. conditioning flags */
	public static final int SND_SEQ_PORT_FLG_GIVEN_PORT =	(1<<0);

/* queue flags */
	public static final int SND_SEQ_QUEUE_FLG_SYNC =	(1<<0);	/* sync enabled */

/* queue status flag */
	public static final int SND_SEQ_QUEUE_FLG_SYNC_LOST =	1;

/* synchronization types */
/* mode */
	public static final int SND_SEQ_SYNC_TICK =		0x80;
	public static final int SND_SEQ_SYNC_TIME =		0x40;
	public static final int SND_SEQ_SYNC_MODE =		0xc0;		/* mask */
/* private format */
	public static final int SND_SEQ_SYNC_FMT_PRIVATE_CLOCK = (SND_SEQ_SYNC_TICK|0);
	public static final int SND_SEQ_SYNC_FMT_PRIVATE_TIME =	(SND_SEQ_SYNC_TIME|0);
/* pre-defined format */
	public static final int SND_SEQ_SYNC_FMT_MIDI_CLOCK =	(SND_SEQ_SYNC_TICK|1);
	public static final int SND_SEQ_SYNC_FMT_MTC =		(SND_SEQ_SYNC_TIME|1);
	public static final int SND_SEQ_SYNC_FMT_DTL =		(SND_SEQ_SYNC_TIME|2);
	public static final int SND_SEQ_SYNC_FMT_SMPTE =	(SND_SEQ_SYNC_TIME|3);
	public static final int SND_SEQ_SYNC_FMT_MIDI_TICK =	(SND_SEQ_SYNC_TIME|4);
/* time format */
	public static final int SND_SEQ_SYNC_FPS_24 =		0;
	public static final int SND_SEQ_SYNC_FPS_25 =		1;
	public static final int SND_SEQ_SYNC_FPS_30_DP =	2;
	public static final int SND_SEQ_SYNC_FPS_30_NDP =	3;

/* sequencer timer sources */
	public static final int SND_SEQ_TIMER_ALSA =		0;	/* ALSA timer */
	public static final int SND_SEQ_TIMER_MIDI_CLOCK =	1;	/* Midi Clock (CLOCK event) */
	public static final int SND_SEQ_TIMER_MIDI_TICK =	2;	/* Midi Timer Tick (TICK event) */

/* type of query subscription */
	public static final int SND_SEQ_QUERY_SUBS_READ =	0;
	public static final int SND_SEQ_QUERY_SUBS_WRITE =	1;

/* instrument types */
	public static final int SND_SEQ_INSTR_ATYPE_DATA =	0;	/* instrument data */
	public static final int SND_SEQ_INSTR_ATYPE_ALIAS =	1;	/* instrument alias */

/* instrument ASCII identifiers */
	public static final String SND_SEQ_INSTR_ID_DLS1 =	"DLS1";
	public static final String SND_SEQ_INSTR_ID_DLS2 =	"DLS2";
	public static final String SND_SEQ_INSTR_ID_SIMPLE =	"Simple Wave";
	public static final String SND_SEQ_INSTR_ID_SOUNDFONT =	"SoundFont";
	public static final String SND_SEQ_INSTR_ID_GUS_PATCH =	"GUS Patch";
	public static final String SND_SEQ_INSTR_ID_INTERWAVE =	"InterWave FFFF";
	public static final String SND_SEQ_INSTR_ID_OPL2_3 =	"OPL2/3 FM";
	public static final String SND_SEQ_INSTR_ID_OPL4 =	"OPL4";

/* instrument types */
	public static final int SND_SEQ_INSTR_TYPE0_DLS1 =	(1<<0);	/* MIDI DLS v1 */
	public static final int SND_SEQ_INSTR_TYPE0_DLS2 =	(1<<1);	/* MIDI DLS v2 */
	public static final int SND_SEQ_INSTR_TYPE1_SIMPLE =	(1<<0);	/* Simple Wave */
	public static final int SND_SEQ_INSTR_TYPE1_SOUNDFONT =	(1<<1);	/* EMU SoundFont */
	public static final int SND_SEQ_INSTR_TYPE1_GUS_PATCH =	(1<<2);	/* Gravis UltraSound Patch */
	public static final int SND_SEQ_INSTR_TYPE1_INTERWAVE =	(1<<3);	/* InterWave FFFF */
	public static final int SND_SEQ_INSTR_TYPE2_OPL2_3 =	(1<<0);	/* Yamaha OPL2/3 FM */
	public static final int SND_SEQ_INSTR_TYPE2_OPL4 =	(1<<1);	/* Yamaha OPL4 */

/* put commands */
	public static final int SND_SEQ_INSTR_PUT_CMD_CREATE =	0;
	public static final int SND_SEQ_INSTR_PUT_CMD_REPLACE =	1;
	public static final int SND_SEQ_INSTR_PUT_CMD_MODIFY =	2;
	public static final int SND_SEQ_INSTR_PUT_CMD_ADD =	3;
	public static final int SND_SEQ_INSTR_PUT_CMD_REMOVE =	4;

/* get commands */
	public static final int SND_SEQ_INSTR_GET_CMD_FULL =	0;
	public static final int SND_SEQ_INSTR_GET_CMD_PARTIAL =	1;

/* query flags */
	public static final int SND_SEQ_INSTR_QUERY_FOLLOW_ALIAS = (1<<0);

/* free commands */
	public static final int SND_SEQ_INSTR_FREE_CMD_ALL =		0;
	public static final int SND_SEQ_INSTR_FREE_CMD_PRIVATE =	1;
	public static final int SND_SEQ_INSTR_FREE_CMD_CLUSTER =	2;
	public static final int SND_SEQ_INSTR_FREE_CMD_SINGLE =		3;



	static
	{
		Alsa.loadNativeLibrary();
		if (TDebug.TraceAlsaSeqNative)
		{
			setTrace(true);
		}
	}



	/*
	 *	This holds a pointer for the native code - do not touch!
	 */
	@SuppressWarnings("unused")
	private long		m_lNativeHandle;



	public AlsaSeq()
	{
		super();
		if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.<init>(): begin"); }
		int	nSuccess = open();
		if (nSuccess < 0)
		{
			throw new RuntimeException("open failed");
		}
		if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.<init>(): end"); }
	}



	public AlsaSeq(String strClientName)
	{
		this();
		if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.<init>(String): begin"); }
		setClientName(strClientName);
		if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.<init>(String): end"); }
	}



	/**	Opens the sequencer.
	 *	This method is intended to be called by the constructor.
	 *	Calls snd_seq_open().
	 */
	private native int open();


	/**	Closes the sequencer.
	 *	Calls snd_seq_close().
	 */
	public native void close();

	public native String getName();

	public native int getType();
	
	public native int setNonblock(boolean bNonblock);
	
	public native int getClientId();

	public native int getOutputBufferSize();

	public native int getInputBufferSize();

	public native int setOutputBufferSize(int nSize);

	public native int setInputBufferSize(int nSize);




	public native int getSystemInfo(AlsaSeqSystemInfo systemInfo);



	public int getClientInfo(AlsaSeqClientInfo clientInfo)
	{
		return getClientInfo(-1, clientInfo);
	}

	public native int getClientInfo(int nClient, AlsaSeqClientInfo clientInfo);

	public native int setClientInfo(AlsaSeqClientInfo clientInfo);



	/**	Gets information about the next client.
	 *	Calls snd_seq_query_next_client().
	 *	and puts the returned values
	 *	into the passed arrays.
	 *
	 *	nClient has to be -1 to start, or a client id returned by
	 *	a previous call to this method.
	 *
	 *	anValues[0]	client id
	 *
	 *	Returns 0 if successful.
	 */
	public native int getNextClient(int nClient, int[] anValues);



	public void setClientName(String strName)
	{
		if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.setClientName(): begin"); }
		AlsaSeqClientInfo	clientInfo = new AlsaSeqClientInfo();
		// TODO: error check
		getClientInfo(clientInfo);
		clientInfo.setName(strName);
		setClientInfo(clientInfo);
		if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.setClientName(): end"); }
	}


	public int getPortInfo(int nPort, AlsaSeqPortInfo portInfo)
	{
		return getPortInfo(-1, nPort, portInfo);
	}

	public native int getPortInfo(int nClient, int nPort, AlsaSeqPortInfo portInfo);



	/**	Gets the next port.
	 *	Calls snd_seq_query_next_port().
	 *	and put the returned values
	 *	into the passed arrays.
	 *
	 *	nClient has to be a valid client.
	 *	nPort has to be -1 to start, or a port returned by
	 *	a previous call to this method.
	 *
	 *	anValues[0]	client
	 *	anValues[1]	port
	 *
	 *	Returns 0 if successful.
	 */
	public native int getNextPort(int nClient, int nPort, int[] anValues);



	// TODO: use structure
	public native int createPort(String strName, int nCapabilities, int nGroupPermissions, int nType, int nMidiChannels, int nMidiVoices, int nSynthVoices);

	/**	Allocates (reserves) a sequencing queue.
		Calls snd_seq_alloc_queue().
		@return the queue number (>= 0), if successful. A negative
		value otherwise.
	*/
	public native int allocQueue();


	/**	Frees a sequencing queue.
		Calls snd_seq_free_queue().

		@param nQueue a queue number that has previously been
		allocated with allocQueue().

		@return 0 if successful. A negative
		value otherwise.
	*/
	public native int freeQueue(int nQueue);



	/**	Get the queue usage flag.
		Calls snd_seq_get_queue_usage().

		@param nQueue a queue number that has previously been
		allocated with allocQueue().

		@return true if the client is allowed to access the queue.
		false otherwise.
	*/
	public native boolean getQueueUsage(int nQueue);



	/**	Set the queue usage flag.
		Calls snd_seq_set_queue_usage().

		@param nQueue a queue number that has previously been
		allocated with allocQueue().

		@param bUsageAllowed true to allow the client access to this
		queue. false to deny it.

		@return 0 if successful. A negative
		value otherwise.
	*/
	public native int setQueueUsage(int nQueue, boolean bUsageAllowed);



	/**	Get the queue information.
		This method fills a QueueInfo instance with information
		from the given queue. Internally, snd_seq_get_queue_info()
		is called.

		@return returns 0 on success, otherwise a negative value.
	*/
	public native int getQueueInfo(int nQueue, AlsaSeqQueueInfo queueInfo);



	/**	Set the queue information.
		This method sets the information for the given queue from
		the QueueInfo instance. Internally, snd_seq_set_queue_info()
		is called.

		@return returns 0 on success, otherwise a negative value.
	*/
	public native int setQueueInfo(int nQueue, AlsaSeqQueueInfo queueInfo);


	/**	Get the queue status.
		This method fills a QueueStatus instance with information
		from the given queue. Internally, snd_seq_get_queue_status()
		is called.

		@return returns 0 on success, otherwise a negative value.
	*/
	public native int getQueueStatus(int nQueue, AlsaSeqQueueStatus queueStatus);


	/**	Get the queue tempo.
		This method fills a QueueTempo instance with information
		from the given queue. Internally, snd_seq_get_queue_tempo()
		is called.

		@return returns 0 on success, otherwise a negative value.
	*/
	public native int getQueueTempo(int nQueue, AlsaSeqQueueTempo queueTempo);


	/**	Set the queue tempo.
		This method sets the information for the given queue from
		the QueueTempo instance. Internally, snd_seq_set_queue_tempo()
		is called.

		@return returns 0 on success, otherwise a negative value.
	*/
	public native int setQueueTempo(int nQueue, AlsaSeqQueueTempo queueTempo);


	/**	Get the queue timer.
		This method fills a QueueTimer instance with information
		from the given queue. Internally, snd_seq_get_queue_timer()
		is called.

		@return returns 0 on success, otherwise a negative value.
	*/
	public native int getQueueTimer(int nQueue, AlsaSeqQueueTimer queueTimer);


	/**	Set the queue timer.
		This method sets the timer for the given queue from
		the QueueTimer instance. Internally, snd_seq_set_queue_timer()
		is called.

		@return returns 0 on success, otherwise a negative value.
	*/
	public native int setQueueTimer(int nQueue, AlsaSeqQueueTimer queueTimer);


	public native int getPortSubscription(AlsaSeqPortSubscribe portSubscribe);
	public native int subscribePort(AlsaSeqPortSubscribe portSubscribe);
	public native int unsubscribePort(AlsaSeqPortSubscribe portSubscribe);



	private static native void setTrace(boolean bTrace);




	public Iterator getClientInfos()
	{
		return new ClientInfoIterator();
	}



	public Iterator getPortInfos(int nClient)
	{
		return new PortInfoIterator(nClient);
	}



	////////////////////////////////////////////////////////////////
	//
	//	Events
	//
	////////////////////////////////////////////////////////////////


	public native int eventOutput(AlsaSeqEvent event);
	public native int eventOutputBuffer(AlsaSeqEvent event);
	public native int eventOutputDirect(AlsaSeqEvent event);
	public native int eventInput(AlsaSeqEvent event);
	public native int eventInputPending(int nFetchSequencer);
	public native int drainOutput();
	public native int eventOutputPending();
	public native int extractOutput(AlsaSeqEvent event);
	public native int dropOutput();
	public native int dropOutputBuffer();
	public native int dropInput();
	public native int dropInputBuffer();



	///////////////////////////////////////////////////////////


// 	/**	Event for the sequencer.
// 	 *	This class encapsulates an instance of
// 	 *	snd_seq_event_t.
// 	 */
// 	public static class Event
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_event_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public Event()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.Event.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of event failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.Event.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		/** Allocates memory for a snd_seq_event_t.

// 		The native part of this method uses calloc() to
// 		allocate the memory (so the allocated memory is
// 		zero'ed).  The memory reference is stored in {@link
// 		#m_lNativeHandle m_lNativeHandle}.  Memory allocated
// 		with this call should be freed by calling {@link
// 		#free() free()}.

// 		 */
// 		private native int malloc();

// 		/** Frees memory for a snd_seq_event_t.
// 		 */
// 		public native void free();

// 		// TODO: implement natively
// 		public native int getLength();

// 		public native int getType();
// 		public native int getFlags();
// 		public native int getTag();
// 		public native int getQueue();
// 		public native long getTimestamp();
// 		public native int getSourceClient();
// 		public native int getSourcePort();
// 		public native int getDestClient();
// 		public native int getDestPort();



// 		/*	Retrieves the parameters of a note event.
// 		 *	This method is suitable for the following event types:
// 		 *	SND_SEQ_EVENT_NOTE
// 		 *	SND_SEQ_EVENT_NOTEON
// 		 *	SND_SEQ_EVENT_NOTEOFF
// 		 *	SND_SEQ_EVENT_KEYPRESS
// 		 *
// 		 *	After return, the array will contain:
// 		 *	anValues[0]	channel
// 		 *	anValues[1]	note
// 		 *	anValues[2]	velocity
// 		 *	anValues[3]	off_velocity
// 		 *	anValues[4]	duration
// 		 */
// 		public native void getNote(int[] anValues);



// 		/*	Retrieves the parameters of a control event.
// 		 *	This method is suitable for the following event types:
// 		 *	SND_SEQ_EVENT_CONTROLLER
// 		 *	SND_SEQ_EVENT_PGMCHANGE
// 		 *	SND_SEQ_EVENT_CHANPRESS
// 		 *	SND_SEQ_EVENT_PITCHBEND
// 		 *	SND_SEQ_EVENT_CONTROL14
// 		 *	SND_SEQ_EVENT_NONREGPARAM
// 		 *	SND_SEQ_EVENT_REGPARAM
// 		 *	SND_SEQ_EVENT_SONGPOS
// 		 *	SND_SEQ_EVENT_SONGSEL
// 		 *	SND_SEQ_EVENT_QFRAME
// 		 *	SND_SEQ_EVENT_TIMESIGN
// 		 *	SND_SEQ_EVENT_KEYSIGN
// 		 *
// 		 *	After return, the array will contain:
// 		 *	anValues[0]	channel
// 		 *	anValues[1]	param
// 		 *	anValues[2]	value
// 		 */
// 		public native void getControl(int[] anValues);



// 		/*	Retrieves the parameters of a queue control event.
// 		 *	This method is suitable for the following event types:
// 		 *	SND_SEQ_EVENT_START
// 		 *	SND_SEQ_EVENT_CONTINUE
// 		 *	SND_SEQ_EVENT_STOP
// 		 *	SND_SEQ_EVENT_SETPOS_TICK
// 		 *	SND_SEQ_EVENT_SETPOS_TIME
// 		 *	SND_SEQ_EVENT_TEMPO
// 		 *	SND_SEQ_EVENT_CLOCK
// 		 *	SND_SEQ_EVENT_TICK
// 		 *	SND_SEQ_EVENT_SYNC
// 		 *	SND_SEQ_EVENT_SYNC_POS
// 		 *
// 		 *	After return, the array will contain:
// 		 *	anValues[0]	queue
// 		 *	anValues[1]	value
// 		 *	alValues[0]	time
// 		 */
// 		public native void getQueueControl(int[] anValues, long[] alValues);



// 		/*	Retrieves the parameters of a variable-length event.
// 		 *	This method is suitable for the following event types:
// 		 *	SND_SEQ_EVENT_SYSEX
// 		 *	SND_SEQ_EVENT_BOUNCE
// 		 *	SND_SEQ_EVENT_USR_VAR0
// 		 *	SND_SEQ_EVENT_USR_VAR1
// 		 *	SND_SEQ_EVENT_USR_VAR2
// 		 *	SND_SEQ_EVENT_USR_VAR3
// 		 *	SND_SEQ_EVENT_USR_VAR4
// 		 *
// 		 */
// 		public native byte[] getVar();


// 		public native void setCommon(int nType, int nFlags, int nTag, int nQueue, long lTimestamp, int nSourceClient, int nSourcePort, int nDestClient, int nDestPort);

// 		public native void setTimestamp(long lTimestamp);

// 		public native void setNote(int nChannel, int nKey, int nVelocity, int nOffVelocity, int nDuration);
// 		public native void setControl(int nChannel, int nParam, int nValue);
// 		public native void setQueueControl(int nControlQueue, int nControlValue, long lControlTime);
// 		public native void setVar(byte[] abData, int nOffset, int nLength);
// 	}



// 	/**	General information about the sequencer.
// 	 *	This class encapsulates the information of
// 	 *	snd_seq_system_info_t.
// 	 */
// 	public static class SystemInfo
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_system_info_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public SystemInfo()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.SystemInfo.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of system_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.SystemInfo.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();



// 		public native int getQueues();



// 		public native int getClients();



// 		public native int getPorts();



// 		public native int getChannels();



// 		public native int getCurrentClients();



// 		public native int getCurrentQueues();
// 	}



//	public static class ClientInfo
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_port_info_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public ClientInfo()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.ClientInfo.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.ClientInfo.<init>(): malloc() returns: " + nReturn); }
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of client_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.ClientInfo.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();



// 		public native int getClient();

// 		public native int getType();

// 		public native String getName();

// 		public native int getBroadcastFilter();

// 		public native int getErrorBounce();

// 		// TODO: event filter

// 		public native int getNumPorts();

// 		public native int getEventLost();


// 		public native void setClient(int nClient);

// 		public native void setName(String strName);

// 		public native void setBroadcastFilter(int nBroadcastFilter);


// 		public native void setErrorBounce(int nErrorBounce);

// 		// TODO: event filter
// 	}



// 	public static class PortInfo
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_port_info_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public PortInfo()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.PortInfo.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of port_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.PortInfo.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();



// 		public native int getClient();



// 		public native int getPort();


// 		/**	Returns the name of the port.
// 			Calls snd_seq_port_info_get_name().
// 		*/
// 		public native String getName();



// 		public native int getCapability();



// 		public native int getType();



// 		public native int getMidiChannels();



// 		public native int getMidiVoices();



// 		public native int getSynthVoices();



// 		public native int getReadUse();



// 		public native int getWriteUse();



// 		public native int getPortSpecified();
// 	}



// 	public static class PortSubscribe
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_port_info_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public PortSubscribe()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.PortSubscribe.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of port_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.PortSubscribe.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();



// 		public native int getSenderClient();
// 		public native int getSenderPort();
// 		public native int getDestClient();
// 		public native int getDestPort();

// 		public native int getQueue();

// 		public native boolean getExclusive();
// 		public native boolean getTimeUpdate();
// 		public native boolean getTimeReal();

// 		public native void setSender(int nClient, int nPort);
// 		public native void setDest(int nClient, int nPort);

// 		public native void setQueue(int nQueue);

// 		public native void setExclusive(boolean bExclusive);
// 		public native void setTimeUpdate(boolean bUpdate);
// 		public native void setTimeReal(boolean bReal);
// 	}



// 	public static class QueueInfo
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_queue_info_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public QueueInfo()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueInfo.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of port_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueInfo.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();

// 		public native int getQueue();
// 		public native String getName();
// 		public native int getOwner();
// 		public native boolean getLocked();
// 		public native int getFlags();

// 		public native void setName(String strName);
// 		public native void setOwner(int nOwner);
// 		public native void setLocked(boolean bLocked);
// 		public native void setFlags(int nFlags);

// 	}



// 	public static class QueueStatus
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_queue_status_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public QueueStatus()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueStatus.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of port_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueStatus.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();

// 		public native int getQueue();
// 		public native int getEvents();
// 		public native long getTickTime();
// 		public native long getRealTime();
// 		public native int getStatus();
// 	}



// 	public static class QueueTempo
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_queue_tempo_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public QueueTempo()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueTempo.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of port_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueTempo.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();

// 		public native int getQueue();
// 		public native int getTempo();
// 		public native int getPpq();
// 		public native void setTempo(int nTempo);
// 		public native void setPpq(int nPpq);
// 	}



// 	public static class QueueTimer
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_queue_timer_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public QueueTimer()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueTimer.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of port_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.QueueTimer.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();

// 		public native int getQueue();
// 		public native int getType();
// 		// TODO:
// 		// public native ?? getTimerId();
// 		public native int getResolution();

// 		public native void setType(int nType);
// 		// TODO:
// 							 // public native void setId(???);
// 		public native void setResolution(int nResolution);
// 	}



// 	public static class RemoveEvents
// 	{
// 		/**
// 		 *	Holds the pointer to snd_seq_queue_timer_t
// 		 *	for the native code.
// 		 *	This must be long to be 64bit-clean.
// 		 */
// 		/*private*/ long	m_lNativeHandle;



// 		public RemoveEvents()
// 		{
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.RemoveEvents.<init>(): begin"); }
// 			int	nReturn = malloc();
// 			if (nReturn < 0)
// 			{
// 				throw new RuntimeException("malloc of port_info failed");
// 			}
// 			if (TDebug.TraceAlsaSeqNative) { TDebug.out("AlsaSeq.RemoveEvents.<init>(): end"); }
// 		}



// 		public void finalize()
// 		{
// 			// TODO: call free()
// 			// call super.finalize() first or last?
// 			// and introduce a flag if free() has already been called?
// 		}



// 		private native int malloc();
// 		public native void free();

// 		public native int getCondition();
// 		public native int getQueue();
// 		public native long getTime();
// 		public native int getDestClient();
// 		public native int getDestPort();
// 		public native int getChannel();
// 		public native int getEventType();
// 		public native int getTag();

// 		public native void setCondition(int nCondition);
// 		public native void setQueue(int nQueue);
// 		public native void setTime(long lTime);
// 		public native void setDest(int nClient, int nPort);
// 		public native void setChannel(int nChannel);
// 		public native void setEventType(int nEventType);
// 		public native void setTag(int nTag);
// 	}



	private class ClientInfoIterator
	implements Iterator
	{
		private int			m_nClient;
		private AlsaSeqClientInfo	m_clientInfo;



		public ClientInfoIterator()
		{
			m_nClient = -1;
			m_clientInfo = createNextClientInfo();
		}



		public boolean hasNext()
		{
			// TDebug.out("hasNext(): clientInfo: " + m_clientInfo);
			return m_clientInfo != null;
		}



		public Object next()
		{
			Object	next = m_clientInfo;
			m_clientInfo = createNextClientInfo();
			return next;
		}



		public void remove()
		{
			throw new UnsupportedOperationException();
		}


		private AlsaSeqClientInfo createNextClientInfo()
		{
			if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.createNextClientInfo(): begin"); }
			AlsaSeqClientInfo	clientInfo = null;
			int[]		anValues = new int[1];
			int	nSuccess = getNextClient(m_nClient, anValues);
			if (TDebug.TraceAlsaSeq) { TDebug.out("succ: " + nSuccess); }
			if (nSuccess == 0)
			{
				// TDebug.out("AlsaSeq.createNextClientInfo(): getNextClientInfo successful");
				m_nClient = anValues[0];
				clientInfo = new AlsaSeqClientInfo();
				// TODO: error check
				getClientInfo(m_nClient, clientInfo);
			}
			if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.createNextClientInfo(): end"); }
			return clientInfo;
		}
	}



	private class PortInfoIterator
	implements Iterator
	{
		private int		m_nClient;
		private int		m_nPort;
		private AlsaSeqPortInfo	m_portInfo;



		public PortInfoIterator(int nClient)
		{
			if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.PortInfoIterator.<init>(): begin"); }
			m_nClient = nClient;
			m_nPort = -1;
			m_portInfo = createNextPortInfo();
			if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.PortInfoIterator.<init>(): end"); }
		}



		public boolean hasNext()
		{
			return m_portInfo != null;
		}



		public Object next()
		{
			Object	next = m_portInfo;
			m_portInfo = createNextPortInfo();
			return next;
		}



		public void remove()
		{
			throw new UnsupportedOperationException();
		}


		private AlsaSeqPortInfo createNextPortInfo()
		{
			if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.PortInfoIterator.createNextPortInfo(): begin"); }
			AlsaSeqPortInfo	portInfo = null;
			int[]		anValues = new int[2];
			int	nSuccess = getNextPort(m_nClient, m_nPort, anValues);
			if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.PortInfoIterator.createNextPortInfo(): getNextPort() returns: " + nSuccess); }
			if (nSuccess == 0)
			{
				m_nPort = anValues[1];
				portInfo = new AlsaSeqPortInfo();
				// TODO: error check
				getPortInfo(m_nClient, m_nPort, portInfo);
			}
			if (TDebug.TraceAlsaSeq) { TDebug.out("AlsaSeq.PortInfoIterator.createNextPortInfo(): end"); }
			return portInfo;
		}
	}

}



/*** AlsaSeq.java ***/
