]> git.alsa-project.org Git - alsa-utils.git/commitdiff
amidi: add sysex-interval option
authorFelipe F. Tonello <eu@felipetonello.com>
Tue, 30 Aug 2016 16:02:48 +0000 (17:02 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 13 Sep 2016 16:19:19 +0000 (18:19 +0200)
This patch adds a new option to amidi tool: sysex-interval.

It adds a delay (in milliseconds) in between each SysEx message - it searches
for a 0xF7 byte.

This is very useful when sending firmware updates to a remote device via SysEx
or any other use that requires this delay in between SysEx messages.

`amidi' manual was updated with an example usage as well.

Signed-off-by: Felipe F. Tonello <eu@felipetonello.com>
Acked-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
amidi/amidi.1
amidi/amidi.c

index 86beb27a1e3be10e50b2b0bb8a834e73c3f8690c..5bc24ba3ad547e263516b4a424082b2028960bd5 100644 (file)
@@ -1,4 +1,4 @@
-.TH AMIDI 1 "16 Apr 2016"
+.TH AMIDI 1 "30 Aug 2016"
 
 .SH NAME
 amidi \- read from and write to ALSA RawMIDI ports
@@ -120,6 +120,12 @@ received MIDI commands.
 Does not ignore Clock bytes (F8h) when saving or printing received
 MIDI commands.
 
+.TP
+.I \-i, \-\-sysex-interval=mseconds
+Adds a delay in between each SysEx message sent to a device. It is
+useful when sending firmware updates via SysEx messages to a remote
+device.
+
 .SH EXAMPLES
 
 .TP
@@ -129,6 +135,14 @@ will send the MIDI commands in
 to port
 .I hw:0.
 
+.TP
+.B amidi \-p hw:1,0,0 -s firmware.syx \-i 100
+will send the MIDI commands in
+.I firmware.syx
+to port
+.I hw:1,0,0
+with 100 milliseconds delay in between each SysEx message.
+
 .TP
 .B amidi \-S 'F0 43 10 4C 00 00 7E 00 F7'
 sends an XG Reset to the default port.
index c20512cc96a7786cee7a3ba35b44460106e84bd6..a8264f181cf3a89c26ef3451815a18bb6a17f41a 100644 (file)
@@ -52,6 +52,7 @@ static int receive_file;
 static int dump;
 static float timeout;
 static int stop;
+static int sysex_interval;
 static snd_rawmidi_t *input, **inputp;
 static snd_rawmidi_t *output, **outputp;
 
@@ -70,19 +71,20 @@ static void usage(void)
        printf(
                "Usage: amidi options\n"
                "\n"
-               "-h, --help             this help\n"
-               "-V, --version          print current version\n"
-               "-l, --list-devices     list all hardware ports\n"
-               "-L, --list-rawmidis    list all RawMIDI definitions\n"
-               "-p, --port=name        select port by name\n"
-               "-s, --send=file        send the contents of a (.syx) file\n"
-               "-r, --receive=file     write received data into a file\n"
-               "-S, --send-hex=\"...\"   send hexadecimal bytes\n"
-               "-d, --dump             print received data as hexadecimal bytes\n"
-               "-t, --timeout=seconds  exits when no data has been received\n"
-               "                       for the specified duration\n"
-               "-a, --active-sensing   include active sensing bytes\n"
-               "-c, --clock            include clock bytes\n");
+               "-h, --help                      this help\n"
+               "-V, --version                   print current version\n"
+               "-l, --list-devices              list all hardware ports\n"
+               "-L, --list-rawmidis             list all RawMIDI definitions\n"
+               "-p, --port=name                 select port by name\n"
+               "-s, --send=file                 send the contents of a (.syx) file\n"
+               "-r, --receive=file              write received data into a file\n"
+               "-S, --send-hex=\"...\"            send hexadecimal bytes\n"
+               "-d, --dump                      print received data as hexadecimal bytes\n"
+               "-t, --timeout=seconds           exits when no data has been received\n"
+               "                                for the specified duration\n"
+               "-a, --active-sensing            include active sensing bytes\n"
+               "-c, --clock                     include clock bytes\n"
+               "-i, --sysex-interval=mseconds   delay in between each SysEx message\n");
 }
 
 static void version(void)
@@ -230,6 +232,47 @@ static void rawmidi_list(void)
        snd_output_close(output);
 }
 
+static int send_midi_interleaved(void)
+{
+       int err;
+       char *data = send_data;
+       size_t buffer_size;
+       snd_rawmidi_params_t *param;
+       snd_rawmidi_status_t *st;
+
+       snd_rawmidi_status_alloca(&st);
+
+       snd_rawmidi_params_alloca(&param);
+       snd_rawmidi_params_current(output, param);
+       buffer_size = snd_rawmidi_params_get_buffer_size(param);
+
+       while (data < (send_data + send_data_length)) {
+               int len = send_data + send_data_length - data;
+               char *temp;
+
+               if (data > send_data) {
+                       snd_rawmidi_status(output, st);
+                       do {
+                               /* 320 µs per byte as noted in Page 1 of MIDI spec */
+                               usleep((buffer_size - snd_rawmidi_status_get_avail(st)) * 320);
+                               snd_rawmidi_status(output, st);
+                       } while(snd_rawmidi_status_get_avail(st) < buffer_size);
+                       usleep(sysex_interval * 1000);
+               }
+
+               /* find end of SysEx */
+               if ((temp = memchr(data, 0xf7, len)) != NULL)
+                       len = temp - data + 1;
+
+               if ((err = snd_rawmidi_write(output, data, len)) < 0)
+                       return err;
+
+               data += len;
+       }
+
+       return 0;
+}
+
 static void load_file(void)
 {
        int fd;
@@ -411,7 +454,7 @@ static void add_send_hex_data(const char *str)
 
 int main(int argc, char *argv[])
 {
-       static const char short_options[] = "hVlLp:s:r:S::dt:ac";
+       static const char short_options[] = "hVlLp:s:r:S::dt:aci:";
        static const struct option long_options[] = {
                {"help", 0, NULL, 'h'},
                {"version", 0, NULL, 'V'},
@@ -425,6 +468,7 @@ int main(int argc, char *argv[])
                {"timeout", 1, NULL, 't'},
                {"active-sensing", 0, NULL, 'a'},
                {"clock", 0, NULL, 'c'},
+               {"sysex-interval", 1, NULL, 'i'},
                { }
        };
        int c, err, ok = 0;
@@ -474,6 +518,9 @@ int main(int argc, char *argv[])
                case 'c':
                        ignore_clock = 0;
                        break;
+               case 'i':
+                       sysex_interval = atoi(optarg);
+                       break;
                default:
                        error("Try `amidi --help' for more information.");
                        return 1;
@@ -549,9 +596,16 @@ int main(int argc, char *argv[])
                        error("cannot set blocking mode: %s", snd_strerror(err));
                        goto _exit;
                }
-               if ((err = snd_rawmidi_write(output, send_data, send_data_length)) < 0) {
-                       error("cannot send data: %s", snd_strerror(err));
-                       goto _exit;
+               if (!sysex_interval) {
+                       if ((err = snd_rawmidi_write(output, send_data, send_data_length)) < 0) {
+                               error("cannot send data: %s", snd_strerror(err));
+                               return err;
+                       }
+               } else {
+                       if ((err = send_midi_interleaved()) < 0) {
+                               error("cannot send data: %s", snd_strerror(err));
+                               return err;
+                       }
                }
        }