mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Added time skew on queue.
The timer speed can be controlled via skew value, smaller = slower centered on the skew-base value.
This commit is contained in:
parent
e457d1f0c0
commit
bcf50519e4
4 changed files with 87 additions and 17 deletions
|
|
@ -438,8 +438,12 @@ void snd_seq_queue_tempo_copy(snd_seq_queue_tempo_t *dst, const snd_seq_queue_te
|
||||||
int snd_seq_queue_tempo_get_queue(const snd_seq_queue_tempo_t *info);
|
int snd_seq_queue_tempo_get_queue(const snd_seq_queue_tempo_t *info);
|
||||||
unsigned int snd_seq_queue_tempo_get_tempo(const snd_seq_queue_tempo_t *info);
|
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_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_base(snd_seq_queue_tempo_t *info, unsigned int 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);
|
||||||
|
|
|
||||||
|
|
@ -98,8 +98,8 @@ enum snd_seq_event_type {
|
||||||
SND_SEQ_EVENT_CLOCK,
|
SND_SEQ_EVENT_CLOCK,
|
||||||
/** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */
|
/** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */
|
||||||
SND_SEQ_EVENT_TICK,
|
SND_SEQ_EVENT_TICK,
|
||||||
/** Sync signal; event data type = #snd_seq_ev_queue_control_t */
|
/** Queue timer skew; event data type = #snd_seq_ev_queue_control_t */
|
||||||
SND_SEQ_EVENT_SYNC,
|
SND_SEQ_EVENT_QUEUE_SKEW,
|
||||||
/** Sync position changed; event data type = #snd_seq_ev_queue_control_t */
|
/** Sync position changed; event data type = #snd_seq_ev_queue_control_t */
|
||||||
SND_SEQ_EVENT_SYNC_POS,
|
SND_SEQ_EVENT_SYNC_POS,
|
||||||
|
|
||||||
|
|
@ -403,6 +403,11 @@ typedef struct snd_seq_result {
|
||||||
int result; /**< status */
|
int result; /**< status */
|
||||||
} snd_seq_result_t;
|
} snd_seq_result_t;
|
||||||
|
|
||||||
|
/** Queue skew values */
|
||||||
|
typedef struct snd_seq_queue_skew {
|
||||||
|
unsigned int value;
|
||||||
|
unsigned int base;
|
||||||
|
} snd_seq_queue_skew_t;
|
||||||
|
|
||||||
/** queue timer control */
|
/** queue timer control */
|
||||||
typedef struct snd_seq_ev_queue_control {
|
typedef struct snd_seq_ev_queue_control {
|
||||||
|
|
@ -412,6 +417,7 @@ typedef struct snd_seq_ev_queue_control {
|
||||||
signed int value; /**< affected value (e.g. tempo) */
|
signed int value; /**< affected value (e.g. tempo) */
|
||||||
snd_seq_timestamp_t time; /**< time */
|
snd_seq_timestamp_t time; /**< time */
|
||||||
unsigned int position; /**< sync position */
|
unsigned int position; /**< sync position */
|
||||||
|
snd_seq_queue_skew_t skew; /**< queue skew */
|
||||||
unsigned int d32[2]; /**< any data */
|
unsigned int d32[2]; /**< any data */
|
||||||
unsigned char d8[8]; /**< any data */
|
unsigned char d8[8]; /**< any data */
|
||||||
} param; /**< data value union */
|
} param; /**< data value union */
|
||||||
|
|
|
||||||
|
|
@ -2260,6 +2260,28 @@ int snd_seq_queue_tempo_get_ppq(const snd_seq_queue_tempo_t *info)
|
||||||
return info->ppq;
|
return info->ppq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the timer skew value of a queue_status container
|
||||||
|
* \param info queue_status container
|
||||||
|
* \return timer skew value
|
||||||
|
*/
|
||||||
|
unsigned int snd_seq_queue_tempo_get_skew(const snd_seq_queue_tempo_t *info)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
return info->skew_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the timer skew base value of a queue_status container
|
||||||
|
* \param info queue_status container
|
||||||
|
* \return timer skew base value
|
||||||
|
*/
|
||||||
|
unsigned int snd_seq_queue_tempo_get_skew_base(const snd_seq_queue_tempo_t *info)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
return info->skew_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
|
||||||
|
|
@ -2282,6 +2304,30 @@ void snd_seq_queue_tempo_set_ppq(snd_seq_queue_tempo_t *info, int ppq)
|
||||||
info->ppq = ppq;
|
info->ppq = ppq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the timer skew value of a queue_status container
|
||||||
|
* \param info queue_status container
|
||||||
|
* \param skew timer skew value
|
||||||
|
*
|
||||||
|
* The skew of timer is calculated as skew / base.
|
||||||
|
* For example, to play with double speed, pass base * 2 as the skew value.
|
||||||
|
*/
|
||||||
|
void snd_seq_queue_tempo_set_skew(snd_seq_queue_tempo_t *info, unsigned int skew)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
info->skew_value = skew;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the timer skew base value of a queue_status container
|
||||||
|
* \param info queue_status container
|
||||||
|
* \param base timer skew base value
|
||||||
|
*/
|
||||||
|
void snd_seq_queue_tempo_set_skew_base(snd_seq_queue_tempo_t *info, unsigned int base)
|
||||||
|
{
|
||||||
|
assert(info);
|
||||||
|
info->skew_base = base;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief obtain the current tempo of the queue
|
* \brief obtain the current tempo of the queue
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,8 @@ static int local_ticks = 0;
|
||||||
static int local_tempo = 500000;
|
static int local_tempo = 500000;
|
||||||
|
|
||||||
static int dest_queue = -1;
|
static int dest_queue = -1;
|
||||||
|
static int shared_queue = 0;
|
||||||
|
static int tick_offset = 0;
|
||||||
static int dest_client = DEST_CLIENT_NUMBER;
|
static int dest_client = DEST_CLIENT_NUMBER;
|
||||||
static int dest_port = DEST_PORT_NUMBER;
|
static int dest_port = DEST_PORT_NUMBER;
|
||||||
static int my_port = 0;
|
static int my_port = 0;
|
||||||
|
|
@ -153,7 +155,8 @@ static void do_header(int format, int ntracks, int division)
|
||||||
|
|
||||||
if (format != 0 || ntracks != 1) {
|
if (format != 0 || ntracks != 1) {
|
||||||
printf("This player does not support merging of tracks.\n");
|
printf("This player does not support merging of tracks.\n");
|
||||||
alsa_stop_timer();
|
if (! shared_queue)
|
||||||
|
alsa_stop_timer();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* set ppq */
|
/* set ppq */
|
||||||
|
|
@ -163,12 +166,11 @@ static void do_header(int format, int ntracks, int division)
|
||||||
perror("get_queue_tempo");
|
perror("get_queue_tempo");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (snd_seq_queue_tempo_get_ppq(tempo) != ppq) {
|
if ((slave_ppq = snd_seq_queue_tempo_get_ppq(tempo)) != ppq) {
|
||||||
slave_ppq = snd_seq_queue_tempo_get_ppq(tempo);
|
|
||||||
snd_seq_queue_tempo_set_ppq(tempo, ppq);
|
snd_seq_queue_tempo_set_ppq(tempo, ppq);
|
||||||
if (snd_seq_set_queue_tempo(seq_handle, dest_queue, tempo) < 0) {
|
if (snd_seq_set_queue_tempo(seq_handle, dest_queue, tempo) < 0) {
|
||||||
perror("set_queue_tempo");
|
perror("set_queue_tempo");
|
||||||
if (!slave)
|
if (!slave && !shared_queue)
|
||||||
exit(1);
|
exit(1);
|
||||||
else
|
else
|
||||||
printf("different PPQ %d in SMF from queue PPQ %d\n", ppq, slave_ppq);
|
printf("different PPQ %d in SMF from queue PPQ %d\n", ppq, slave_ppq);
|
||||||
|
|
@ -185,8 +187,16 @@ static void do_header(int format, int ntracks, int division)
|
||||||
wait_start();
|
wait_start();
|
||||||
if (verbose >= VERB_INFO)
|
if (verbose >= VERB_INFO)
|
||||||
printf("Go!\n");
|
printf("Go!\n");
|
||||||
} else
|
} else if (shared_queue) {
|
||||||
|
snd_seq_queue_status_t *stat;
|
||||||
|
snd_seq_queue_status_alloca(&stat);
|
||||||
|
snd_seq_get_queue_status(seq_handle, dest_queue, stat);
|
||||||
|
tick_offset = snd_seq_queue_status_get_tick_time(stat);
|
||||||
|
fprintf(stderr, "tick offset = %d\n", tick_offset);
|
||||||
|
} else {
|
||||||
alsa_start_timer();
|
alsa_start_timer();
|
||||||
|
tick_offset = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill time */
|
/* fill time */
|
||||||
|
|
@ -201,6 +211,7 @@ static void set_event_time(snd_seq_event_t *ev, unsigned int currtime)
|
||||||
} else {
|
} else {
|
||||||
if (ppq != slave_ppq)
|
if (ppq != slave_ppq)
|
||||||
currtime = (currtime * slave_ppq) / ppq;
|
currtime = (currtime * slave_ppq) / ppq;
|
||||||
|
currtime += tick_offset;
|
||||||
snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime);
|
snd_seq_ev_schedule_tick(ev, dest_queue, 0, currtime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +265,7 @@ static void do_noteon(int chan, int pitch, int vol)
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
if (verbose >= VERB_EVENT)
|
if (verbose >= VERB_EVENT)
|
||||||
printf("NoteOn (%d) %d %d\n", chan, pitch, vol);
|
printf("%d: NoteOn (%d) %d %d\n", Mf_currtime, chan, pitch, vol);
|
||||||
set_event_header(&ev);
|
set_event_header(&ev);
|
||||||
snd_seq_ev_set_noteon(&ev, chan, pitch, vol);
|
snd_seq_ev_set_noteon(&ev, chan, pitch, vol);
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
@ -266,7 +277,7 @@ static void do_noteoff(int chan, int pitch, int vol)
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
if (verbose >= VERB_EVENT)
|
if (verbose >= VERB_EVENT)
|
||||||
printf("NoteOff (%d) %d %d\n", chan, pitch, vol);
|
printf("%d: NoteOff (%d) %d %d\n", Mf_currtime, chan, pitch, vol);
|
||||||
set_event_header(&ev);
|
set_event_header(&ev);
|
||||||
snd_seq_ev_set_noteoff(&ev, chan, pitch, vol);
|
snd_seq_ev_set_noteoff(&ev, chan, pitch, vol);
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
@ -278,7 +289,7 @@ static void do_program(int chan, int program)
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
if (verbose >= VERB_EVENT)
|
if (verbose >= VERB_EVENT)
|
||||||
printf("Program (%d) %d\n", chan, program);
|
printf("%d: Program (%d) %d\n", Mf_currtime, chan, program);
|
||||||
set_event_header(&ev);
|
set_event_header(&ev);
|
||||||
snd_seq_ev_set_pgmchange(&ev, chan, program);
|
snd_seq_ev_set_pgmchange(&ev, chan, program);
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
@ -290,7 +301,7 @@ static void do_parameter(int chan, int control, int value)
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
if (verbose >= VERB_EVENT)
|
if (verbose >= VERB_EVENT)
|
||||||
printf("Control (%d) %d %d\n", chan, control, value);
|
printf("%d: Control (%d) %d %d\n", Mf_currtime, chan, control, value);
|
||||||
set_event_header(&ev);
|
set_event_header(&ev);
|
||||||
snd_seq_ev_set_controller(&ev, chan, control, value);
|
snd_seq_ev_set_controller(&ev, chan, control, value);
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
@ -302,7 +313,7 @@ static void do_pitchbend(int chan, int lsb, int msb)
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
if (verbose >= VERB_EVENT)
|
if (verbose >= VERB_EVENT)
|
||||||
printf("Pitchbend (%d) %d %d\n", chan, lsb, msb);
|
printf("%d: Pitchbend (%d) %d %d\n", Mf_currtime, chan, lsb, msb);
|
||||||
set_event_header(&ev);
|
set_event_header(&ev);
|
||||||
snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192);
|
snd_seq_ev_set_pitchbend(&ev, chan, (lsb + (msb << 7)) - 8192);
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
@ -313,7 +324,7 @@ static void do_pressure(int chan, int pitch, int pressure)
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
if (verbose >= VERB_EVENT)
|
if (verbose >= VERB_EVENT)
|
||||||
printf("KeyPress (%d) %d %d\n", chan, pitch, pressure);
|
printf("%d: KeyPress (%d) %d %d\n", Mf_currtime, chan, pitch, pressure);
|
||||||
set_event_header(&ev);
|
set_event_header(&ev);
|
||||||
snd_seq_ev_set_keypress(&ev, chan, pitch, pressure);
|
snd_seq_ev_set_keypress(&ev, chan, pitch, pressure);
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
@ -324,7 +335,7 @@ static void do_chanpressure(int chan, int pressure)
|
||||||
snd_seq_event_t ev;
|
snd_seq_event_t ev;
|
||||||
|
|
||||||
if (verbose >= VERB_EVENT)
|
if (verbose >= VERB_EVENT)
|
||||||
printf("ChanPress (%d) %d\n", chan, pressure);
|
printf("%d: ChanPress (%d) %d\n", Mf_currtime, chan, pressure);
|
||||||
set_event_header(&ev);
|
set_event_header(&ev);
|
||||||
snd_seq_ev_set_chanpress(&ev, chan, pressure);
|
snd_seq_ev_set_chanpress(&ev, chan, pressure);
|
||||||
write_ev(&ev);
|
write_ev(&ev);
|
||||||
|
|
@ -336,7 +347,7 @@ static void do_sysex(int len, char *msg)
|
||||||
|
|
||||||
if (verbose >= VERB_MUCH) {
|
if (verbose >= VERB_MUCH) {
|
||||||
int c;
|
int c;
|
||||||
printf("Sysex, len=%d\n", len);
|
printf("%d: Sysex, len=%d\n", Mf_currtime, len);
|
||||||
for (c = 0; c < len; c++) {
|
for (c = 0; c < len; c++) {
|
||||||
printf(" %02x", (unsigned char)msg[c]);
|
printf(" %02x", (unsigned char)msg[c]);
|
||||||
if (c % 16 == 15)
|
if (c % 16 == 15)
|
||||||
|
|
@ -440,7 +451,7 @@ int main(int argc, char *argv[])
|
||||||
int tmp;
|
int tmp;
|
||||||
int c;
|
int c;
|
||||||
snd_seq_addr_t dest_addr;
|
snd_seq_addr_t dest_addr;
|
||||||
const char *addr = NULL;
|
const char *addr = "65:0";
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) {
|
while ((c = getopt(argc, argv, "s:a:p:q:vrb")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
@ -525,11 +536,13 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
/* setup queue */
|
/* setup queue */
|
||||||
if (dest_queue >= 0) {
|
if (dest_queue >= 0) {
|
||||||
|
shared_queue = 1;
|
||||||
if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) {
|
if (snd_seq_set_queue_usage(seq_handle, dest_queue, 1) < 0) {
|
||||||
perror("use queue");
|
perror("use queue");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
shared_queue = 0;
|
||||||
dest_queue = snd_seq_alloc_queue(seq_handle);
|
dest_queue = snd_seq_alloc_queue(seq_handle);
|
||||||
if (dest_queue < 0) {
|
if (dest_queue < 0) {
|
||||||
perror("alloc queue");
|
perror("alloc queue");
|
||||||
|
|
@ -590,7 +603,8 @@ int main(int argc, char *argv[])
|
||||||
mfread();
|
mfread();
|
||||||
|
|
||||||
alsa_sync();
|
alsa_sync();
|
||||||
alsa_stop_timer();
|
if (! shared_queue)
|
||||||
|
alsa_stop_timer();
|
||||||
|
|
||||||
snd_seq_close(seq_handle);
|
snd_seq_close(seq_handle);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue