Page MenuHomeFreeBSD

D46418.diff
No OneTemporary

D46418.diff

diff --git a/usr.bin/Makefile b/usr.bin/Makefile
--- a/usr.bin/Makefile
+++ b/usr.bin/Makefile
@@ -89,6 +89,7 @@
mandoc \
mdo \
mesg \
+ mididump \
ministat \
mkdep \
mkfifo \
diff --git a/usr.bin/mididump/Makefile b/usr.bin/mididump/Makefile
new file mode 100644
--- /dev/null
+++ b/usr.bin/mididump/Makefile
@@ -0,0 +1,8 @@
+.include <src.opts.mk>
+
+PROG= mididump
+SRCS= ${PROG}.c
+MAN= ${PROG}.1
+LDFLAGS+= -lm
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/mididump/mididump.1 b/usr.bin/mididump/mididump.1
new file mode 100644
--- /dev/null
+++ b/usr.bin/mididump/mididump.1
@@ -0,0 +1,80 @@
+.\"-
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2024 The FreeBSD Foundation
+.\"
+.\" Portions of this software were developed by Christos Margiolis
+.\" <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd September 14, 2024
+.Dt MIDIDUMP 1
+.Os
+.Sh NAME
+.Nm mididump
+.Nd dump MIDI events
+.Sh SYNOPSIS
+.Nm
+.Op Fl t
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to dump MIDI 1.0 events in real-time.
+.Pp
+The options are as follows:
+.Bl -tag -width "-t"
+.It Fl t
+Print "Timing Clock" events.
+These events are not printed by default, as they tend to clutter output.
+.El
+.Pp
+The
+.Ar device
+argument corresponds to the MIDI device (e.g.
+.Pa /dev/umidi0.0 ) .
+.Sh SEE ALSO
+.Rs
+.%T Summary of MIDI 1.0 Messages
+.%U https://midi.org/summary-of-midi-1-0-messages
+.Re
+.Rs
+.%T Expanded MIDI 1.0 Messages List (Status Bytes)
+.%U https://midi.org/expanded-midi-1-0-messages-list
+.Re
+.Rs
+.%T Standard MIDI-File Format Spec. 1.1, updated
+.%U https://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html
+.Re
+.Rs
+.%T MIDI CC List for Continuous Controllers
+.%U https://anotherproducer.com/online-tools-for-musicians/midi-cc-list/
+.Re
+.Sh AUTHORS
+The
+.Nm
+utility was implemented by
+.An Christos Margiolis Aq Mt christos@FreeBSD.org
+under sponsorship from the
+.Fx
+Foundation.
diff --git a/usr.bin/mididump/mididump.c b/usr.bin/mididump/mididump.c
new file mode 100644
--- /dev/null
+++ b/usr.bin/mididump/mididump.c
@@ -0,0 +1,320 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 The FreeBSD Foundation
+ *
+ * This software was developed by Christos Margiolis <christos@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/soundcard.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
+#define NOTE2OCTAVE(n) (n / 12 - 1)
+#define NOTE2FREQ(n) (440 * pow(2.0f, ((float)n - 69) / 12))
+#define CHAN_MASK 0x0f
+
+struct note {
+ const char *name;
+ const char *alt;
+} static notes[] = {
+ { "C", NULL },
+ { "C#", "Db" },
+ { "D", NULL },
+ { "D#", "Eb" },
+ { "E", NULL },
+ { "F", NULL },
+ { "F#", "Gb" },
+ { "G", NULL },
+ { "G#", "Ab" },
+ { "A", NULL },
+ { "A#", "Bb" },
+ { "B", NULL },
+};
+
+/* Hardcoded values are not defined in sys/soundcard.h. */
+static const char *ctls[] = {
+ [CTL_BANK_SELECT] = "Bank Select",
+ [CTL_MODWHEEL] = "Modulation Wheel",
+ [CTL_BREATH] = "Breath Controller",
+ [0x03] = "Undefined",
+ [CTL_FOOT] = "Foot Pedal",
+ [CTL_PORTAMENTO_TIME] = "Portamento Time",
+ [CTL_DATA_ENTRY] = "Data Entry",
+ [CTL_MAIN_VOLUME] = "Volume",
+ [CTL_BALANCE] = "Balance",
+ [0x09] = "Undefined",
+ [CTL_PAN] = "Pan",
+ [CTL_EXPRESSION] = "Expression",
+ [0x0c] = "Effect Controller 1",
+ [0x0d] = "Effect Controller 2",
+ [0x0e] = "Undefined",
+ [0x0f] = "Undefined",
+ [CTL_GENERAL_PURPOSE1] = "General Purpose 1",
+ [CTL_GENERAL_PURPOSE2] = "General Purpose 2",
+ [CTL_GENERAL_PURPOSE3] = "General Purpose 3",
+ [CTL_GENERAL_PURPOSE4] = "General Purpose 4",
+ [0x14 ... 0x1f] = "Undefined",
+ [0x20 ... 0x3f] = "LSB Controller",
+ [CTL_DAMPER_PEDAL] = "Damper Pedal (Sustain)",
+ [CTL_PORTAMENTO] = "Portamento",
+ [CTL_SOSTENUTO] = "Sostenuto Pedal",
+ [CTL_SOFT_PEDAL] = "Soft Pedal",
+ [0x44] = "Legato Foot-Switch",
+ [CTL_HOLD2] = "Hold 2",
+ [0x46] = "Sound Controller 1",
+ [0x47] = "Sound Controller 2",
+ [0x48] = "Sound Controller 3",
+ [0x49] = "Sound Controller 4",
+ [0x4a] = "Sound Controller 5",
+ [0x4b] = "Sound Controller 6",
+ [0x4c] = "Sound Controller 7",
+ [0x4d] = "Sound Controller 8",
+ [0x4e] = "Sound Controller 9",
+ [0x4f] = "Sound Controller 10",
+ [CTL_GENERAL_PURPOSE5] = "General Purpose 5",
+ [CTL_GENERAL_PURPOSE6] = "General Purpose 6",
+ [CTL_GENERAL_PURPOSE7] = "General Purpose 7",
+ [CTL_GENERAL_PURPOSE8] = "General Purpose 8",
+ [0x54] = "Portamento CC",
+ [0x55 ... 0x57] = "Undefined",
+ [0x58] = "Hi-Res Velocity Prefix",
+ [0x59 ... 0x5a] = "Undefined",
+ [CTL_EXT_EFF_DEPTH] = "Effect 1 Depth",
+ [CTL_TREMOLO_DEPTH] = "Effect 2 Depth",
+ [CTL_CHORUS_DEPTH] = "Effect 3 Depth",
+ [CTL_DETUNE_DEPTH] = "Effect 4 Depth",
+ [CTL_PHASER_DEPTH] = "Effect 5 Depth",
+ [CTL_DATA_INCREMENT] = "Data Increment",
+ [CTL_DATA_DECREMENT] = "Data Decrement",
+ [CTL_NONREG_PARM_NUM_LSB] = "NRPN (LSB)",
+ [CTL_NONREG_PARM_NUM_MSB] = "NRPN (MSB)",
+ [CTL_REGIST_PARM_NUM_LSB] = "RPN (LSB)",
+ [CTL_REGIST_PARM_NUM_MSB] = "RPN (MSB)",
+ [0x66 ... 0x77] = "Undefined",
+ /* Channel mode messages */
+ [0x78] = "All Sound Off",
+ [0x79] = "Reset All Controllers",
+ [0x7a] = "Local On/Off Switch",
+ [0x7b] = "All Notes Off",
+ [0x7c] = "Omni Mode Off",
+ [0x7d] = "Omni Mode On",
+ [0x7e] = "Mono Mode",
+ [0x7f] = "Poly Mode",
+};
+
+static void __dead2
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-t] device\n", getprogname());
+ exit(1);
+}
+
+static uint8_t
+read_byte(int fd)
+{
+ uint8_t byte;
+
+ if (read(fd, &byte, sizeof(byte)) < (ssize_t)sizeof(byte))
+ err(1, "read");
+
+ return (byte);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct note *pn;
+ char buf[16];
+ int fd, ch, tflag = 0;
+ uint8_t event, chan, b1, b2;
+
+ while ((ch = getopt(argc, argv, "t")) != -1) {
+ switch (ch) {
+ case 't':
+ tflag = 1;
+ break;
+ case '?': /* FALLTHROUGH */
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ if ((fd = open(*argv, O_RDONLY)) < 0)
+ err(1, "open(%s)", *argv);
+
+ for (;;) {
+ event = read_byte(fd);
+ if (!(event & 0x80))
+ continue;
+ chan = (event & CHAN_MASK) + 1;
+
+ switch (event) {
+ case 0x80 ... 0x8f: /* FALLTHROUGH */
+ case 0x90 ... 0x9f:
+ b1 = read_byte(fd);
+ b2 = read_byte(fd);
+ pn = &notes[b1 % ARRLEN(notes)];
+ snprintf(buf, sizeof(buf), "%s%d", pn->name,
+ NOTE2OCTAVE(b1));
+ if (pn->alt != NULL) {
+ snprintf(buf + strlen(buf), sizeof(buf),
+ "/%s%d", pn->alt, NOTE2OCTAVE(b1));
+ }
+ printf("Note %-3s channel=%d, "
+ "note=%d (%s, %.2fHz), velocity=%d\n",
+ (event >= 0x80 && event <= 0x8f) ? "off" : "on",
+ chan, b1, buf, NOTE2FREQ(b1), b2);
+ break;
+ case 0xa0 ... 0xaf:
+ b1 = read_byte(fd);
+ b2 = read_byte(fd);
+ printf("Polyphonic aftertouch channel=%d, note=%d, "
+ "pressure=%d\n",
+ chan, b1, b2);
+ break;
+ case 0xb0 ... 0xbf:
+ b1 = read_byte(fd);
+ b2 = read_byte(fd);
+ if (b1 < 0 || b1 > ARRLEN(ctls) - 1)
+ break;
+ printf("Control/Mode change channel=%d, "
+ "control=%d (%s), value=%d",
+ chan, b1, ctls[b1], b2);
+ if (b1 >= 0x40 && b1 <= 0x45) {
+ if (b2 <= 63)
+ printf(" (off)");
+ else
+ printf(" (on)");
+ }
+ if (b1 == 0x7a) {
+ if (b2 == 0)
+ printf(" (off)");
+ else if (b2 == 127)
+ printf(" (on");
+ }
+ putchar('\n');
+ break;
+ case 0xc0 ... 0xcf:
+ b1 = read_byte(fd);
+ printf("Program change channel=%d, "
+ "program=%d\n",
+ chan, b1);
+ break;
+ case 0xd0 ... 0xdf:
+ b1 = read_byte(fd);
+ printf("Channel aftertouch channel=%d, "
+ "pressure=%d\n",
+ chan, b1);
+ break;
+ case 0xe0 ... 0xef:
+ /* TODO Improve */
+ b1 = read_byte(fd);
+ b2 = read_byte(fd);
+ printf("Pitch bend channel=%d, change=%d\n",
+ chan, b1 | b2 << 7);
+ break;
+ case 0xf0:
+ printf("SysEx vendorid=");
+ b1 = read_byte(fd);
+ printf("0x%02x", b1);
+ if (b1 == 0) {
+ printf(" 0x%02x 0x%02x",
+ read_byte(fd), read_byte(fd));
+ }
+ printf(" data=");
+ for (;;) {
+ b1 = read_byte(fd);
+ printf("0x%02x ", b1);
+ /* End of SysEx (EOX) */
+ if (b1 == 0xf7)
+ break;
+ }
+ putchar('\n');
+ break;
+ case 0xf2:
+ b1 = read_byte(fd);
+ b2 = read_byte(fd);
+ printf("Song position pointer ptr=%d\n",
+ b1 | b2 << 7);
+ break;
+ case 0xf3:
+ b1 = read_byte(fd);
+ printf("Song select song=%d\n", b1);
+ break;
+ case 0xf6:
+ printf("Tune request\n");
+ break;
+ case 0xf7:
+ printf("End of SysEx (EOX)\n");
+ break;
+ case 0xf8:
+ if (tflag)
+ printf("Timing clock\n");
+ break;
+ case 0xfa:
+ printf("Start\n");
+ break;
+ case 0xfb:
+ printf("Continue\n");
+ break;
+ case 0xfc:
+ printf("Stop\n");
+ break;
+ case 0xfe:
+ printf("Active sensing\n");
+ break;
+ case 0xff:
+ printf("System reset\n");
+ break;
+ case 0xf1: /* TODO? MIDI time code qtr. frame */
+ case 0xf4: /* Undefined (reserved) */
+ case 0xf5:
+ case 0xf9:
+ case 0xfd:
+ break;
+ default:
+ printf("Unknown event type: 0x%02x\n", event);
+ break;
+ }
+ }
+
+ close(fd);
+
+ return (0);
+}

File Metadata

Mime Type
text/plain
Expires
Tue, Sep 24, 1:28 AM (22 h, 30 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
12533371
Default Alt Text
D46418.diff (11 KB)

Event Timeline