SuperDirt
SuperDirt copied to clipboard
Sysex syntax
Hi there! I've spent some time trying to send Sysex messages from Tidal to an outboard sampler without any luck.
What is the correct syntax to use?
An example sysex message :
0xF0, 0x47, 0x5F, 0x00, 0x69, 0x02, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x09, 0xF7
From SuperCollider i can send the following without any problem:
~midiOut.sysex(Int8Array[0xF0, 0x47, 0x5F, 0x00, 0x69, 0x02, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x09, 0xF7 ])
in Tidal, the following doesn't work, as it throws "Wrong Type" errors:
once $ midicmd "sysex" # array "0xF0, 0x47, 0x5F, 0x00, 0x69, 0x02, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x09, 0xF7" # midichan 0 # s "midi"
# array
expects a Pattern Double
and the sysex
method in Supercollider expects an Int8Array
. I couldn't find this trasnformation anywhere so i added this line in the DirtEventTypes.sc
file, inside the midiEvent( play: {} )
block :
if(~array.notNil) {midicmd = \sysex; ~array = Int8Array.newFrom([~array.asInteger]) };
this solves the Error problems but I don't know of a way to send the full sysex message as one continuous List, since Tidal breaks it into a pattern.
I've tried stack
, sometimes it manages to send it, but always in a random order
once $ array (stack [0xF0, 0x47, 0x5F, 0x00, 0x69, 0x02, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x09, 0xF7]) # midichan 0 # s "midi"
Please advise! Thanks and bests, Tad
Hi @tadklimp,
My guess is that array
is defined as a pattern of doubles in error. I think it's better sent as a string, which I think is the only 'array'-like type in the open sound control protocol standard.
The following tries to send it as a string:
import Data.Char (chr)
once $ pS "array" (pure $ map chr [0xF0, 0x47, 0x5F, 0x00, 0x69, 0x02, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x09, 0xF7]) # s "midi" # midicmd "sysex"
However, that didn't work out of the box. I guess superdirt needs something to translate from string to Int8Array.
Hi @yaxu ,
thanks a lot for this! Almost there ... :-D I tried your suggestion and here are some observations:
- the message arrives as a
Symbol
class in SuperCollider, not aString
- the only way i could read it was to transform it into ASCII , otherwise it appears as unknown characters.
- Here is a crude way to transform and print the message and also tweak the Ascii results [i guess ascii values above 128 appear as negative in supercollider?]
if(~array.notNil) { {
var asciiArray = ~array.ascii; // transform msg into an array of ascii
var numList = List.new; // a new List placeholder
asciiArray.do({ |i|
if(i.isNegative)
{ i= 256+(i); numList.add(i)} // for neg. values add 256
{ numList.add(i) };
});
numList.postln; // post the received msg
}.value
};
I placed the above snippet in the DirtEventTypes.sc file, inside the midiEvent( play: {} )block.
With the above, everything looks good, except one very strange thing:
-
if the Sysex string includes
0x00
or0
, the value is not accepted and the following is posted on the SuperCollider window:`no synth or sample named 'nil' could be found.`
I guess that the Sysex message 0
is transformed through OSC into the symbol \0
and tries to trigger a synth ?? I cannot understand.
Any ideas?
Thanks and bests, Tad
@tadklimp Ah, I suppose the string is treated as 'null-terminated' somewhere resulting in data corruption. Looking at the OSC spec, Tidal really needs to be sending this as an 'OSC blob' rather than a string (I was wrong about string being the only suitable field). Tidal doesn't support this currently but it won't take long to add. I'll make a separate issue for that and try to look at this later on.
Investigating this a bit more:
Saving the above snippet in DirtEventTypes.sc and sending the following from Tidal:
once $ pS "array" (pure $ map chr [0xF0, 0x47, 0x5F, 0xF7, 0x00, 0x04, 0xF4 ]) # s "midi"
The value 0x00
and anything after it is not even being sent, or they are truncated?
Is it that 0x00
is "understood" as nil
and thus as the end of the OSC message?
There are some issues with how SuperCollider treats incoming OSC messages (here and here ) but is beyond my understanidng.
@telephon do you have any ideas on this?
thanks a lot!
Hi @yaxu , we posted simultaneously! :-) Thanks for this! Looking forward to an update! Best, Tad
Yep I'm confident switching to blobs will solve this one!
@yaxu has this been solved?
Yes I think so, apart from documentation, but the tidal issue can stand for that.
Hi @yaxu and @telephon,
after a long hiatus I'm experimenting with Tidal and Sysex again. I'm using Tidal 1.6.1 and Supercollider 3.10.2 on OSX 10.11.6.
It seems that the sysex messaging is currently broken?
When evaluating the following:
once $ array (pure [0xF0, 0x47, 0x5F, 0x00, 0x69, 0x02, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 12, 0xF7]) # s "midi" #midicmd "sysex"
this error is printed in SC3:
ERROR: Primitive '_SendMIDIOut' failed.
Wrong type.
RECEIVER:
Instance of MIDIOut { (0x118386328, gc=3C, fmt=00, flg=00, set=02)
instance variables [3]
port : Integer 1
uid : Integer 2081379076
latency : Integer 0
}
CALL STACK:
MethodError:reportError
arg this = <instance of PrimitiveFailedError>
Nil:handleError
arg this = nil
arg error = <instance of PrimitiveFailedError>
Thread:handleError
arg this = <instance of Thread>
arg error = <instance of PrimitiveFailedError>
Object:throw
arg this = <instance of PrimitiveFailedError>
Object:primitiveFailed
arg this = <instance of MIDIOut>
MIDIOut:write
arg this = <instance of MIDIOut>
arg len = 3
arg hiStatus = 128
arg loStatus = [*14]
arg a = 60
arg b = 64
MIDIOut:noteOff
arg this = <instance of MIDIOut>
arg chan = <instance of Int8Array>
arg note = 60
arg veloc = 64
Function:awake
arg this = <instance of Function>
arg beats = 379.71125616548
arg seconds = 379.71125616548
arg clock = <instance of Meta_SystemClock>
var time = 379.71125616548
^^ The preceding error dump is for ERROR: Primitive '_SendMIDIOut' failed.
Wrong type.
RECEIVER: a MIDIOut
I managed to "fix" it by inserting the following code in DirtEventTypes.sc
:
if(~array.notNil) { val = ~array; ~uid = midiout.uid ; donecmd.value(\sysex); schedmidi.value({ midiout.sysex(val) }) };
This sends the Sysex message but also sends a note-On and note-Off message.
To avoid that I changed the hasNote
variable definition in the same file from:
var hasNote = (~n != \none or: {~note.notNil} );
to this:
var hasNote = (~array.isNil and: {(~n != \none or: {~note.notNil} )} );
Now everything works fine and the following code works:
once $ array (pure [0xF0, 0x47, 0x5F, 0x00, 0x69, 0x02, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 12, 0xF7]) # s "midi"
Maybe there is a more elegant way to solve this?
cheers! Thomas
you could test if sysex works if you send directly from sclang (https://sccode.org/1-4Zg)
thanks @telephon,
with the above mentioned code added to the DirtEventTypes.sc
file, sysex works fine, both from Tidal and sclang.
I was just wondering if my "hack" is valid, or there is a better solution.
ah I didn't see this. There is a standard way to send arrays, in this case probably as blobs as @yaxu said. I'm not sure if this hack is optimal. Perhaps you could also take a look at the RawArray
subclasses in sclang, maybe there is a better way of direct conversion. I'm not sure right now …