* [v7 PATCH] amidi: add sysex-interval option @ 2016-08-30 16:02 Felipe F. Tonello 2016-09-12 16:41 ` Felipe Ferreri Tonello ` (2 more replies) 0 siblings, 3 replies; 8+ messages in thread From: Felipe F. Tonello @ 2016-08-30 16:02 UTC (permalink / raw) To: alsa-devel 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> --- amidi/amidi.1 | 16 ++++++++++- amidi/amidi.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 86 insertions(+), 18 deletions(-) diff --git a/amidi/amidi.1 b/amidi/amidi.1 index 86beb27a1e3b..5bc24ba3ad54 100644 --- a/amidi/amidi.1 +++ b/amidi/amidi.1 @@ -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 @@ -130,6 +136,14 @@ 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. diff --git a/amidi/amidi.c b/amidi/amidi.c index c20512cc96a7..a8264f181cf3 100644 --- a/amidi/amidi.c +++ b/amidi/amidi.c @@ -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(¶m); + 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; + } } } -- 2.9.3 _______________________________________________ Alsa-devel mailing list Alsa-devel@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/alsa-devel ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [v7 PATCH] amidi: add sysex-interval option 2016-08-30 16:02 [v7 PATCH] amidi: add sysex-interval option Felipe F. Tonello @ 2016-09-12 16:41 ` Felipe Ferreri Tonello 2016-09-12 23:32 ` Takashi Sakamoto 2016-09-13 15:37 ` Clemens Ladisch 2016-09-13 16:20 ` Takashi Iwai 2 siblings, 1 reply; 8+ messages in thread From: Felipe Ferreri Tonello @ 2016-09-12 16:41 UTC (permalink / raw) To: alsa-devel [-- Attachment #1: Type: text/plain, Size: 6649 bytes --] ping? On 30/08/16 17:02, Felipe F. Tonello wrote: > 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> > --- > amidi/amidi.1 | 16 ++++++++++- > amidi/amidi.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++------------ > 2 files changed, 86 insertions(+), 18 deletions(-) > > diff --git a/amidi/amidi.1 b/amidi/amidi.1 > index 86beb27a1e3b..5bc24ba3ad54 100644 > --- a/amidi/amidi.1 > +++ b/amidi/amidi.1 > @@ -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 > @@ -130,6 +136,14 @@ 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. > > diff --git a/amidi/amidi.c b/amidi/amidi.c > index c20512cc96a7..a8264f181cf3 100644 > --- a/amidi/amidi.c > +++ b/amidi/amidi.c > @@ -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(¶m); > + 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; > + } > } > } > > -- Felipe [-- Attachment #2: 0x92698E6A.asc --] [-- Type: application/pgp-keys, Size: 7177 bytes --] [-- Attachment #3: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [v7 PATCH] amidi: add sysex-interval option 2016-09-12 16:41 ` Felipe Ferreri Tonello @ 2016-09-12 23:32 ` Takashi Sakamoto 2016-09-13 13:53 ` Felipe Ferreri Tonello 0 siblings, 1 reply; 8+ messages in thread From: Takashi Sakamoto @ 2016-09-12 23:32 UTC (permalink / raw) To: Felipe Ferreri Tonello, alsa-devel Hi, On Sep 13 2016 01:41, Felipe Ferreri Tonello wrote: > ping? Sorry to be late. I've already read this patch, then consider about whether this patch is for general purporse or not. The basic design of 'amidi' tool is somehow generic purpose; send/receive MIDI messages to/from ALSA rawmidi devices. In my opinion, model-specific features is not so preferable to this tool. The system exclusive messages are for the purpose to implement vendor-dependent something. So if this patch is quite unique for a small part of devices, I think it better to add isolated tools with this feature from amidi. For my information and help of my review, please show which devices do you want to set up this tool? Another my concern is a case that MIDI messages in a given file includes some messages except for system exclusives. > On 30/08/16 17:02, Felipe F. Tonello wrote: >> 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> >> --- >> amidi/amidi.1 | 16 ++++++++++- >> amidi/amidi.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++------------ >> 2 files changed, 86 insertions(+), 18 deletions(-) >> >> diff --git a/amidi/amidi.1 b/amidi/amidi.1 >> index 86beb27a1e3b..5bc24ba3ad54 100644 >> --- a/amidi/amidi.1 >> +++ b/amidi/amidi.1 >> @@ -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 >> @@ -130,6 +136,14 @@ 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. >> >> diff --git a/amidi/amidi.c b/amidi/amidi.c >> index c20512cc96a7..a8264f181cf3 100644 >> --- a/amidi/amidi.c >> +++ b/amidi/amidi.c >> @@ -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(¶m); >> + 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; >> + } >> } >> } Regards Takashi Sakamoto ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [v7 PATCH] amidi: add sysex-interval option 2016-09-12 23:32 ` Takashi Sakamoto @ 2016-09-13 13:53 ` Felipe Ferreri Tonello 2016-09-13 17:44 ` Takashi Sakamoto 0 siblings, 1 reply; 8+ messages in thread From: Felipe Ferreri Tonello @ 2016-09-13 13:53 UTC (permalink / raw) To: Takashi Sakamoto, alsa-devel [-- Attachment #1: Type: text/plain, Size: 9315 bytes --] Hi Takashi, On 13/09/16 00:32, Takashi Sakamoto wrote: > Hi, > > On Sep 13 2016 01:41, Felipe Ferreri Tonello wrote: >> ping? > > Sorry to be late. I've already read this patch, then consider about > whether this patch is for general purporse or not. > > The basic design of 'amidi' tool is somehow generic purpose; > send/receive MIDI messages to/from ALSA rawmidi devices. In my opinion, > model-specific features is not so preferable to this tool. > > The system exclusive messages are for the purpose to implement > vendor-dependent something. So if this patch is quite unique for a small > part of devices, I think it better to add isolated tools with this > feature from amidi. This is not a vendor-dependent feature, by any means. This feature is really useful for upgrading firmwares via SysEx, this is a very common practice used by several devices. There are other applications for other OSes that implements this feature, that is why I saw the need for `amidi' to support, been so useful. > > For my information and help of my review, please show which devices do > you want to set up this tool? Many devices uses this to update internal firmware, for example. I use in the Seaboard RISE, Seaboard GRAND, Linnstrument, and so on. > > Another my concern is a case that MIDI messages in a given file includes > some messages except for system exclusives. As suggested by Clemens Ladish, I implemented delays in between SysEx only, because in practice that is what people use this feature for. But even then, other types of MIDI messages will not cause any problem, it will not be delayed. > >> On 30/08/16 17:02, Felipe F. Tonello wrote: >>> 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> >>> --- >>> amidi/amidi.1 | 16 ++++++++++- >>> amidi/amidi.c | 88 >>> +++++++++++++++++++++++++++++++++++++++++++++++------------ >>> 2 files changed, 86 insertions(+), 18 deletions(-) >>> >>> diff --git a/amidi/amidi.1 b/amidi/amidi.1 >>> index 86beb27a1e3b..5bc24ba3ad54 100644 >>> --- a/amidi/amidi.1 >>> +++ b/amidi/amidi.1 >>> @@ -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 >>> @@ -130,6 +136,14 @@ 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. >>> >>> diff --git a/amidi/amidi.c b/amidi/amidi.c >>> index c20512cc96a7..a8264f181cf3 100644 >>> --- a/amidi/amidi.c >>> +++ b/amidi/amidi.c >>> @@ -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(¶m); >>> + 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; >>> + } >>> } >>> } > -- Felipe [-- Attachment #2: 0x92698E6A.asc --] [-- Type: application/pgp-keys, Size: 7291 bytes --] [-- Attachment #3: Type: text/plain, Size: 0 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [v7 PATCH] amidi: add sysex-interval option 2016-09-13 13:53 ` Felipe Ferreri Tonello @ 2016-09-13 17:44 ` Takashi Sakamoto 2016-09-14 5:43 ` Martin Tarenskeen 0 siblings, 1 reply; 8+ messages in thread From: Takashi Sakamoto @ 2016-09-13 17:44 UTC (permalink / raw) To: Felipe Ferreri Tonello, alsa-devel On Sep 13 2016 22:53, Felipe Ferreri Tonello wrote: > Hi Takashi, > > On 13/09/16 00:32, Takashi Sakamoto wrote: >> Hi, >> >> On Sep 13 2016 01:41, Felipe Ferreri Tonello wrote: >>> ping? >> >> Sorry to be late. I've already read this patch, then consider about >> whether this patch is for general purporse or not. >> >> The basic design of 'amidi' tool is somehow generic purpose; >> send/receive MIDI messages to/from ALSA rawmidi devices. In my opinion, >> model-specific features is not so preferable to this tool. >> >> The system exclusive messages are for the purpose to implement >> vendor-dependent something. So if this patch is quite unique for a small >> part of devices, I think it better to add isolated tools with this >> feature from amidi. > > This is not a vendor-dependent feature, by any means. This feature is > really useful for upgrading firmwares via SysEx, this is a very common > practice used by several devices. > > There are other applications for other OSes that implements this > feature, that is why I saw the need for `amidi' to support, been so useful. Hm. If the MIDI messages you want to handle were vendor-independent, it would probably be 'universal system exclusive' or described in some recommended practices (RPs). But your patch comment don't address to them. At least, I find no public documents for your purpose. So I can't avoid to judge the feature is for something dependent to vendors. >> For my information and help of my review, please show which devices do >> you want to set up this tool? > > Many devices uses this to update internal firmware, for example. I use > in the Seaboard RISE, Seaboard GRAND, Linnstrument, and so on. If vendors voluntarily expand the specification then the expansion is widely used and practices in fact, it was better to describe it to your patch comment, to help reviewers. >> Another my concern is a case that MIDI messages in a given file includes >> some messages except for system exclusives. > > As suggested by Clemens Ladish, I implemented delays in between SysEx > only, because in practice that is what people use this feature for. But > even then, other types of MIDI messages will not cause any problem, it > will not be delayed. I mean this case: <F0>...<F7> <no exclusive messages such like note> <F0>...<F7> <ditto> <F0>...<F7> In this case, I think your code includes ambiguities to handle messages between each system exclusives. For upgrading firmwares on MIDI devices, the non-exclusive messages should not be transferred, perhaps, to protect the devices from disorder. In this view, I addressed to split this feature to independent tool to amidi. Anyway, this patch was applied to upstream. >>> On 30/08/16 17:02, Felipe F. Tonello wrote: >>>> 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> >>>> --- >>>> amidi/amidi.1 | 16 ++++++++++- >>>> amidi/amidi.c | 88 >>>> +++++++++++++++++++++++++++++++++++++++++++++++------------ >>>> 2 files changed, 86 insertions(+), 18 deletions(-) >>>> >>>> diff --git a/amidi/amidi.1 b/amidi/amidi.1 >>>> index 86beb27a1e3b..5bc24ba3ad54 100644 >>>> --- a/amidi/amidi.1 >>>> +++ b/amidi/amidi.1 >>>> @@ -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 >>>> @@ -130,6 +136,14 @@ 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. >>>> >>>> diff --git a/amidi/amidi.c b/amidi/amidi.c >>>> index c20512cc96a7..a8264f181cf3 100644 >>>> --- a/amidi/amidi.c >>>> +++ b/amidi/amidi.c >>>> @@ -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(¶m); >>>> + 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; >>>> + } >>>> } >>>> } ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [v7 PATCH] amidi: add sysex-interval option 2016-09-13 17:44 ` Takashi Sakamoto @ 2016-09-14 5:43 ` Martin Tarenskeen 0 siblings, 0 replies; 8+ messages in thread From: Martin Tarenskeen @ 2016-09-14 5:43 UTC (permalink / raw) To: Takashi Sakamoto; +Cc: alsa-devel, Felipe Ferreri Tonello >>>>> + "-i, --sysex-interval=mseconds delay in between each SysEx I really appreciate this new option. It's by no means useful only for firmware upgrades that's often mentioned in this thread. IMO that's a special case. More common is that (older) synths expect a delay between SyxEx blocks to prevent "MIDI buffer full" type of messages on the synth's display. I have read in the manual of some Yamaha synths (can't remember which) a recommendation to use an interval of 10 ms. When I programmed YSEDITOR, a Yamaha synth editor/librarian in the old Atari days, I often used series of sysex messages simulating button presses to put the synth in a certain mode, before sending bulkdumps and parameter change messages. Some messages took more time inside the synth to be processed and I had to insert time intervals before I could send another message. If I combine such a sequence of sysex messages in a single .syx file and use amidi to send the message, I will surely need the new -i parameter. Apart from that, every sysex dump utility I have seen has a similar feature. MIDI-OX for Windows is probably the best known example. So, thanks guys. -- MT ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [v7 PATCH] amidi: add sysex-interval option 2016-08-30 16:02 [v7 PATCH] amidi: add sysex-interval option Felipe F. Tonello 2016-09-12 16:41 ` Felipe Ferreri Tonello @ 2016-09-13 15:37 ` Clemens Ladisch 2016-09-13 16:20 ` Takashi Iwai 2 siblings, 0 replies; 8+ messages in thread From: Clemens Ladisch @ 2016-09-13 15:37 UTC (permalink / raw) To: Takashi Iwai; +Cc: alsa-devel, Felipe F. Tonello Felipe F. Tonello wrote: > 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> ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [v7 PATCH] amidi: add sysex-interval option 2016-08-30 16:02 [v7 PATCH] amidi: add sysex-interval option Felipe F. Tonello 2016-09-12 16:41 ` Felipe Ferreri Tonello 2016-09-13 15:37 ` Clemens Ladisch @ 2016-09-13 16:20 ` Takashi Iwai 2 siblings, 0 replies; 8+ messages in thread From: Takashi Iwai @ 2016-09-13 16:20 UTC (permalink / raw) To: Felipe F. Tonello; +Cc: alsa-devel On Tue, 30 Aug 2016 18:02:48 +0200, Felipe F. Tonello wrote: > > 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> Applied now. Thanks. Takashi ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2016-09-14 5:43 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-08-30 16:02 [v7 PATCH] amidi: add sysex-interval option Felipe F. Tonello 2016-09-12 16:41 ` Felipe Ferreri Tonello 2016-09-12 23:32 ` Takashi Sakamoto 2016-09-13 13:53 ` Felipe Ferreri Tonello 2016-09-13 17:44 ` Takashi Sakamoto 2016-09-14 5:43 ` Martin Tarenskeen 2016-09-13 15:37 ` Clemens Ladisch 2016-09-13 16:20 ` Takashi Iwai
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.