Encoding user created content in a URL

I’ve just updated my MIDI Surf app that I posted about a few weeks ago, adding a feature where users can share the MIDI controllers that they make. Just to give everyone the background, MIDI Surf is a highly customisable web-based MIDI controller, which you can use to control a range of musical devices like synthesisers, samplers, lighting rigs etc.

With the initial release, there was no (easy) way to save the controllers that you made, which is a pain, as it can be quite a labourious process to make a controller in the first place, given that you need to dig through the device manual to figure out what you can control and how you control it. I wanted users to be able to share via a URL, and while I could do this with a server, I wanted to keep the whole thing as simple as possible, so I tried encoding the controller into the URL. I know this isn’t a new idea, but I’m really pleased with how seamlessly it worked!

The bulk of the controller data is contained in a recursive data type called Controller, which looks like this:

type Controller
    = Module String Controller
    | Row (List Controller)
    | Column (List Controller)
    | Note NoteState
    | Chord ChordState
    | CCValue CCValueState
    | Command CommandState
    | Sequence SequenceState
    | Fader FaderState
    | XYFader XYFaderState
    | PitchBend PitchBendState
    | MidiLog
    | Space

So to create something like this:

It is built up from a Column containing multiple Rows with various different buttons that send note information or change parameters on the synth.

The state of your controllers was already saved to local storage using a port, encoding the value using the excellent miniBill/codec library, which makes the recursive data type a breeze to work with. When adding the save feature, I built on this by enabling users to export this as string to a file and then importing it back in. To make the URL feature, I initially tried to make a really terse encoding by hand with a corresponding parser, but I remember reading that JSON compresses really well with GZIP, so thought that maybe I could just encode the string, convert it to bytes, compress it and then base 64 encode it, then chuck in a url as a query string. I’m using elm/bytes, folkertdev/elm-flate, danfishgold/base64-bytes:

encodedPage =
    Codec.encodeToString 0 pageCodec page

 compressedPage =
    encodedPage
        |> Encode.string
        |> Encode.encode
        |> Flate.deflateGZip
        |> Base64.fromBytes

For a relatively simple controller, I get around 4x compression, but on the most complex one I’ve tested, I get over 12x (15633 chars to 1248). It’s pretty much instantaneous on all the devices I’ve tested too. This link should open MIDI Surf and ask you if you want to import a controller called “Elm Discourse”.

Anyway, I thought people might be interested. Here’s the source if you fancy a gander: GitHub - mochreach/midi-surf: A flexible and powerful MIDI controller in your browser!. Thanks to @miniBill, @folkertdev, danfishgold and @evancz for the libraries that make this work.

14 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.