mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
test: Add an example program to create a virtual UMP Endpoint
Provide an example program to demonstrate how to create a UMP Endpoint and Blocks, i.e. a virtual UMP device. It's a simple filtering application that just haves the incoming note on/off velocity and sends out to the output. The UMP Endpoint and Block attributes can be adjusted via command-line options. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
6167b8ce3e
commit
f784035a90
2 changed files with 189 additions and 1 deletions
|
|
@ -1,6 +1,6 @@
|
|||
SUBDIRS=. lsb
|
||||
|
||||
check_PROGRAMS=control pcm pcm_min latency seq \
|
||||
check_PROGRAMS=control pcm pcm_min latency seq seq-ump-example \
|
||||
playmidi1 timer rawmidi midiloop \
|
||||
oldapi queue_timer namehint client_event_filter \
|
||||
chmap audio_time user-ctl-element-set pcm-multi-thread
|
||||
|
|
@ -12,6 +12,7 @@ pcm_min_LDADD=../src/libasound.la
|
|||
latency_LDADD=../src/libasound.la
|
||||
latency_LDFLAGS= -lm
|
||||
seq_LDADD=../src/libasound.la
|
||||
seq_ump_example_LDADD=../src/libasound.la
|
||||
playmidi1_LDADD=../src/libasound.la
|
||||
timer_LDADD=../src/libasound.la
|
||||
rawmidi_LDADD=../src/libasound.la
|
||||
|
|
|
|||
187
test/seq-ump-example.c
Normal file
187
test/seq-ump-example.c
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
// An example program to create a virtual UMP Endpoint
|
||||
//
|
||||
// A client simply reads each UMP packet and sends to subscribers
|
||||
// while the note on/off velocity is halved
|
||||
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alsa/ump_msg.h>
|
||||
|
||||
/* make the note on/off velocity half for MIDI1 CVM */
|
||||
static void midi1_half_note_velocity(snd_seq_ump_event_t *ev)
|
||||
{
|
||||
snd_ump_msg_midi1_t *midi1 = (snd_ump_msg_midi1_t *)ev->ump;
|
||||
|
||||
switch (snd_ump_msg_status(ev->ump)) {
|
||||
case SND_UMP_MSG_NOTE_OFF:
|
||||
case SND_UMP_MSG_NOTE_ON:
|
||||
midi1->note_on.velocity >>= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* make the note on/off velocity half for MIDI2 CVM */
|
||||
static void midi2_half_note_velocity(snd_seq_ump_event_t *ev)
|
||||
{
|
||||
snd_ump_msg_midi2_t *midi2 = (snd_ump_msg_midi2_t *)ev->ump;
|
||||
|
||||
switch (snd_ump_msg_status(ev->ump)) {
|
||||
case SND_UMP_MSG_NOTE_OFF:
|
||||
case SND_UMP_MSG_NOTE_ON:
|
||||
midi2->note_on.velocity >>= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void help(void)
|
||||
{
|
||||
printf("seq-ump-example: Create a virtual UMP Endpoint and Blocks\n"
|
||||
"\n"
|
||||
"Usage: seq-ump-example [OPTIONS]\n"
|
||||
"\n"
|
||||
"-n,--num-blocks blocks Number of blocks (groups) to create\n"
|
||||
"-m,--midi-version version MIDI protocol version (1 or 2)\n"
|
||||
"-N--name UMP Endpoint name string\n"
|
||||
"-P,--product name UMP Product ID string\n"
|
||||
"-M,--manufacturer id UMP Manufacturer ID value (24bit)\n"
|
||||
"-F,--family id UMP Family ID value (16bit)\n"
|
||||
"-O,--model id UMP Model ID value (16bit)\n"
|
||||
"-R,--sw-revision id UMP Software Revision ID (32bit)\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int midi_version = 2;
|
||||
int num_blocks = 1;
|
||||
const char *name = "ACMESynth";
|
||||
const char *product = "Halfmoon";
|
||||
unsigned int manufacturer = 0x123456;
|
||||
unsigned int family = 0x1234;
|
||||
unsigned int model = 0xabcd;
|
||||
unsigned int sw_revision = 0x12345678;
|
||||
snd_seq_t *seq;
|
||||
snd_ump_endpoint_info_t *ep;
|
||||
snd_ump_block_info_t *blk;
|
||||
snd_seq_ump_event_t *ev;
|
||||
int i, c, err;
|
||||
unsigned char tmp[4];
|
||||
|
||||
static const struct option long_option[] = {
|
||||
{"num-blocks", required_argument, 0, 'n'},
|
||||
{"midi-version", required_argument, 0, 'm'},
|
||||
{"name", required_argument, 0, 'N'},
|
||||
{"product", required_argument, 0, 'P'},
|
||||
{"manufacturer", required_argument, 0, 'M'},
|
||||
{"family", required_argument, 0, 'F'},
|
||||
{"model", required_argument, 0, 'O'},
|
||||
{"sw-revision", required_argument, 0, 'R'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, "n:m:N:P:M:F:O:R:",
|
||||
long_option, NULL)) >= 0) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
num_blocks = atoi(optarg);
|
||||
break;
|
||||
case 'm':
|
||||
midi_version = atoi(optarg);
|
||||
break;
|
||||
case 'N':
|
||||
name = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
product = optarg;
|
||||
break;
|
||||
case 'M':
|
||||
manufacturer = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'F':
|
||||
family = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'O':
|
||||
model = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
case 'R':
|
||||
sw_revision = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
help();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
err = snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "failed to open sequencer: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
snd_ump_endpoint_info_alloca(&ep);
|
||||
snd_ump_endpoint_info_set_name(ep, name);
|
||||
snd_ump_endpoint_info_set_product_id(ep, product);
|
||||
if (midi_version == 1) {
|
||||
snd_ump_endpoint_info_set_protocol_caps(ep, SND_UMP_EP_INFO_PROTO_MIDI1);
|
||||
snd_ump_endpoint_info_set_protocol(ep, SND_UMP_EP_INFO_PROTO_MIDI1);
|
||||
} else {
|
||||
snd_ump_endpoint_info_set_protocol_caps(ep, SND_UMP_EP_INFO_PROTO_MIDI2);
|
||||
snd_ump_endpoint_info_set_protocol(ep, SND_UMP_EP_INFO_PROTO_MIDI2);
|
||||
}
|
||||
snd_ump_endpoint_info_set_num_blocks(ep, num_blocks);
|
||||
snd_ump_endpoint_info_set_manufacturer_id(ep, manufacturer);
|
||||
snd_ump_endpoint_info_set_family_id(ep, family);
|
||||
snd_ump_endpoint_info_set_model_id(ep, model);
|
||||
for (i = 0; i < 4; i++)
|
||||
tmp[i] = (sw_revision >> ((3 - i) * 8)) & 0xff;
|
||||
snd_ump_endpoint_info_set_sw_revision(ep, tmp);
|
||||
|
||||
err = snd_seq_create_ump_endpoint(seq, ep, num_blocks);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "failed to set UMP EP info: %d\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
snd_ump_block_info_alloca(&blk);
|
||||
|
||||
for (i = 0; i < num_blocks; i++) {
|
||||
char blkname[32];
|
||||
|
||||
sprintf(blkname, "Filter %d", i + 1);
|
||||
snd_ump_block_info_set_name(blk, blkname);
|
||||
snd_ump_block_info_set_direction(blk, SND_UMP_DIR_BIDIRECTION);
|
||||
snd_ump_block_info_set_first_group(blk, i);
|
||||
snd_ump_block_info_set_num_groups(blk, 1);
|
||||
snd_ump_block_info_set_ui_hint(blk, SND_UMP_BLOCK_UI_HINT_BOTH);
|
||||
|
||||
err = snd_seq_create_ump_block(seq, i, blk);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "failed to set UMP block info %d: %d\n",
|
||||
i, err);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* halve the incoming note-on / off velocity and pass through
|
||||
* to subscribers
|
||||
*/
|
||||
while (snd_seq_ump_event_input(seq, &ev) >= 0) {
|
||||
if (!snd_seq_ev_is_ump(ev))
|
||||
continue;
|
||||
switch (snd_ump_msg_type(ev->ump)) {
|
||||
case SND_UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE:
|
||||
midi1_half_note_velocity(ev);
|
||||
break;
|
||||
case SND_UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE:
|
||||
midi2_half_note_velocity(ev);
|
||||
break;
|
||||
}
|
||||
|
||||
snd_seq_ev_set_subs(ev);
|
||||
snd_seq_ev_set_direct(ev);
|
||||
snd_seq_ump_event_output(seq, ev);
|
||||
snd_seq_drain_output(seq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue