How do I send midi sysex messages on norns?

Hi!
I would like to send sysex messages in a norns script. How do I do that? / Can I do that?

I want to use the lcd on my ableton push to display what im using my knobs for. I can control the lcd screen with max msp no problem using sysex messages. On norns the sysex part of the midi standard seems hidden or missing.

Thanks!
Eric

2 Likes

There’s no sysex handling built into norns. You might be able to script your own solution though. Not really sure how involved that’d be.

1 Like

Is it reasonable to expect sysex support in the future?

norns is many sound instruments. it connects to grids, MIDI and other objects. norns lets you define its behavior with scripts and DSP.

MIDI is listed in the product description without an asterisk.

the GH issue was closed a bit ago as it hadn’t received much follow-up interest – i’ve pinged it again: https://github.com/monome/norns/issues/262

1 Like

you just send the bytes.

(assuming that midi_out is some midi device that you have connected in the script)

midi_out:send(0xf0) -- sysex start
--- send sysex bytes...
midi_out:send(0xf7) -- sysex end

:woman_shrugging:

if anything is “missing”, it is that Midi.to_data() function doesn’t include entires for “systex_start” and “sysex_end”, which contsitutes the entirety of the “MIDI standard for sysex.” if you like, and you are someone who would use this features, you could add those here:

and PR.

but it doesn’t make a ton of sense to ask for high-level structure around what is by definition a low-level protocol, where every byte value depends on knowing details of the target machine.

7 Likes

“ MIDI is listed in the product description without an asterisk.”

There are many many midi devices that to not support sysex. Can you use push without ABLETON? I was under the impression that you needed to have ableton up and running and you could easily have ableton open and use the push to control CC knobs that nots does respond to.

I can work with that.
I’ll give it a shot.
Thanks!

I only asked it it was reasonable. It seemed to me that norns should have some sysex support, which it apparently does.

Yes you can control the push without ableton, i use max and pd no problem. I think the only thing that works funny is the “user” button which i dont touch normally.

Technobear even controls the push2 with his orac machines.

Yeah I agree low-level makes sense. I just couldn’t even figure that out. Thank you for the help!

I have tried a couple things to try to get a test message to the device.

midiout.send(0xf0) --did not work throws error
midiout.send{0xf0} --didnt throw error but doesn't do much by itself... is this right or is there a better way to convert to the data type?

So i tried sending my test message:

    --neither of these worked for me maybe im doing something weird
    midi_out.send{0xf0,0x47,0x7F,0x15,0x18,0x00,0x45,0x00,0x54,0x68,0x61,0x6E,0x6B,0x20,0x79,0x6F,0x75,0x21,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0xf7} 

     midi_out.send{0xf0}
     midi_out.send{0xf0,0x47,0x7F,0x15,0x18,0x00,0x45,0x00,0x54,0x68,0x61,0x6E,0x6B,0x20,0x79,0x6F,0x75,0x21,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20} 
     midi_out.send{0xf7}

I also tried sending with the decimal values.

This is how i send this test script in max:


