History

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.

Takashi Iwai committed 2 years ago

Commit fefbbdf1 parent a892b705 files · +30 −12Browse files

Unified · Split

5 files
  1. include/uapi/sound/asequencer.h +4 −3
  2. sound/core/seq/seq_clientmgr.c +4 −0
  3. sound/core/seq/seq_queue.c +4 −2
  4. sound/core/seq/seq_timer.c +15 −6
  5. sound/core/seq/seq_timer.h +3 −1
include/uapi/sound/asequencer.h+4−3
@@ -10,7 +10,7 @@ · 9 unmodified lines
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 { · 506 unmodified lines
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+4−0
@@ -1718,6 +1718,8 @@ static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client, · 1717 unmodified lines
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, · 15 unmodified lines
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+4−2
@@ -460,7 +460,8 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client, · 459 unmodified lines
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, · 257 unmodified lines
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, · 10 unmodified lines
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+15−6
@@ -20,14 +20,17 @@ · 19 unmodified lines
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) · 45 unmodified lines
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,8 +168,9 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) · 79 unmodified lines
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
@@ -173,6 +178,9 @@ int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq) · 1 unmodified line
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) · 4 unmodified lines
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+3−1
@@ -36,6 +36,7 @@ struct snd_seq_timer { · 35 unmodified lines
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); · 74 unmodified lines
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);