Skip to content

Commit fefbbdf

Browse files
committed
ALSA: seq: Add tempo base unit for MIDI2 Set Tempo messages
MIDI2 Set Tempo message defines the tempo in 10ns unit for finer accuracy, while MIDI1 was defined in 1us unit. For adapting this different unit, introduce "tempo_base" field to snd_seq_queue_tempo struct so that user-space can pass the proper tempo base unit. The accepted value is limited, it must be either 0, 10 or 1000. The protocol version is bumped to 1.0.4 along with this. The access with the older protocol version ignores the tempo-base value in ioctls and always treats as 1000. Reviewed-by: Jaroslav Kysela <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent a892b70 commit fefbbdf

File tree

5 files changed

+30
-12
lines changed

5 files changed

+30
-12
lines changed

include/uapi/sound/asequencer.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <sound/asound.h>
1111

1212
/** version of the sequencer */
13-
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 3)
13+
#define SNDRV_SEQ_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 4)
1414

1515
/**
1616
* definition of sequencer event types
@@ -523,11 +523,12 @@ struct snd_seq_queue_status {
523523
/* queue tempo */
524524
struct snd_seq_queue_tempo {
525525
int queue; /* sequencer queue */
526-
unsigned int tempo; /* current tempo, us/tick */
526+
unsigned int tempo; /* current tempo, us/tick (or different time-base below) */
527527
int ppq; /* time resolution, ticks/quarter */
528528
unsigned int skew_value; /* queue skew */
529529
unsigned int skew_base; /* queue skew base */
530-
char reserved[24]; /* for the future */
530+
unsigned short tempo_base; /* tempo base in nsec unit; either 10 or 1000 */
531+
char reserved[22]; /* for the future */
531532
};
532533

533534

sound/core/seq/seq_clientmgr.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,6 +1718,8 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client,
17181718
tempo->ppq = tmr->ppq;
17191719
tempo->skew_value = tmr->skew;
17201720
tempo->skew_base = tmr->skew_base;
1721+
if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 4))
1722+
tempo->tempo_base = tmr->tempo_base;
17211723
queuefree(queue);
17221724

17231725
return 0;
@@ -1739,6 +1741,8 @@ static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
17391741
struct snd_seq_queue_tempo *tempo = arg;
17401742
int result;
17411743

1744+
if (client->user_pversion < SNDRV_PROTOCOL_VERSION(1, 0, 4))
1745+
tempo->tempo_base = 0;
17421746
result = snd_seq_set_queue_tempo(client->number, tempo);
17431747
return result < 0 ? result : 0;
17441748
}

sound/core/seq/seq_queue.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,8 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client,
460460
return -EPERM;
461461
}
462462

463-
result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq);
463+
result = snd_seq_timer_set_tempo_ppq(q->timer, info->tempo, info->ppq,
464+
info->tempo_base);
464465
if (result >= 0 && info->skew_base > 0)
465466
result = snd_seq_timer_set_skew(q->timer, info->skew_value,
466467
info->skew_base);
@@ -724,7 +725,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
724725

725726
tmr = q->timer;
726727
if (tmr->tempo)
727-
bpm = 60000000 / tmr->tempo;
728+
bpm = (60000 * tmr->tempo_base) / tmr->tempo;
728729
else
729730
bpm = 0;
730731

@@ -741,6 +742,7 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
741742
snd_iprintf(buffer, "timer state : %s\n", tmr->running ? "Running" : "Stopped");
742743
snd_iprintf(buffer, "timer PPQ : %d\n", tmr->ppq);
743744
snd_iprintf(buffer, "current tempo : %d\n", tmr->tempo);
745+
snd_iprintf(buffer, "tempo base : %d ns\n", tmr->tempo_base);
744746
snd_iprintf(buffer, "current BPM : %d\n", bpm);
745747
snd_iprintf(buffer, "current time : %d.%09d s\n", tmr->cur_time.tv_sec, tmr->cur_time.tv_nsec);
746748
snd_iprintf(buffer, "current tick : %d\n", tmr->tick.cur_tick);

sound/core/seq/seq_timer.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@
2020

2121
static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
2222
{
23-
if (tmr->tempo < 1000000)
24-
tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
23+
unsigned int threshold =
24+
tmr->tempo_base == 1000 ? 1000000 : 10000;
25+
26+
if (tmr->tempo < threshold)
27+
tmr->tick.resolution = (tmr->tempo * tmr->tempo_base) / tmr->ppq;
2528
else {
2629
/* might overflow.. */
2730
unsigned int s;
2831
s = tmr->tempo % tmr->ppq;
29-
s = (s * 1000) / tmr->ppq;
30-
tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
32+
s = (s * tmr->tempo_base) / tmr->ppq;
33+
tmr->tick.resolution = (tmr->tempo / tmr->ppq) * tmr->tempo_base;
3134
tmr->tick.resolution += s;
3235
}
3336
if (tmr->tick.resolution <= 0)
@@ -79,6 +82,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
7982
/* setup defaults */
8083
tmr->ppq = 96; /* 96 PPQ */
8184
tmr->tempo = 500000; /* 120 BPM */
85+
tmr->tempo_base = 1000; /* 1us */
8286
snd_seq_timer_set_tick_resolution(tmr);
8387
tmr->running = 0;
8488

@@ -164,15 +168,19 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
164168
return 0;
165169
}
166170

167-
/* set current tempo and ppq in a shot */
168-
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
171+
/* set current tempo, ppq and base in a shot */
172+
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq,
173+
unsigned int tempo_base)
169174
{
170175
int changed;
171176

172177
if (snd_BUG_ON(!tmr))
173178
return -EINVAL;
174179
if (tempo <= 0 || ppq <= 0)
175180
return -EINVAL;
181+
/* allow only 10ns or 1us tempo base for now */
182+
if (tempo_base && tempo_base != 10 && tempo_base != 1000)
183+
return -EINVAL;
176184
guard(spinlock_irqsave)(&tmr->lock);
177185
if (tmr->running && (ppq != tmr->ppq)) {
178186
/* refuse to change ppq on running timers */
@@ -183,6 +191,7 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
183191
changed = (tempo != tmr->tempo) || (ppq != tmr->ppq);
184192
tmr->tempo = tempo;
185193
tmr->ppq = ppq;
194+
tmr->tempo_base = tempo_base ? tempo_base : 1000;
186195
if (changed)
187196
snd_seq_timer_set_tick_resolution(tmr);
188197
return 0;

sound/core/seq/seq_timer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct snd_seq_timer {
3636

3737
unsigned int skew;
3838
unsigned int skew_base;
39+
unsigned int tempo_base;
3940

4041
struct timespec64 last_update; /* time of last clock update, used for interpolation */
4142

@@ -116,7 +117,8 @@ int snd_seq_timer_stop(struct snd_seq_timer *tmr);
116117
int snd_seq_timer_start(struct snd_seq_timer *tmr);
117118
int snd_seq_timer_continue(struct snd_seq_timer *tmr);
118119
int snd_seq_timer_set_tempo(struct snd_seq_timer *tmr, int tempo);
119-
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq);
120+
int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq,
121+
unsigned int tempo_base);
120122
int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr, snd_seq_tick_time_t position);
121123
int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr, snd_seq_real_time_t position);
122124
int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew, unsigned int base);

0 commit comments

Comments
 (0)