From patchwork Sat May 20 07:07:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13249122 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 306A8C77B7F for ; Sat, 20 May 2023 07:09:13 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id B7211741; Sat, 20 May 2023 09:08:20 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz B7211741 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684566550; bh=PdIT3ICYqNGge9juKk0xy9KBjouHa4s+LE42qIw2DPE=; h=From:To:Subject:Date:In-Reply-To:References:List-Id:List-Archive: List-Help:List-Owner:List-Post:List-Subscribe:List-Unsubscribe: From; b=JpU8FrNfMbE5VVzmmE3DMKU0VyfXIzr+zWc2oV4p69WXVACPsb9LNZnkVFNlvHnEp 12KGu8y8hDRi8Q9xOSidSDebmSO3Pz6xyiF6+Acx6i7hfwCSnVdixDIfZP8Kx093UZ 9vnqgDRhfpqQspiE2NBL9LeG6aS+4mSAY+AMXXwk= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 84D64F80431; Sat, 20 May 2023 09:07:53 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 86568F8053D; Sat, 20 May 2023 09:07:52 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id D9FE5F8053D; Sat, 20 May 2023 09:07:48 +0200 (CEST) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 173FEF8025A for ; Sat, 20 May 2023 09:07:43 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 173FEF8025A Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=VjlWXb4G; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=RfkEE+50 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id A867E220DA; Sat, 20 May 2023 07:07:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684566463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CnS5D+lKrd9D8rcuWQ0Jp7SYxA3HGPJ480QzqEcnpQA=; b=VjlWXb4GSIWndpH1SHzp067IofacReWUEGFUlOfjRGWT2mBLn9ifQFFHyUkZSLMAN4TV+d r20j7ASpUKHhecPlv6msBLPalX4Y9eESp92v5j05VSQpgbSZNPjYeH0z6YRgl/HYFUxX0P /CSz9uRbtM0qjEc9khj0CgnTHQpDHow= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684566463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CnS5D+lKrd9D8rcuWQ0Jp7SYxA3HGPJ480QzqEcnpQA=; b=RfkEE+50WI78NnQI7G3mP34h/MDY1u1k3DNSt4/3mretUWfF68mde6IRia2lxcCDOjDjys N6TgpLMTbppBakBQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 88595139F5; Sat, 20 May 2023 07:07:43 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id AFCAIL9xaGRrHgAAMHmgww (envelope-from ); Sat, 20 May 2023 07:07:43 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Subject: [PATCH alsa-utils 1/3] aseqdump: Add UMP support Date: Sat, 20 May 2023 09:07:36 +0200 Message-Id: <20230520070738.8382-2-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230520070738.8382-1-tiwai@suse.de> References: <20230520070738.8382-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: 4HCMEDA7L5XZSSM3ETQLIUDXCNCS7LJP X-Message-ID-Hash: 4HCMEDA7L5XZSSM3ETQLIUDXCNCS7LJP X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add the support for showing the UMP events to aseqdump. With the new option -u, the program can start as a UMP sequencer client and receive UMP events instead of the legacy MIDI events. Also, the automatic event conversion among legacy and UMP clients can be suppressed by the new -r option, too. Signed-off-by: Takashi Iwai --- configure.ac | 4 + seq/aseqdump/aseqdump.1 | 9 ++ seq/aseqdump/aseqdump.c | 211 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 219 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index e079e241aa29..2ce8a62c585c 100644 --- a/configure.ac +++ b/configure.ac @@ -54,6 +54,10 @@ AC_CHECK_LIB([asound], [snd_seq_client_info_get_pid], [HAVE_SEQ_CLIENT_INFO_GET_ if test "$HAVE_SEQ_CLIENT_INFO_GET_PID" = "yes" ; then AC_DEFINE([HAVE_SEQ_CLIENT_INFO_GET_PID], 1, [alsa-lib supports snd_seq_client_info_get_pid]) fi +AC_CHECK_LIB([asound], [snd_seq_client_info_get_midi_version], [HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION="yes"]) +if test "$HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION" = "yes" ; then + AC_DEFINE([HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION], 1, [alsa-lib supports snd_seq_client_info_get_midi_version]) +fi AC_CHECK_LIB([atopology], [snd_tplg_save], [have_topology="yes"], [have_topology="no"]) # diff --git a/seq/aseqdump/aseqdump.1 b/seq/aseqdump/aseqdump.1 index f6f2aa9cb12b..6f7904159b90 100644 --- a/seq/aseqdump/aseqdump.1 +++ b/seq/aseqdump/aseqdump.1 @@ -27,6 +27,15 @@ Prints the current version. .I \-l,\-\-list Prints a list of possible input ports. +.TP +.I \-u,\-\-ump=version +Sets the client MIDI version. +0 is for legacy mode, 1 is UMP MIDI 1.0 mode, and 2 is UMP MIDI 2.0 mode. + +.TP +.I \-r,\-\-raw +Suppress the automatic conversion of events among UMP and legacy clients. + .TP .I \-p,\-\-port=client:port,... Sets the sequencer port(s) from which events are received. diff --git a/seq/aseqdump/aseqdump.c b/seq/aseqdump/aseqdump.c index 44ae3bbc5654..1fee0430f9b3 100644 --- a/seq/aseqdump/aseqdump.c +++ b/seq/aseqdump/aseqdump.c @@ -29,12 +29,19 @@ #include #include "aconfig.h" #include "version.h" +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION +#include +#endif static snd_seq_t *seq; static int port_count; static snd_seq_addr_t *ports; static volatile sig_atomic_t stop = 0; - +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION +static int ump_version; +#else +#define ump_version 0 +#endif /* prints an error message to stderr, and dies */ static void fatal(const char *msg, ...) @@ -131,6 +138,7 @@ static void connect_ports(void) static void dump_event(const snd_seq_event_t *ev) { printf("%3d:%-3d ", ev->source.client, ev->source.port); + switch (ev->type) { case SND_SEQ_EVENT_NOTEON: if (ev->data.note.velocity) @@ -297,6 +305,165 @@ static void dump_event(const snd_seq_event_t *ev) } } +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION +static void dump_ump_midi1_event(const unsigned int *ump) +{ + const snd_ump_msg_midi1_t *m = (const snd_ump_msg_midi1_t *)ump; + unsigned char group = m->hdr.group; + unsigned char status = m->hdr.status; + unsigned char channel = m->hdr.channel; + + printf("Group %2d, ", group); + switch (status) { + case SND_UMP_MSG_NOTE_OFF: + printf("Note off %2d, note %d, velocity 0x%x", + channel, m->note_off.note, m->note_off.velocity); + break; + case SND_UMP_MSG_NOTE_ON: + printf("Note on %2d, note %d, velocity 0x%x", + channel, m->note_off.note, m->note_off.velocity); + break; + case SND_UMP_MSG_POLY_PRESSURE: + printf("Poly pressure %2d, note %d, value 0x%x", + channel, m->poly_pressure.note, m->poly_pressure.data); + break; + case SND_UMP_MSG_CONTROL_CHANGE: + printf("Control change %2d, controller %d, value 0x%x", + channel, m->control_change.index, m->control_change.data); + break; + case SND_UMP_MSG_PROGRAM_CHANGE: + printf("Program change %2d, program %d", + channel, m->program_change.program); + case SND_UMP_MSG_CHANNEL_PRESSURE: + printf("Channel pressure %2d, value 0x%x", + channel, m->channel_pressure.data); + break; + case SND_UMP_MSG_PITCHBEND: + printf("Pitchbend %2d, value 0x%x", + channel, (m->pitchbend.data_msb << 7) | m->pitchbend.data_lsb); + break; + default: + printf("UMP MIDI1 event: status = %d, channel = %d, 0x%08x", + status, channel, *ump); + break; + } + printf("\n"); +} + +static void dump_ump_midi2_event(const unsigned int *ump) +{ + const snd_ump_msg_midi2_t *m = (const snd_ump_msg_midi2_t *)ump; + unsigned char group = m->hdr.group; + unsigned char status = m->hdr.status; + unsigned char channel = m->hdr.channel; + unsigned int bank; + + printf("Group %2d, ", group); + switch (status) { + case SND_UMP_MSG_PER_NOTE_RCC: + printf("Per-note RCC %2u, note %u, index %u, value 0x%x", + channel, m->per_note_rcc.note, + m->per_note_rcc.index, m->per_note_rcc.data); + break; + case SND_UMP_MSG_PER_NOTE_ACC: + printf("Per-note ACC %2u, note %u, index %u, value 0x%x", + channel, m->per_note_acc.note, + m->per_note_acc.index, m->per_note_acc.data); + break; + case SND_UMP_MSG_RPN: + printf("RPN %2u, bank %u:%u, value 0x%x", + channel, m->rpn.bank, m->rpn.index, m->rpn.data); + break; + case SND_UMP_MSG_NRPN: + printf("NRPN %2u, bank %u:%u, value 0x%x", + channel, m->rpn.bank, m->rpn.index, m->rpn.data); + break; + case SND_UMP_MSG_RELATIVE_RPN: + printf("relative RPN %2u, bank %u:%u, value 0x%x", + channel, m->rpn.bank, m->rpn.index, m->rpn.data); + break; + case SND_UMP_MSG_RELATIVE_NRPN: + printf("relative NRP %2u, bank %u:%u, value 0x%x", + channel, m->rpn.bank, m->rpn.index, m->rpn.data); + break; + case SND_UMP_MSG_PER_NOTE_PITCHBEND: + printf("Per-note pitchbend %2d, note %d, value 0x%x", + channel, m->per_note_pitchbend.note, + m->per_note_pitchbend.data); + break; + case SND_UMP_MSG_NOTE_OFF: + printf("Note off %2d, note %d, velocity 0x%x, attr type = %d, data = 0x%x", + channel, m->note_off.note, m->note_off.velocity, + m->note_off.attr_type, m->note_off.attr_data); + break; + case SND_UMP_MSG_NOTE_ON: + printf("Note on %2d, note %d, velocity 0x%x, attr type = %d, data = 0x%x", + channel, m->note_off.note, m->note_off.velocity, + m->note_off.attr_type, m->note_off.attr_data); + break; + case SND_UMP_MSG_POLY_PRESSURE: + printf("Poly pressure %2d, note %d, value 0x%x", + channel, m->poly_pressure.note, m->poly_pressure.data); + break; + case SND_UMP_MSG_CONTROL_CHANGE: + printf("Control change %2d, controller %d, value 0x%x", + channel, m->control_change.index, m->control_change.data); + break; + case SND_UMP_MSG_PROGRAM_CHANGE: + printf("Program change %2d, program %d", + channel, m->program_change.program); + if (m->program_change.bank_valid) + printf(", Bank select %d:%d", + m->program_change.bank_msb, + m->program_change.bank_lsb); + break; + case SND_UMP_MSG_CHANNEL_PRESSURE: + printf("Channel pressure %2d, value 0x%x", + channel, m->channel_pressure.data); + break; + case SND_UMP_MSG_PITCHBEND: + printf("Channel pressure %2d, value 0x%x", + channel, m->channel_pressure.data); + break; + case SND_UMP_MSG_PER_NOTE_MGMT: + printf("Per-note management %2d, value 0x%x", + channel, m->per_note_mgmt.flags); + break; + default: + printf("UMP MIDI2 event: status = %d, channel = %x, 0x%08x", + status, status, *ump); + break; + } + printf("\n"); +} + +static void dump_ump_event(const snd_seq_ump_event_t *ev) +{ + if (!snd_seq_ev_is_ump(ev)) { + dump_event((const snd_seq_event_t *)ev); + return; + } + + printf("%3d:%-3d ", ev->source.client, ev->source.port); + + switch (snd_ump_msg_type(ev->ump)) { + case SND_UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE: + dump_ump_midi1_event(ev->ump); + break; + case SND_UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE: + dump_ump_midi2_event(ev->ump); + break; + default: + printf("UMP event: type = %d, group = %d, status = %d, 0x%08x\n", + snd_ump_msg_type(ev->ump), + snd_ump_msg_group(ev->ump), + snd_ump_msg_status(ev->ump), + *ev->ump); + break; + } +} +#endif /* HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION */ + static void list_ports(void) { snd_seq_client_info_t *cinfo; @@ -335,6 +502,10 @@ static void help(const char *argv0) " -h,--help this help\n" " -V,--version show version\n" " -l,--list list input ports\n" +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + " -u,--ump=version set client MIDI version (0=legacy, 1= UMP MIDI 1.0, 2=UMP MIDI2.0)\n" + " -r,--raw do not convert UMP and legacy events\n" +#endif " -p,--port=client:port,... source port(s)\n", argv0); } @@ -351,12 +522,20 @@ static void sighandler(int sig) int main(int argc, char *argv[]) { - static const char short_options[] = "hVlp:"; + static const char short_options[] = "hVlp:" +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + "u:r" +#endif + ; static const struct option long_options[] = { {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, {"list", 0, NULL, 'l'}, {"port", 1, NULL, 'p'}, +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + {"ump", 1, NULL, 'u'}, + {"raw", 0, NULL, 'r'}, +#endif {0} }; @@ -382,6 +561,15 @@ int main(int argc, char *argv[]) case 'p': parse_ports(optarg); break; +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + case 'u': + ump_version = atoi(optarg); + snd_seq_set_client_midi_version(seq, ump_version); + break; + case 'r': + snd_seq_set_client_ump_conversion(seq, 0); + break; +#endif default: help(argv[0]); return 1; @@ -409,7 +597,8 @@ int main(int argc, char *argv[]) printf("Waiting for data at port %d:0.", snd_seq_client_id(seq)); printf(" Press Ctrl+C to end.\n"); - printf("Source Event Ch Data\n"); + printf("Source %sEvent Ch Data\n", + ump_version ? "Group " : ""); signal(SIGINT, sighandler); signal(SIGTERM, sighandler); @@ -420,14 +609,26 @@ int main(int argc, char *argv[]) snd_seq_poll_descriptors(seq, pfds, npfds, POLLIN); if (poll(pfds, npfds, -1) < 0) break; - do { + for (;;) { snd_seq_event_t *event; +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + snd_seq_ump_event_t *ump_ev; + if (ump_version > 0) { + err = snd_seq_ump_event_input(seq, &ump_ev); + if (err < 0) + break; + if (ump_ev) + dump_ump_event(ump_ev); + continue; + } +#endif + err = snd_seq_event_input(seq, &event); if (err < 0) break; if (event) dump_event(event); - } while (err > 0); + } fflush(stdout); if (stop) break; From patchwork Sat May 20 07:07:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13249125 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 804C7C77B7D for ; Sat, 20 May 2023 07:10:04 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id D577D828; Sat, 20 May 2023 09:09:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz D577D828 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684566601; bh=NxSiUWCClPE6FOHgmhvLq9UswJT93RsbEk2w6BlWz6Y=; h=From:To:Subject:Date:In-Reply-To:References:List-Id:List-Archive: List-Help:List-Owner:List-Post:List-Subscribe:List-Unsubscribe: From; b=RNT/fSr/36SKYb4q+5SDExUg9Qn88h7WaZtyuMWxrp/O4I7P6cABZsUtIG9CWFxFW vOvp1GYNy/+sXIamWnswPQihgTGvs6bfbfBjaChwDXGrA3z5dTFD7e7dICTso1PXcF kVf3c46nvTfZfgPkMDsq2J18K7RBvVRmhJOiXpcg= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 0B995F80580; Sat, 20 May 2023 09:08:01 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 832BAF80580; Sat, 20 May 2023 09:08:01 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id AA939F80567; Sat, 20 May 2023 09:07:55 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [IPv6:2001:67c:2178:6::1d]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 03784F8016A for ; Sat, 20 May 2023 09:07:43 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 03784F8016A Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=qTV66kA7; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=N1ZNCbT4 Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id CA7411FE3F; Sat, 20 May 2023 07:07:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684566463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nTRWhH+7Eaa22PZpsKS0R+NBeYTa6L4FPvhAgcjfX6E=; b=qTV66kA7NE3Ze2sIcaW0XKmyxA6S407o0qw3n0z4v2M2V8Nzqz/IQUhbMt+gfA4wxfNHzk 1Hip/vEJU+jyCMlacrMGsC6W1s80Vhm/DntubhurJFPcl/Yd8+wNsiT/zIDsyq8P2R44sk dp6QC6HjDJRHSyRohhrI7OTQqFEyVRg= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684566463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=nTRWhH+7Eaa22PZpsKS0R+NBeYTa6L4FPvhAgcjfX6E=; b=N1ZNCbT4hCZkASk9aY0d6CT5FZiGDhToIguLWK0FEwRoiS59XrsWmvRZbYXtNiEyz2J7qQ uKOQztToLBNNyvBQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id AC420134F5; Sat, 20 May 2023 07:07:43 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id cCIXKb9xaGRrHgAAMHmgww (envelope-from ); Sat, 20 May 2023 07:07:43 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Subject: [PATCH alsa-utils 2/3] aconnect: Add UMP support Date: Sat, 20 May 2023 09:07:37 +0200 Message-Id: <20230520070738.8382-3-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230520070738.8382-1-tiwai@suse.de> References: <20230520070738.8382-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: PNBWMBTXNHKP3SLZB7BB6J4K66Q2N2WD X-Message-ID-Hash: PNBWMBTXNHKP3SLZB7BB6J4K66Q2N2WD X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: This patch extends the aconnect program for supporting UMP. Now the verbose output can show the UMP client version. Also, a new option -a is added to control the behavior whether to show the all ports including the inactive ports or not. As default, only the active ports are shown, but UMP clients allow to hide some ports as inactive. Signed-off-by: Takashi Iwai --- seq/aconnect/aconnect.1 | 3 ++ seq/aconnect/aconnect.c | 91 +++++++++++++++++++++++++++++++++-------- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/seq/aconnect/aconnect.1 b/seq/aconnect/aconnect.1 index 2050187a3362..5c015196f19c 100644 --- a/seq/aconnect/aconnect.1 +++ b/seq/aconnect/aconnect.1 @@ -120,6 +120,9 @@ List existing output (writable) ports. This option is exclusive to .B \-i. .TP +.B \-a, \-\-all +List inactive ports, too. +.TP .B \-l, \-\-list List the current connection status. The connected and connecting ports from/to each port are listed together. diff --git a/seq/aconnect/aconnect.c b/seq/aconnect/aconnect.c index 85a7770156aa..582b454c2c22 100644 --- a/seq/aconnect/aconnect.c +++ b/seq/aconnect/aconnect.c @@ -29,6 +29,13 @@ #include "aconfig.h" #include "gettext.h" +#ifdef SND_SEQ_PORT_CAP_INACTIVE +#define HANDLE_SHOW_ALL +static int show_all; +#else +#define show_all 0 +#endif + static void error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...) { va_list arg; @@ -60,6 +67,9 @@ static void usage(void) printf(_(" aconnect -i|-o [-options]\n")); printf(_(" -i,--input list input (readable) ports\n")); printf(_(" -o,--output list output (writable) ports\n")); +#ifdef HANDLE_SHOW_ALL + printf(_(" -a,--all show inactive ports, too\n")); +#endif printf(_(" -l,--list list current connections of each port\n")); printf(_(" * Remove all exported connections\n")); printf(_(" -x, --removeall\n")); @@ -72,25 +82,38 @@ static void usage(void) #define LIST_INPUT 1 #define LIST_OUTPUT 2 -#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits)) +#define perm_ok(cap,bits) (((cap) & (bits)) == (bits)) + +#ifdef SND_SEQ_PORT_DIR_INPUT +static int check_direction(snd_seq_port_info_t *pinfo, int bit) +{ + int dir = snd_seq_port_info_get_direction(pinfo); + return !dir || (dir & bit); +} +#else +#define check_direction(x, y) 1 +#endif static int check_permission(snd_seq_port_info_t *pinfo, int perm) { - if (perm) { - if (perm & LIST_INPUT) { - if (perm_ok(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ)) - goto __ok; - } - if (perm & LIST_OUTPUT) { - if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) - goto __ok; - } + int cap = snd_seq_port_info_get_capability(pinfo); + + if (cap & SND_SEQ_PORT_CAP_NO_EXPORT) return 0; + + if (!perm) + return 1; + if (perm & LIST_INPUT) { + if (perm_ok(cap, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ) && + check_direction(pinfo, SND_SEQ_PORT_DIR_INPUT)) + return 1; } - __ok: - if (snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT) - return 0; - return 1; + if (perm & LIST_OUTPUT) { + if (perm_ok(cap, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE) && + check_direction(pinfo, SND_SEQ_PORT_DIR_OUTPUT)) + return 1; + } + return 0; } /* @@ -151,12 +174,20 @@ static void do_search_port(snd_seq_t *seq, int perm, action_func_t do_action) /* reset query info */ snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); snd_seq_port_info_set_port(pinfo, -1); +#ifdef HANDLE_SHOW_ALL + if (show_all) + snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_INACTIVE); +#endif count = 0; while (snd_seq_query_next_port(seq, pinfo) >= 0) { if (check_permission(pinfo, perm)) { do_action(seq, cinfo, pinfo, count); count++; } +#ifdef HANDLE_SHOW_ALL + if (show_all) + snd_seq_port_info_set_capability(pinfo, SND_SEQ_PORT_CAP_INACTIVE); +#endif } } } @@ -173,7 +204,20 @@ static void print_port(snd_seq_t *seq, snd_seq_client_info_t *cinfo, snd_seq_client_info_get_name(cinfo), (snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ? _("user") : _("kernel"))); - +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + switch (snd_seq_client_info_get_midi_version(cinfo)) { + case SND_SEQ_CLIENT_UMP_MIDI_1_0: + printf(",UMP-MIDI1"); + break; + case SND_SEQ_CLIENT_UMP_MIDI_2_0: + printf(",UMP-MIDI2"); + break; + } +#endif +#ifdef HANDLE_SHOW_ALL + if (snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_INACTIVE) + printf(",INACTIVE"); +#endif #ifdef HAVE_SEQ_CLIENT_INFO_GET_CARD card = snd_seq_client_info_get_card(cinfo); #endif @@ -251,6 +295,12 @@ enum { SUBSCRIBE, UNSUBSCRIBE, LIST, REMOVE_ALL }; +#ifdef HANDLE_SHOW_ALL +#define ACONNECT_OPTS "dior:t:elxa" +#else +#define ACONNECT_OPTS "dior:t:elx" +#endif + static const struct option long_option[] = { {"disconnect", 0, NULL, 'd'}, {"input", 0, NULL, 'i'}, @@ -260,6 +310,9 @@ static const struct option long_option[] = { {"exclusive", 0, NULL, 'e'}, {"list", 0, NULL, 'l'}, {"removeall", 0, NULL, 'x'}, +#ifdef HANDLE_SHOW_ALL + {"all", 0, NULL, 'a'}, +#endif {NULL, 0, NULL, 0}, }; @@ -280,7 +333,7 @@ int main(int argc, char **argv) textdomain(PACKAGE); #endif - while ((c = getopt_long(argc, argv, "dior:t:elx", long_option, NULL)) != -1) { + while ((c = getopt_long(argc, argv, ACONNECT_OPTS, long_option, NULL)) != -1) { switch (c) { case 'd': command = UNSUBSCRIBE; @@ -313,6 +366,12 @@ int main(int argc, char **argv) case 'x': command = REMOVE_ALL; break; +#ifdef HANDLE_SHOW_ALL + case 'a': + command = LIST; + show_all = 1; + break; +#endif default: usage(); exit(1); From patchwork Sat May 20 07:07:38 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 13249124 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3894BC77B7D for ; Sat, 20 May 2023 07:09:51 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id DE71A847; Sat, 20 May 2023 09:08:58 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz DE71A847 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1684566589; bh=9cbzx5jjRyhcs8SdY4WG5UaeSTFSmwuawEcXx4uqBXI=; h=From:To:Subject:Date:In-Reply-To:References:List-Id:List-Archive: List-Help:List-Owner:List-Post:List-Subscribe:List-Unsubscribe: From; b=LXA+hPg8+38TBY3/lrJCTfM6J8/n+91YHai5hW3dbrwpsKwao8iR0zHEyiCZCYdv8 ddxyZVsvsBW0V0IALGiRzSy5jLbm7B1Fae3QHjq9aPk/k+Az+DXVXk0k+Yk+pFuCV8 FxGXMqdvuQANlYA+uqMBw+YBvNhU2SWpFX0mT8ok= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 08848F8016A; Sat, 20 May 2023 09:07:58 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 756A7F8016A; Sat, 20 May 2023 09:07:57 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 573C8F80272; Sat, 20 May 2023 09:07:53 +0200 (CEST) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 71617F80272 for ; Sat, 20 May 2023 09:07:44 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 71617F80272 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=suse.de header.i=@suse.de header.a=rsa-sha256 header.s=susede2_rsa header.b=eEI18KTd; dkim=pass header.d=suse.de header.i=@suse.de header.a=ed25519-sha256 header.s=susede2_ed25519 header.b=3L5RAQqm Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id F0A161FE41; Sat, 20 May 2023 07:07:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1684566463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ttLvM6U4JAocI3YT1PumrSnqT9uSUna1NmRHRI11Wbc=; b=eEI18KTdOgWxP/TI9cYPOMghChTg9eDc80ZzAyy3+cgG2YkXD6uFDbHSaeoGlWWbCIzBpm gU/F676VDR5RzMIjD24vTOHLrPK7nf4fTRvfxkBSYhlNn2r5RpR/95RIc20g9aXHpvB17z roNC2VlyqLXumpEXA825dc1TtHUfkfE= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1684566463; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ttLvM6U4JAocI3YT1PumrSnqT9uSUna1NmRHRI11Wbc=; b=3L5RAQqmsKUh7zJTjT0TgiTm+VcXEBMiaiFKTmvu6AZMA7E+2x1lqvHCkOP+/tY5fkyjma PaFWObf+S1qKp6BQ== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id CE195139F5; Sat, 20 May 2023 07:07:43 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 6ElvMb9xaGRrHgAAMHmgww (envelope-from ); Sat, 20 May 2023 07:07:43 +0000 From: Takashi Iwai To: alsa-devel@alsa-project.org Subject: [PATCH alsa-utils 3/3] aplaymidi: Add UMP support Date: Sat, 20 May 2023 09:07:38 +0200 Message-Id: <20230520070738.8382-4-tiwai@suse.de> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230520070738.8382-1-tiwai@suse.de> References: <20230520070738.8382-1-tiwai@suse.de> MIME-Version: 1.0 Message-ID-Hash: TK47PYBF5K3NCUUXTPJXF6VFMDZRIXKL X-Message-ID-Hash: TK47PYBF5K3NCUUXTPJXF6VFMDZRIXKL X-MailFrom: tiwai@suse.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: By switching via the new option -u, aplaymidi can behave as a UMP client and output UMP packets instead of legacy sequencer events. As of now, the only supported version is 1. Signed-off-by: Takashi Iwai --- seq/aplaymidi/aplaymidi.1 | 6 ++ seq/aplaymidi/aplaymidi.c | 216 ++++++++++++++++++++++++++++++-------- 2 files changed, 181 insertions(+), 41 deletions(-) diff --git a/seq/aplaymidi/aplaymidi.1 b/seq/aplaymidi/aplaymidi.1 index 02fef9d9d668..0c8238d586fe 100644 --- a/seq/aplaymidi/aplaymidi.1 +++ b/seq/aplaymidi/aplaymidi.1 @@ -31,6 +31,12 @@ Prints a list of possible output ports. Sets the sequencer port(s) to which the events in the MIDI file(s) are sent. +.TP +.I \-u, \-\-ump=version +Changes the sequencer client to the given MIDI version and outputs via +the UMP packets instead of legacy sequencer events. +As of now, the only supported version is 1. + A client can be specified by its number, its name, or a prefix of its name. A port is specified by its number; for port 0 of a client, the ":0" part of the port specification can be omitted. diff --git a/seq/aplaymidi/aplaymidi.c b/seq/aplaymidi/aplaymidi.c index e8491e13148d..e96364f0de09 100644 --- a/seq/aplaymidi/aplaymidi.c +++ b/seq/aplaymidi/aplaymidi.c @@ -30,6 +30,9 @@ #include #include "aconfig.h" #include "version.h" +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION +#include +#endif /* * 31.25 kbaud, one start bit, eight data bits, two stop bits. @@ -75,6 +78,9 @@ static int file_offset; /* current offset in input file */ static int num_tracks; static struct track *tracks; static int smpte_timing; +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION +static int ump_mode; +#endif /* prints an error message to stderr */ static void errormsg(const char *msg, ...) @@ -639,8 +645,130 @@ static void handle_big_sysex(snd_seq_event_t *ev) ev->data.ext.len = length; } +static int fill_legacy_event(struct event* event, snd_seq_event_t *ev) +{ + ev->type = event->type; + switch (ev->type) { + case SND_SEQ_EVENT_NOTEON: + case SND_SEQ_EVENT_NOTEOFF: + case SND_SEQ_EVENT_KEYPRESS: + snd_seq_ev_set_fixed(ev); + ev->data.note.channel = event->data.d[0]; + ev->data.note.note = event->data.d[1]; + ev->data.note.velocity = event->data.d[2]; + break; + case SND_SEQ_EVENT_CONTROLLER: + snd_seq_ev_set_fixed(ev); + ev->data.control.channel = event->data.d[0]; + ev->data.control.param = event->data.d[1]; + ev->data.control.value = event->data.d[2]; + break; + case SND_SEQ_EVENT_PGMCHANGE: + case SND_SEQ_EVENT_CHANPRESS: + snd_seq_ev_set_fixed(ev); + ev->data.control.channel = event->data.d[0]; + ev->data.control.value = event->data.d[1]; + break; + case SND_SEQ_EVENT_PITCHBEND: + snd_seq_ev_set_fixed(ev); + ev->data.control.channel = event->data.d[0]; + ev->data.control.value = ((event->data.d[1]) | + ((event->data.d[2]) << 7)) - 0x2000; + break; + case SND_SEQ_EVENT_SYSEX: + snd_seq_ev_set_variable(ev, event->data.length, event->sysex); + handle_big_sysex(ev); + break; + default: + fatal("Invalid event type %d!", ev->type); + } + return 0; +} + +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION +static unsigned char to_ump_status(unsigned char ev_type) +{ + switch (ev_type) { + case SND_SEQ_EVENT_NOTEON: + return SND_UMP_MSG_NOTE_ON; + case SND_SEQ_EVENT_NOTEOFF: + return SND_UMP_MSG_NOTE_OFF; + case SND_SEQ_EVENT_KEYPRESS: + return SND_UMP_MSG_POLY_PRESSURE; + case SND_SEQ_EVENT_CONTROLLER: + return SND_UMP_MSG_CONTROL_CHANGE; + case SND_SEQ_EVENT_PGMCHANGE: + return SND_UMP_MSG_PROGRAM_CHANGE; + case SND_SEQ_EVENT_CHANPRESS: + return SND_UMP_MSG_CHANNEL_PRESSURE; + case SND_SEQ_EVENT_PITCHBEND: + return SND_UMP_MSG_PITCHBEND; + default: + return 0; + } +} + +static int fill_ump_event(struct event* event, snd_seq_ump_event_t *ump_ev, + const snd_seq_event_t *ev) +{ + snd_ump_msg_midi1_t ump = {}; + unsigned char status = to_ump_status(event->type); + + memcpy(ump_ev, ev, sizeof(*ev)); + if (!status) + return 0; /* handle as is */ + + ump.note_on.type = SND_UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE; + switch (event->type) { + case SND_SEQ_EVENT_NOTEON: + /* correct the note-on with velocity 0 to note-off; + * UMP may handle velocity 0 differently + */ + if (!ev->data.note.velocity) + status = SND_UMP_MSG_NOTE_OFF; + /* fallthrough */ + case SND_SEQ_EVENT_NOTEOFF: + case SND_SEQ_EVENT_KEYPRESS: + ump.note_on.status = status; + ump.note_on.channel = event->data.d[0]; + ump.note_on.note = event->data.d[1]; + ump.note_on.velocity = event->data.d[2]; + break; + case SND_SEQ_EVENT_CONTROLLER: + ump.control_change.status = status; + ump.control_change.channel = event->data.d[0]; + ump.control_change.index = event->data.d[1]; + ump.control_change.data = event->data.d[2]; + break; + case SND_SEQ_EVENT_PGMCHANGE: + ump.program_change.status = status; + ump.program_change.channel = event->data.d[0]; + ump.program_change.program = event->data.d[1]; + break; + case SND_SEQ_EVENT_CHANPRESS: + ump.channel_pressure.status = status; + ump.channel_pressure.channel = event->data.d[0]; + ump.channel_pressure.data = event->data.d[1]; + break; + case SND_SEQ_EVENT_PITCHBEND: + ump.pitchbend.status = status; + ump.pitchbend.channel = event->data.d[0]; + ump.pitchbend.data_msb = event->data.d[2]; + ump.pitchbend.data_lsb = event->data.d[1]; + break; + default: + return 0; /* handle as is */ + } + snd_seq_ev_set_ump_data(ump_ev, &ump, sizeof(ump)); + return 0; +} +#endif /* HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION */ + static void play_midi(void) { +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + snd_seq_ump_event_t ump_ev; +#endif snd_seq_event_t ev; int i, max_tick, err; @@ -688,52 +816,28 @@ static void play_midi(void) event_track->current_event = event->next; /* output the event */ - ev.type = event->type; ev.time.tick = event->tick; ev.dest = ports[event->port]; - switch (ev.type) { - case SND_SEQ_EVENT_NOTEON: - case SND_SEQ_EVENT_NOTEOFF: - case SND_SEQ_EVENT_KEYPRESS: - snd_seq_ev_set_fixed(&ev); - ev.data.note.channel = event->data.d[0]; - ev.data.note.note = event->data.d[1]; - ev.data.note.velocity = event->data.d[2]; - break; - case SND_SEQ_EVENT_CONTROLLER: - snd_seq_ev_set_fixed(&ev); - ev.data.control.channel = event->data.d[0]; - ev.data.control.param = event->data.d[1]; - ev.data.control.value = event->data.d[2]; - break; - case SND_SEQ_EVENT_PGMCHANGE: - case SND_SEQ_EVENT_CHANPRESS: - snd_seq_ev_set_fixed(&ev); - ev.data.control.channel = event->data.d[0]; - ev.data.control.value = event->data.d[1]; - break; - case SND_SEQ_EVENT_PITCHBEND: - snd_seq_ev_set_fixed(&ev); - ev.data.control.channel = event->data.d[0]; - ev.data.control.value = - ((event->data.d[1]) | - ((event->data.d[2]) << 7)) - 0x2000; - break; - case SND_SEQ_EVENT_SYSEX: - snd_seq_ev_set_variable(&ev, event->data.length, - event->sysex); - handle_big_sysex(&ev); - break; - case SND_SEQ_EVENT_TEMPO: - snd_seq_ev_set_fixed(&ev); + if (event->type == SND_SEQ_EVENT_TEMPO) { ev.dest.client = SND_SEQ_CLIENT_SYSTEM; ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; ev.data.queue.queue = queue; ev.data.queue.param.value = event->data.tempo; - break; - default: - fatal("Invalid event type %d!", ev.type); + } else { + err = fill_legacy_event(event, &ev); + if (err < 0) + continue; } +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + if (ump_mode) { + err = fill_ump_event(event, &ump_ev, &ev); + if (err < 0) + continue; + err = snd_seq_ump_event_output(seq, &ump_ev); + check_snd("output event", err); + continue; + } +#endif /* this blocks when the output pool has been filled */ err = snd_seq_event_output(seq, &ev); @@ -851,6 +955,9 @@ static void usage(const char *argv0) "-V, --version print current version\n" "-l, --list list all possible output ports\n" "-p, --port=client:port,... set port(s) to play to\n" +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + "-u, --ump=version UMP output (only version=1 is supported)\n" +#endif "-d, --delay=seconds delay after song ends\n", argv0); } @@ -860,18 +967,28 @@ static void version(void) puts("aplaymidi version " SND_UTIL_VERSION_STR); } +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION +#define OPTIONS "hVlp:d:u:" +#else +#define OPTIONS "hVlp:d:" +#endif + + int main(int argc, char *argv[]) { - static const char short_options[] = "hVlp:d:"; + static const char short_options[] = OPTIONS; static const struct option long_options[] = { {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'V'}, {"list", 0, NULL, 'l'}, {"port", 1, NULL, 'p'}, +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + {"ump", 1, NULL, 'u'}, +#endif {"delay", 1, NULL, 'd'}, {0} }; - int c; + int c, err; int do_list = 0; init_seq(); @@ -894,12 +1011,29 @@ int main(int argc, char *argv[]) case 'd': end_delay = atoi(optarg); break; +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + case 'u': + if (strcmp(optarg, "1")) { + errormsg("Only MIDI 1.0 is supported"); + return 1; + } + ump_mode = 1; + break; +#endif default: usage(argv[0]); return 1; } } + +#ifdef HAVE_SEQ_CLIENT_INFO_GET_MIDI_VERSION + if (ump_mode) { + err = snd_seq_set_client_midi_version(seq, SND_SEQ_CLIENT_UMP_MIDI_1_0); + check_snd("set midi version", err); + } +#endif + if (do_list) { list_ports(); } else {