----------begin_max5_patcher----------
2548.3oc2as0aiiaE94L.y+AtFEnsntYDuIJMuTLXmWVfYKVf121svP1hwlS
jkDjnxkcQ+uWdQxVxQxVQWblo.IQHjT5vyGOWIO7Od+6tYw5jm34K.eD7qfa
t4OTsbioMcK2T0vMK1G7zlnfby.WrtPJShWrrru3h8h3HtzzIrVqIExWzrHz
7IRV+0+Nhc3SjFH2rSDucUFeizNYfTJ6VWDyg3hPLBkBw9KAdNjaQXFh5nZB
46RXdKAHxsN1+B9OUeQKskOmxsetEqCh2t3X+oAYA64Rd1Jdbv5HynbL88ee
+6zOUOV1aDYOOOOXK+.+H4OIsPUTP63Dpp06Rhk4he2LAfHEiza7ChVT+iDq
3GSeeJSDDcNnkxnZ.yyAqefQ2RUnG5rnmB4FL3DyeTMceI1HAPLH5BhQ8CdP
s.OdiDcHLC5X96EPGQrbwx4AjRy3o73PPPp9wj.VsJKgGLZYT9770jC360Cz
56YXhNPXx0hL9Pu2TXRHS5vdDdB.G2wANd9P8ChaO03FA9nADdnPNIBJj1vB
13zmfNUOsOftmWVY4QiPVCQyietSjqFpmeH7bP.Ba3YFAqcLAcblYkkScd2t
e5KyU9miovLllaXdD8C52K7j643IejQUk3QuJ7TWF0hRBB07KvY9r6OPsYnu
ATfLSjVLzaMBkykyFF4NTSdXGiNAxBRdvYFj1jreOOV9RT5elHAOljcuZ18O
.eNoPYsDrIRr4dfbmHGDnBuXev8bPdQFGHj+YCbBjIptUCLISyQfe9m97OAR
Sxj2df.QhX9ljhXYCmEpHVxUSi.oHIdU6C40sBstXco88NrD6z1h1f8YaWmb
QVAbqSaWiWpoek4K+3mmDw1VQ.x.Q.DrLwIiVM1JC6LO.vmBC1C94hrrfmUz
Pk1zNoL8ie3CaExcEquU8deHPMjut2Lj1k7PWVxCMafry.AYenUvxlSFxw3o
ASFEJ2kUxLESvAl+cJRYusbRoCMoTRYvP9Fajt8xF4xoMDhC3jGQGVJvmoBK
0QGoJ.iT3.T8u5eU+KV2x2O+LwVpmfs1gNReoXHzt0NlHocIylyzWjH0Aoj+
8tf36AOmT7CfYKKKJcjpSNlc2A5YrtPcFXNV2yedeRXSWuSadWc5X3eoh.I.
rtHdyNPxcfM6Tjcihp4eb1bXRGpCSFwllu4uPe6l15LKlxSMlwWISVk+bN+o
YKlW5P21LWGeS7BDey9AQ5WLuM9f7rRjoBZTyAQD+A0huxPU8Y7MKBRSq09M
0eIMh90Dy2xa4w1Dw11fGaKi+fn5SPO1bPlh4jJNSEVrg4e5XHU5ujRyHKtP
X9XkspWiqlZlESMvkmFrw9AzK5G5uV.WFsTWeqIMGapm00YUhKaiR1bOOrtr
qBJS4wh35lwa1eH+tfhH4pNjCZNf6Jmks2a6R.2rXalHLIVOQZtvnauhj5y7
vnZPavSlgDGj11qqjAUvSW8lqX1h70AY50sRaPnC8JSRhZ12w2Lhemrr+TQb
7o.pLI8L8lI1t6bu85DUu6O6m2zU9phXa2qTxHxU4AObBxKChhJMAbBEdJHV
rOPxkB65Ax4XuVCx6x2jkDE0jusc8PacEpj92veTDJ2YHVCwC0KHRqDrVbbY
OTrkmKOoQYv17SZJW9rcIndaEqK0yWI46SiTbyIiPo3Hxk46RdLubjUheMfh
iGuWC895FWa1w4c9zzRqNqXU9uwfzhnHkKn6LYCemHKWpxQrlCoFudqYczsE
5yYk9Ldsdwt33r3zOXG5qcdljVeWd1vFr63EFevE1MGciUYlavndSWam.5xD
whNQM7vPMXGnl2HAMO6t45Tau8aXztUmcQh7Cav+0BU+8HPdjRGWI21M3hFF
3h5.bYSB3VJP5h6I5VO0voDcOqkhzfPviB4NfwQetdiy3wl8RSawnLaSfdi1
jfHdP+sefuV1ObG4hEoLcCnYWLfTyZm9Xlu1lOLGR52W4n2uL36NK9IS3nKy
jjoQS1wDdK1LGTYIbYU4YP1wRjE8C45mpCperOBYXeaj9H5obek8kFgAYnTb
H+o5YXLcfggs6FKFfjBrmhBmEJNS5giDppk5gVSpqfGMya8.5.DySJx1TM4J
YavILgJvYoH9PFY+5g.N.uJShu5oBouSE1rOUX8cpfl8ohWemJjyNUp53XR9
KzYtEtxlr5p.oLSrtPZkrZr+EuxDoTI6uNH5jTeZMQqCynoe2v2wihRzmaXT
3OLak5GgMx8Yxtevr2ryVUKGBHy1dRhbG2g3UtQ40SOYlv.77gAzQdPl99WI
L.MeXvXOLWaMHbEv.37gA3QhA1BecRvft1e9+VW7+TXqjLth0A6R6cYQOxxP
LKHTjrMKoH8BRCI2cmtzcz.Ds+HAC2C1sb410ydfXuhyfnkC35vjPx2W8ZGZ
rZ47vI48PPTQygDJx0eqPK4TSqxelAQvsAxN8H0tTH9UU.niTJjTlAXoXH9x
G0+xwej+cZxRWc0ARyF0jq3DfYkSu+L58WOG7WBhAp2SjwAYIOpOHR8H+xO9
4+52dkhBYnkhhma858o77KGYonzYTk+IH3+W94aupq.OznE02XliQIf7oyb0
UnXk07rAFofZrh8E6anGzQEJoHZ0PgHVaHFbjHlUooekH7xY9xZco6PBh3nx
TRiDpPhTK1J2Ot9yXwEiFrEImxrVJqhk25KeyI.m6rCbCUpjVkpy2l.GctAN
n+PKuLqIu2bfSEeY17gNCUejXiIv0wl5D6JeGONfNDO0TQYrEPg.JBPw.JAP
o.pKfx.tTfqKvkoCeSIkwLhdLDfgALBfQALW.iAXd.luxDCvCB7P.OLvi.7n
pvf.dLfmGvyG36.7g.eDvGC7I.eJv2UWWn9d.ee8M2Q8KTmTg5WronQgNT0u
tlpFE53oOuCaUjZJcT03fpwAI5yHSeomLkSJDpFGTMNjisLSQeCVwlrwUTbP
acNiIn4NjhNznJOSPTscZbp0qHiSshZKg.F4aKi0j41XMdjIR9VaqduHTnHD
32V7IUnaxjXvuTjuC7EwCbvujjI+sEyWopNRC4VsQnG9HzcB7XwxlGTVIbc5
4uTAZu3bWPMOCnNNzEcsNe9MBo2DjzG5ouQ30GURVnshSclfY.D1mof+jww5
qlbOX4oChq9TWffroif3qMAQ8gfdSF875E+4NozC1WkjqkRoeG5jnoXA0oWl
glNAHRuPX+okf3KQPjyzRPzEIHbZI3EWBmNYVneenGYxnGx4JSO30kd3qL45
E6gmNap394FtzvvUKRGmNrpBmhY.o2r7D4GoeQSNcFAn3Wyh5rDNY+lB5KUY
qSgoXcl1q.9nSW7PTuq75rKq2f7zPP1U1XAqelemNU0dY9k09JXYhmmbw9Lj
5zKz2oWluVtHem4R78hKvWYc800E268uSMf+GaBSX4A
-----------end_max5_patcher-----------

