mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	seq: Add API functions to set different tempo base values
MIDI2 Set Tempo message uses 10ns-based values, and we need to update the API to change the base time unit. This patch adds a few new API functions: - snd_seq_has_queue_tempo_base() returns 1 if the client supports a new tempo-base value; if 0, it's an old system and application has to use the tempo in the fixed 1us unit - the tempo base can be changed with snd_seq_queue_tempo_set_tempo_base(), provided in nsec unit; the value has to be either 10 or 1000 (or 0 as default, equivalent with 1000) The protocol version is checked and fallback to the fixed 1us base for the old clients. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
		
							parent
							
								
									568b2ac1db
								
							
						
					
					
						commit
						24c7f42733
					
				
					 6 changed files with 74 additions and 3 deletions
				
			
		| 
						 | 
					@ -506,13 +506,16 @@ unsigned int snd_seq_queue_tempo_get_tempo(const snd_seq_queue_tempo_t *info);
 | 
				
			||||||
int snd_seq_queue_tempo_get_ppq(const snd_seq_queue_tempo_t *info);
 | 
					int snd_seq_queue_tempo_get_ppq(const snd_seq_queue_tempo_t *info);
 | 
				
			||||||
unsigned int snd_seq_queue_tempo_get_skew(const snd_seq_queue_tempo_t *info);
 | 
					unsigned int snd_seq_queue_tempo_get_skew(const snd_seq_queue_tempo_t *info);
 | 
				
			||||||
unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info);
 | 
					unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info);
 | 
				
			||||||
 | 
					unsigned int snd_seq_queue_tempo_get_tempo_base(const snd_seq_queue_tempo_t *info);
 | 
				
			||||||
void snd_seq_queue_tempo_set_tempo(snd_seq_queue_tempo_t *info, unsigned int tempo);
 | 
					void snd_seq_queue_tempo_set_tempo(snd_seq_queue_tempo_t *info, unsigned int tempo);
 | 
				
			||||||
void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t *info, int ppq);
 | 
					void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t *info, int ppq);
 | 
				
			||||||
void snd_seq_queue_tempo_set_skew(snd_seq_queue_tempo_t *info, unsigned int skew);
 | 
					void snd_seq_queue_tempo_set_skew(snd_seq_queue_tempo_t *info, unsigned int skew);
 | 
				
			||||||
void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int base);
 | 
					void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int base);
 | 
				
			||||||
 | 
					void snd_seq_queue_tempo_set_tempo_base(snd_seq_queue_tempo_t *info, unsigned int tempo_base);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_seq_get_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo);
 | 
					int snd_seq_get_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo);
 | 
				
			||||||
int snd_seq_set_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo);
 | 
					int snd_seq_set_queue_tempo(snd_seq_t *handle, int q, snd_seq_queue_tempo_t *tempo);
 | 
				
			||||||
 | 
					int snd_seq_has_queue_tempo_base(snd_seq_t *handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@
 | 
				
			||||||
#include <sound/asound.h>
 | 
					#include <sound/asound.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** version of the sequencer */
 | 
					/** version of the sequencer */
 | 
				
			||||||
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3)
 | 
					#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * definition of sequencer event types
 | 
					 * definition of sequencer event types
 | 
				
			||||||
