Skip to content

Commit

Permalink
ALSA: seq: Automatic conversion of UMP events
Browse files Browse the repository at this point in the history
This patch enables the automatic conversion of UMP events from/to the
legacy ALSA sequencer MIDI events.  Also, as UMP itself has two
different modes (MIDI 1.0 and MIDI 2.0), yet another converters
between them are needed, too.  Namely, we have conversions between the
legacy and UMP like:
  - seq legacy event -> seq UMP MIDI 1.0 event
  - seq legacy event -> seq UMP MIDI 2.0 event
  - seq UMP MIDI 1.0 event -> seq legacy event
  - seq UMP MIDI 2.0 event -> seq legacy event

and the conversions between UMP MIDI 1.0 and 2.0 clients like:
  - seq UMP MIDI 1.0 event -> seq UMP MIDI 2.0 event
  - seq UMP MIDI 2.0 event -> seq UMP MIDI 1.0 event

The translation is per best-effort; some MIDI 2.0 specific events are
ignored when translated to MIDI 1.0.

Reviewed-by: Jaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20230523075358.9672-31-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed May 23, 2023
1 parent a3ca3b3 commit e9e0281
Show file tree
Hide file tree
Showing 7 changed files with 1,279 additions and 14 deletions.
2 changes: 2 additions & 0 deletions sound/core/seq/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,7 @@ config SND_SEQ_UMP
Say Y here to enable the support for handling UMP (Universal MIDI
Packet) events via ALSA sequencer infrastructure, which is an
essential feature for enabling MIDI 2.0 support.
It includes the automatic conversion of ALSA sequencer events
among legacy and UMP clients.

endif # SND_SEQUENCER
1 change: 1 addition & 0 deletions sound/core/seq/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
seq_fifo.o seq_prioq.o seq_timer.o \
seq_system.o seq_ports.o
snd-seq-$(CONFIG_SND_PROC_FS) += seq_info.o
snd-seq-$(CONFIG_SND_SEQ_UMP) += seq_ump_convert.o
snd-seq-midi-objs := seq_midi.o
snd-seq-midi-emul-objs := seq_midi_emul.o
snd-seq-midi-event-objs := seq_midi_event.o
Expand Down
48 changes: 34 additions & 14 deletions sound/core/seq/seq_clientmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "seq_timer.h"
#include "seq_info.h"
#include "seq_system.h"
#include "seq_ump_convert.h"
#include <sound/seq_device.h>
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
Expand Down Expand Up @@ -612,6 +613,27 @@ static int update_timestamp_of_queue(struct snd_seq_event *event,
return 1;
}

/* deliver a single event; called from below and UMP converter */
int __snd_seq_deliver_single_event(struct snd_seq_client *dest,
struct snd_seq_client_port *dest_port,
struct snd_seq_event *event,
int atomic, int hop)
{
switch (dest->type) {
case USER_CLIENT:
if (!dest->data.user.fifo)
return 0;
return snd_seq_fifo_event_in(dest->data.user.fifo, event);
case KERNEL_CLIENT:
if (!dest_port->event_input)
return 0;
return dest_port->event_input(event,
snd_seq_ev_is_direct(event),
dest_port->private_data,
atomic, hop);
}
return 0;
}

/*
* deliver an event to the specified destination.
Expand Down Expand Up @@ -648,22 +670,20 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
update_timestamp_of_queue(event, dest_port->time_queue,
dest_port->time_real);

switch (dest->type) {
case USER_CLIENT:
if (dest->data.user.fifo)
result = snd_seq_fifo_event_in(dest->data.user.fifo, event);
break;
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
if (snd_seq_ev_is_ump(event)) {
result = snd_seq_deliver_from_ump(client, dest, dest_port,
event, atomic, hop);
goto __skip;
} else if (snd_seq_client_is_ump(dest)) {
result = snd_seq_deliver_to_ump(client, dest, dest_port,
event, atomic, hop);
goto __skip;
}
#endif /* CONFIG_SND_SEQ_UMP */

case KERNEL_CLIENT:
if (dest_port->event_input == NULL)
break;
result = dest_port->event_input(event, direct,
dest_port->private_data,
result = __snd_seq_deliver_single_event(dest, dest_port, event,
atomic, hop);
break;
default:
break;
}

__skip:
if (dest_port)
Expand Down
15 changes: 15 additions & 0 deletions sound/core/seq/seq_clientmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table
int snd_seq_client_notify_subscription(int client, int port,
struct snd_seq_port_subscribe *info, int evtype);

int __snd_seq_deliver_single_event(struct snd_seq_client *dest,
struct snd_seq_client_port *dest_port,
struct snd_seq_event *event,
int atomic, int hop);

/* only for OSS sequencer */
bool snd_seq_client_ioctl_lock(int clientid);
void snd_seq_client_ioctl_unlock(int clientid);
Expand All @@ -95,4 +100,14 @@ extern int seq_client_load[15];
struct snd_seq_client *snd_seq_kernel_client_get(int client);
void snd_seq_kernel_client_put(struct snd_seq_client *cptr);

static inline bool snd_seq_client_is_ump(struct snd_seq_client *c)
{
return c->midi_version != SNDRV_SEQ_CLIENT_LEGACY_MIDI;
}

static inline bool snd_seq_client_is_midi2(struct snd_seq_client *c)
{
return c->midi_version == SNDRV_SEQ_CLIENT_UMP_MIDI_2_0;
}

#endif
15 changes: 15 additions & 0 deletions sound/core/seq/seq_ports.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ struct snd_seq_port_subs_info {
int (*close)(void *private_data, struct snd_seq_port_subscribe *info);
};

/* context for converting from legacy control event to UMP packet */
struct snd_seq_ump_midi2_bank {
bool rpn_set;
bool nrpn_set;
bool bank_set;
unsigned char cc_rpn_msb, cc_rpn_lsb;
unsigned char cc_nrpn_msb, cc_nrpn_lsb;
unsigned char cc_data_msb, cc_data_lsb;
unsigned char cc_bank_msb, cc_bank_lsb;
};

struct snd_seq_client_port {

struct snd_seq_addr addr; /* client/port number */
Expand Down Expand Up @@ -75,6 +86,10 @@ struct snd_seq_client_port {
/* UMP direction and group */
unsigned char direction;
unsigned char ump_group;

#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
struct snd_seq_ump_midi2_bank midi2_bank[16]; /* per channel */
#endif
};

struct snd_seq_client;
Expand Down
Loading

0 comments on commit e9e0281

Please sign in to comment.