my bad - yes, i guess Midi.send expects a table for raw data.

i dont’ really have time test the midi stuff directly myself. i will take a look at your patch and see if i can suggest something.

1 Like

That’s greatly appreciated.

first problem.

this data table includes the sysex start byte 0xf0. (systex data bytes must be in [0-127].) you need to omit the start byte as well as the end byte if we are already sending them.

in other words: the raw data you send to the norns midi device for sysex, is exactly the same as the raw data you send to the max midiout object.

second problem.

on the norns side… again i’m not testing this but i think the answer is that you have to send one byte at a time.

so in my snippet, for “--- send sysex bytes...”, you would have a loop.

i’d say this is complex enough to warrant a helper function. maybe just Midi:send_sysex(data) since it doesn’t really follow the assumptions of the other helper message types.

posting code for such a function momentarily…

-- @param m: a midi device 
-- @param d: a table of systex data, omitting the framing bytes
function send_sysex(m, d) 
  m:send{0xf0}
  for i,v in ipairs(d) do
    m:send{d[i]}
  end
  m:send{0xf7}  
end

you could try that and let us know how it goes.

apologies that my first snippet was initially unclear and used the wrong function-call syntax, obscuring my point: that sysex messages are just streams of bytes, “meaningless” except for the framing values. if you’re already adding the protocol bytes by hand, there’s literally nothing else to add to the MIDI API to support this.

