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_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_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_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_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);
/*
*/
#include <sound/asound.h>
/** 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
/* queue tempo */
struct snd_seq_queue_tempo {
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 */
unsigned int skew_value; /* queue skew */
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 */
};
#ifdef HAVE_SEQ_SYMS
@SYMBOL_PREFIX@snd_seq_create_ump_endpoint;
@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
#ifdef HAVE_RAWMIDI_SYMS
@SYMBOL_PREFIX@snd_ump_endpoint_info_clear;
You can schedule the event in a certain queue so that the tempo
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
To start, stop, or continue a queue, you need to send a queue-control
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
* \param info queue_status container
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
* \param seq sequencer handle
int snd_seq_set_queue_tempo(snd_seq_t *seq, int q, snd_seq_queue_tempo_t * tempo)
{
assert(seq && tempo);
+ if (!seq->has_queue_tempo_base &&
+ tempo->tempo_base && tempo->tempo_base != 1000)
+ return -EINVAL;
tempo->queue = q;
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;
+}
/*----------------------------------------------------------------*/
/*SYSERR("SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO failed");*/
return -errno;
}
+ if (!seq->has_queue_tempo_base)
+ tempo->tempo_base = 1000;
return 0;
}
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;
+
if (ioctl(hw->fd, SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, tempo) < 0) {
/*SYSERR("SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO failed");*/
return -errno;
seq->ops = &snd_seq_hw_ops;
seq->private_data = hw;
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);
if (client < 0) {
snd_seq_close(seq);
size_t tmpbufsize; /* size of errbuf */
size_t packet_size; /* input packet alignment size */
int midi_version; /* current protocol version */
+ int has_queue_tempo_base; /* support queue tempo-base? */
unsigned int num_ump_groups; /* number of UMP groups */
snd_ump_endpoint_info_t *ump_ep; /* optional UMP info */