Search code examples
midisysex

Strings encoded in the body of Midi SysEx - help decoding?


I'm trying to work out how to send sysex to my fractal audio FM9 to change the name of a scene. I've been able to capture the sysex that is being sent by the management application (using Wireshark) for a range of strings, but I'm falling short to understand how the string value is encoded into the body of the sysex message.

So first things first, I think I have detected the bytes that contain the encoded string. The full sysex that is sent to change the scene name to "Clean"

f0 00 01 74 12 01 2b 00 00 00 00 00 00 00 00 00 00 00 00 20 00 24 5b 4e 47 13 3c 40 20 10 08 04 02 01 00 40 20 10 08 04 02 01 00 40 20 10 08 04 02 01 00 40 20 10 08 04 02 00 45 f7

Now I can see from the various settings that the data seems to start at offset 19, however all settings I have made so far have 0x20 in position 19 and 0x00 in offset 21, so the data probably do start at offset 22 and occupy 37 bytes (the last maybe being a null terminator?).

The maximum length of a string that can be entered is 31 characters. Here is a set of examples of the sysex that is produced based on various input strings, of interest to me is that the second last byte has the low order nibble of 0010 (2). Spaces seem to work out to 40 20 10 08 04 02 01 00, which I think might be a pattern of descending masks (bit shifting right over a pattern of 8 bytes), ....I'm just not seeing the pattern!

enter image description here

I'm hoping someone may have encountered this before and be able to suggest an approach.

Thanks in advance


Solution

  • This isn't pretty but it isn't high volume and it works based on what I've tested so far. I just dump out the binary into a string and then take 7 bits at a time and return that as a byte array.

    I'm quite sure there's a way to do this without strings, but it will do for now.

    static byte[] TranscodeString(string input)
    {
        var source = (input.PadRight(31, ' ').Select(x => ((byte)x).ToString("B8")).Aggregate((x, y) => x + y).PadRight(250, '0') + "10")
            .Select((x, i) => new { Key = i / 7, Byte = x })
            .GroupBy(x => x.Key)
            .Select(x => x.Select(y => y.Byte.ToString()).Aggregate((a, b) => a + b))
            .ToArray();
        var result = source.Select(x => Convert.ToByte(x, 2)).ToArray();
        return result;
    }