2 Likes

Ah you have to send each code separately, i see the iter now in the max patch too.

You just made my norns like a billion times more awesome (for me at least)

image

5 Likes

excellent, that’s good to hear.

yeah, one reason we closed that issue is that from the norns system perspective, there is not much we could meaningfully add to support sending sysex in a “general” sense. (i suppose the API could check the data for accidental inclusion of non-data bytes. this exchange demonstrates some possible utility to that.)

for receiving sysex from hardware, it’s a little more complex but not much; you would hack something like this into a script:

-- state variables.
sysexDataFrame  = {}
handlingSysex = false

handleSysexDataFrame = function()
-- parse the data and whatever
  parse(sysexDataFrame)
-- empty the data frame
  sysexDataFrame = {}
end

-- m is a midi device
m.event = function(data) 
  if handlingSysex
    if data == 0xf7          -- this is a stop byte
      handlingSysex = false 
      handleSysexDataFrame()
    else                      -- assuming this is a data byte
      table.insert(sysexDataFrame, data)
    end
  else
    if data == 0xf0         --- this is a start byte
      handlingSysex = true
    else
      -- handle other message types
    end
  end
end

(ok, that could be more elegant, like just branch on the top bit, but you see what i mean.)

for more general support we could add that boilerplate to the midi device class. but honestly, once more i’m not sure it really solves a lot of problems. if you are gonna make, say, a TG77 patch manager on norns (which by the way would be very cool, and a kind of use case that we’ve always supported), this requires implementing all the TG77-specific protocol anyway. so the sweet spot for abstraction isn’t the sysex framing and state management, it’s having someone making e.g. a TG-77 specific library that knows a little more about how the data frames are structured.

4 Likes

Yeah I think my issue was more that i didn’t understand what sysex is… I think my understanding is a bit better and should allow me to do everything i want. Fortunately i dont have to read sysex messages from the push, the knobs and buttons are all regular midi events, but that does seem like an interesting way to share data.

My first little project will be a library that lets the user assign script parameters to each of the 8 knobs on the fly. The LCD will just display the parameter name and the current value.

1 Like

So it seems that my code works just fine using normal numbers instead of hex. Is there a good reason to use hex in this situation?

regular brain: hexadecimal is typical for representing raw byte values such as midi payloads

expanding brain: if anything, decimal values are an abnormal representation that are included in programming languages only for human convenience

galaxy brain: if you try to represent even a single nontrivial normal number you will use up all available memory and the operating system will terminate the process

6 Likes

i’ll bite: [*]

this is one of many cases in computer-land where byte values have a semantic meaning (MIDI command codes) that is unrelated to their scalar value. (in other words, we don’t do arithmetic with MIDI command codes, and it wouldn’t be very useful to express noteon as noteoff +16.)

instead, we get closer to the semantic meaning of the MIDI codes by considering them as bit sequences, and we can easily distinguish the command nybbles 0x8_ for note-off and 0x9_ for note-on, noting that they differ by a single bit. (e.g., i can pretty easily read 0x95 and 0x85 as “note-on followed by noteoff on channel 5”, whereas if i read “149, 133” i would have to perform a mental divide-by-16-plus remainder.)

for example: given some familiarity with hex notation, the 0xf_ values in your systex string jump out immediately as having the top bit set (as any value >= 0x80 does.)

accordingly they stand out as illegal MIDI data values (having the top bit set means they will be interpreted as commands.) a base-16 notation corresponds more directly to a bit pattern: in decimal, i would be visually examing all three digits to determine whether a given value is > 127.

it’s also concise, and signals immediately to the reader of the code that these are values that fit in an 8 bits of memory (2 hexadecimal digits), and that they are probably going to be transmitted, stored or manipulated in a byte-wise fashion.

[* no pun intended]

9 Likes