| 
						 | 
					@ -539,11 +539,12 @@ struct snd_seq_queue_status {
 | 
				
			||||||
/* queue tempo */
 | 
					/* queue tempo */
 | 
				
			||||||
struct snd_seq_queue_tempo {
 | 
					struct snd_seq_queue_tempo {
 | 
				
			||||||
	int queue;			/* sequencer queue */
 | 
						int queue;			/* sequencer queue */
 | 
				
			||||||
	unsigned int tempo;		/* current tempo, us/tick */
 | 
						unsigned int tempo;		/* current tempo, us/tick (or different time-base below) */
 | 
				
			||||||
	int ppq;			/* time resolution, ticks/quarter */
 | 
						int ppq;			/* time resolution, ticks/quarter */
 | 
				
			||||||
	unsigned int skew_value;	/* queue skew */
 | 
						unsigned int skew_value;	/* queue skew */
 | 
				
			||||||
	unsigned int skew_base;		/* queue skew base */
 | 
						unsigned int skew_base;		/* queue skew base */
 | 
				
			||||||
	char reserved[24];		/* for the future */
 | 
						unsigned short tempo_base;	/* tempo base in nsec unit; either 10 or 1000 */
 | 
				
			||||||
 | 
						char reserved[22];		/* for the future */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,6 +206,9 @@ ALSA_1.2.13 {
 | 
				
			||||||
#ifdef HAVE_SEQ_SYMS
 | 
					#ifdef HAVE_SEQ_SYMS
 | 
				
			||||||
    @SYMBOL_PREFIX@snd_seq_create_ump_endpoint;
 | 
					    @SYMBOL_PREFIX@snd_seq_create_ump_endpoint;
 | 
				
			||||||
    @SYMBOL_PREFIX@snd_seq_create_ump_block;
 | 
					    @SYMBOL_PREFIX@snd_seq_create_ump_block;
 | 
				
			||||||
 | 
					    @SYMBOL_PREFIX@snd_seq_queue_tempo_get_tempo_base;
 | 
				
			||||||
 | 
					    @SYMBOL_PREFIX@snd_seq_queue_tempo_set_tempo_base;
 | 
				
			||||||
 | 
					    @SYMBOL_PREFIX@snd_seq_has_tempo_base;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef HAVE_RAWMIDI_SYMS
 | 
					#ifdef HAVE_RAWMIDI_SYMS
 | 
				
			||||||
    @SYMBOL_PREFIX@snd_ump_endpoint_info_clear;
 | 
					    @SYMBOL_PREFIX@snd_ump_endpoint_info_clear;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -490,6 +490,21 @@ the buffer is flushed by #snd_seq_drain_output() call.
 | 
				
			||||||
You can schedule the event in a certain queue so that the tempo
 | 
					You can schedule the event in a certain queue so that the tempo
 | 
				
			||||||
change happens at the scheduled time, too.
 | 
					change happens at the scheduled time, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The tempo is set as default in microsecond unit as defined for
 | 
				
			||||||
 | 
					Standard MIDI Format 1.  But since the value in MIDI2 Set Tempo message
 | 
				
			||||||
 | 
					is based on 10-nanosecand unit, sequencer queue also allows to set up
 | 
				
			||||||
 | 
					in 10-nanosecond unit.  For that, change the tempo-base value in
 | 
				
			||||||
 | 
					#snd_seq_queue_tempo_t to 10 via #snd_seq_queue_tempo_set_tempo_base()
 | 
				
			||||||
 | 
					along with the 10-nanobased tempo value.  The default tempo base is 1000,
 | 
				
			||||||
 | 
					i.e. 1 microsecond.
 | 
				
			||||||
 | 
					Currently the API supports only either 0, 10 or 1000 as the tempo-base
 | 
				
			||||||
 | 
					(where 0 is treated as 1000).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The older kernel might not support the different tempo-base, and setting a
 | 
				
			||||||
 | 
					different value from 1000 would fail.  The application may heck the
 | 
				
			||||||
 | 
					availability of tempo-base change via #snd_seq_has_tempo_base() function
 | 
				
			||||||
 | 
					beforehand, and re-calculate in microsecond unit as fallback.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
\subsection seq_ev_start Starting and stopping a queue
 | 
					\subsection seq_ev_start Starting and stopping a queue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To start, stop, or continue a queue, you need to send a queue-control
 | 
					To start, stop, or continue a queue, you need to send a queue-control
 | 
				
			||||||
| 
						 | 
					@ -3878,6 +3893,19 @@ unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info
 | 
				
			||||||
	return info->skew_base;
 | 
						return info->skew_base;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Get the tempo base of a queue_status container
 | 
				
			||||||
 | 
					 * \param info queue_status container
 | 
				
			||||||
 | 
					 * \return tempo base time in nsec unit
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \sa snd_seq_get_queue_tempo()
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					unsigned int snd_seq_queue_tempo_get_tempo_base(const snd_seq_queue_tempo_t *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert(info);
 | 
				
			||||||
 | 
						return info->tempo_base;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * \brief Set the tempo of a queue_status container
 | 
					 * \brief Set the tempo of a queue_status container
 | 
				
			||||||
 * \param info queue_status container
 | 
					 * \param info queue_status container
 | 
				
			||||||
| 
						 | 
					@ -3933,6 +3961,21 @@ void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int
 | 
				
			||||||
	info->skew_base = base;
 | 
						info->skew_base = base;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief Set the tempo base of a queue_status container
 | 
				
			||||||
 | 
					 * \param info queue_status container
 | 
				
			||||||
 | 
					 * \param tempo_base tempo base time in nsec unit
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \sa snd_seq_get_queue_tempo()
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void snd_seq_queue_tempo_set_tempo_base(snd_seq_queue_tempo_t *info, unsigned int tempo_base)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert(info);
 | 
				
			||||||
 | 
						if (!tempo_base)
 | 
				
			||||||
 | 
							tempo_base = 1000;
 | 
				
			||||||
 | 
						info->tempo_base = tempo_base;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * \brief obtain the current tempo of the queue
 | 
					 * \brief obtain the current tempo of the queue
 | 
				
			||||||
 * \param seq sequencer handle
 | 
					 * \param seq sequencer handle
 | 
				
			||||||
| 
						 | 
					@ -3962,10 +4005,25 @@ int snd_seq_get_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo
 | 
				
			||||||
int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
 | 
					int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	assert(seq && tempo);
 | 
						assert(seq && tempo);
 | 
				
			||||||
 | 
						if (!seq->has_queue_tempo_base &&
 | 
				
			||||||
 | 
						    tempo->tempo_base && tempo->tempo_base != 1000)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
	tempo->queue = q;
 | 
						tempo->queue = q;
 | 
				
			||||||
	return seq->ops->set_queue_tempo(seq, tempo);
 | 
						return seq->ops->set_queue_tempo(seq, tempo);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * \brief inquiry the support of tempo base change
 | 
				
			||||||
 | 
					 * \param seq sequencer handle
 | 
				
			||||||
 | 
					 * \return 1 if the client supports the tempo base change, 0 if not
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \sa snd_seq_get_queue_tempo()
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int snd_seq_has_queue_tempo_base(snd_seq_t *seq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						assert(seq);
 | 
				
			||||||
 | 
						return seq->has_queue_tempo_base;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*----------------------------------------------------------------*/
 | 
					/*----------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -275,12 +275,15 @@ static int snd_seq_hw_get_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * te
 | 
				
			||||||
		/*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO failed");*/
 | 
							/*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO failed");*/
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (!seq->has_queue_tempo_base)
 | 
				
			||||||
 | 
							tempo->tempo_base = 1000;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
 | 
					static int snd_seq_hw_set_queue_tempo(snd_seq_t *seq, snd_seq_queue_tempo_t * tempo)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_seq_hw_t *hw = seq->private_data;
 | 
						snd_seq_hw_t *hw = seq->private_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
 | 
						if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
 | 
				
			||||||
		/*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO failed");*/
 | 
							/*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO failed");*/
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
| 
						 | 
					@ -587,6 +590,8 @@ int snd_seq_hw_open(snd_seq_t **handle, const char *name, int streams, int mode)
 | 
				
			||||||
	seq->ops = &snd_seq_hw_ops;
 | 
						seq->ops = &snd_seq_hw_ops;
 | 
				
			||||||
	seq->private_data = hw;
 | 
						seq->private_data = hw;
 | 
				
			||||||
	seq->packet_size = sizeof(snd_seq_event_t);
 | 
						seq->packet_size = sizeof(snd_seq_event_t);
 | 
				
			||||||
 | 
						seq->has_queue_tempo_base = ver >= SNDRV_PROTOCOL_VERSION(1, 0, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	client = snd_seq_hw_client_id(seq);
 | 
						client = snd_seq_hw_client_id(seq);
 | 
				
			||||||
	if (client < 0) {
 | 
						if (client < 0) {
 | 
				
			||||||
		snd_seq_close(seq);
 | 
							snd_seq_close(seq);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,6 +94,7 @@ struct _snd_seq {
 | 
				
			||||||
	size_t tmpbufsize;		/* size of errbuf */
 | 
						size_t tmpbufsize;		/* size of errbuf */
 | 
				
			||||||
	size_t packet_size;		/* input packet alignment size */
 | 
						size_t packet_size;		/* input packet alignment size */
 | 
				
			||||||
	int midi_version;	/* current protocol version */
 | 
						int midi_version;	/* current protocol version */
 | 
				
			||||||
 | 
						int has_queue_tempo_base;	/* support queue tempo-base? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int num_ump_groups;		/* number of UMP groups */
 | 
						unsigned int num_ump_groups;		/* number of UMP groups */
 | 
				
			||||||
	snd_ump_endpoint_info_t *ump_ep;	/* optional UMP info */
 | 
						snd_ump_endpoint_info_t *ump_ep;	/* optional UMP info */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue