This page covers:

  • What is "automation"
  • Channel-to-preset mapping
  • MIDI hotkeys
  • MIDI playback switches
  • Looping randomizer
  • Websockets

What is "automation"

For the purposes of this page, "automation" is anything that automatically adjusts Keysight settings somehow. There is the Automation tab, but a few other places that automation can occur. Automation can be incredibly powerful for live performances, but also has application in video rendering.

Channel-to-preset mapping

Automation > Channel-to-preset mapping

This is the primary method for visualising different hands in a MIDI file. Channel data (or track data) must be present in the MIDI file for this to work! Check the Log to ensure your MIDI file has working channel data.

Channels

When this tab is enabled, the non-dynamic elements of the preset (Scene / Light bars / Scene lights etc.) will use the currently selected preset, but any spawned effects will switch to the preset in their corresponding dropdown menu.

Channel colour mode also exists, but full channel-to-preset mapping allows for complete control over colour and effect style per MIDI channel.

Warning

Channel-to-preset mapping uses preset index as the mapping target, not the preset name! If you shuffle presets around, the mapping will also change.

MIDI hotkeys

Automation > MIDI hotkeys

A variety of actions can be performed via MIDI triggers as set up in this menu. This is primarily intended for live-streaming to provide Keysight control without moving from the piano.

MIDI toggles

The first toggle will disable just the given action. The second toggle enables "exclusive" mode, where only the given MIDI key combination must be down for the action to trigger.

Recording hotkeys

After adding a new action, a key combination must be recorded for it to be triggerable (obviously). While recording, the keys currently held are logged, and the combination of the maximum number of held keys is saved as the shortcut once all keys are released again.

Info

If setting up hotkeys for live-streaming, it is strongly recommended to use one key at one end of the piano, and then another key at the other, to try and make sure hotkeys are not triggered accidentally during performance. It can also be useful to have a conceptual "domain" for actions bound to, say, the lower note (for example: A0 = "preset switch"), and then changing the upper register key for different actions within that conceptual domain (for example: A0 + C8 = preset slot 1, A0 + B7 = preset slot 2, etc.).

Actions

  • Reload preset from file
    • Useful if the current preset has been randomized and you want to reset to the saved version of it
  • Load preset (file)
    • Switches to the given slot, and attempts to load that slot from the saved file. This is typically the most useful way of switching presets
  • Load preset (memory)
    • Switches to the given slot, but does not load it from the saved file. This means if the preset slot has been altered (e.g. via the Randomizer), those changes are not reset
  • Transpose up/down/reset
    • Useful if you transpose on your keyboard on the fly, and wish to make sure Keysight mirrors the transposition you're using
  • Randomize
    • Triggers the Randomizer. Can be useful for generating new presets on the fly while performing
  • Overdrive randomize
    • Triggers the Randomizer but with horrible settings to produce very obnoxious presets
  • Reload current preset from file
    • Reloads the currently selected preset from file, if it exists. Useful for reverting randomization on your current preset
  • Undo
    • Self-explanatory
  • Redo
    • Self-explanatory
  • Enable websocket
    • Enables websocket actions. Useful if you want to toggle chat-control during livestreaming
  • Disable websocket
    • Disables all websocket actions except any "Enable websocket" websocket actions

Non-MIDI hotkeys

There are a few hard-wired hotkeys provided by Keysight too:

  • Number row 1 - 0 will switch to preset slot 1 - 10 respectively
  • Controller LB / L1 and RB / R1 cycle preset slots
  • More niche hotkeys can be found under the Controls tab

Warning

The number row keys require Keysight to be the focused window by the operating system, which is often not the case while live-streaming.

MIDI playback switches

MIDI

The active preset can also be switched automatically during MIDI playback at set times using the following menu:

Playback switches

These switches trigger at the given time during MIDI playback. It is recommended to set a time just ahead of when you want the switch to occur, to ensure it occurs the frame before your intended switch time.

Info

When in top-down mode, these switches trigger Note Objects to change immediately and then the scene to change after waiting the given time-delay time. This means elements like the Backdrop only change once "new" notes reach the keyboard. This behaviour can be disabled under System > Interface, Misc. section.

Looping Randomizer

(Disambiguation) The Randomizer can be set up to trigger itself on a looping timer. This is covered in detail on the relevant page here.

Websockets

System > Websockets

Websockets can be an enormously powerful tool for automation, allowing remote control of Keysight. The most common implementation of this is chat-controlled Keysight in a live context, but the possibilities are only limited by your programming ability and imagination!

Unfortunately, websockets are implemented via the Socket.IO Client➚ plugin, as it was the only real option available when originally building out this feature. Websockets use Socket.IO version 2.X only, and do not support generic websockets or Socket.IO 3.X!

Keysight is a websocket client. Setting up a websocket server is the responsibility of the user.

Note

I cannot really offer a lot of support for websocket-server-related activities, as I have absolutely no clue how to actually develop things like that! All guides and info on websockets, minus the Keysight-side documentation, are created by the community.

Inbound

Inbound

The toggle labelled 1 will attempt to connect/disconnect from the given address. The toggle labelled 2 will block inbound websocket actions (except any "enable websocket" actions) without disconnecting (useful for temporarily disabling chat control).

  • Address
    • Address and port to connect to. Should attempt to disconnect and reconnect if changed while websocket is active. Seems to default to local address if left blank, which some implementations exploit, but I cannot recommend doing this as it seems unreliable
  • Password (optional)
    • When connecting, a JSON header containing the field Pass is filled out with the given password
  • Event name
    • Event name that Keysight listens to to receive websocket messages

Responses

While Broadcast responses is enabled, Keysight will output a message back over the inbound websocket with information after a successful websocket action execution.

This message is broadcast over an event name that is the received message (clamped to 20 characters), and is simply:

{"reply":"[response message]"}

This is intended to provide a way of giving feedback on successful actions back into your livestream chat. The exact response message depends on the action, but typically it will look something like Loaded '{Name}' preset from file (slot index: {index})

Preset display

There is a hidden function built just for my own stream that also provides information on the current preset in Keysight, intended to be sent to a browser source for capture in OBS. Whenever preset information changes (including edge cases like looping randomizer etc.), a message of {"display":"[display message]"} is broadcast over the display event name.

Actions

When adding a new action, the string field provides the trigger message Keysight is listening for to execute this action. Multiple trigger strings can be provided with the / character, like so:

Input strings

Messages of quicksilver, 1, preset 1, and default will all trigger this action. Many actions, like this "Load preset (file)", also require an index. The field to the right containing 1 is specifying that this action should use a preset index of 1.

Note

I'm not going to explain the meaning of every action here, sorry! Only the important ones. If you're here and messing around with websockets, I trust you to understand that the "Undo" action presses the undo button in Keysight.

Several actions have unintuitive function or require special incoming message formats to function:

  • Randomize (seed)
    • Possibly the most important action. The incoming message to trigger this action must be in the format [trigger]:[seed]. That is, if providing the input string of seed and wishing to randomize using the seed test, the incoming websocket message must be seed:test
  • Query seed/preset
    • An information-only command. Does nothing inside Keysight, but provides a websocket response message with the current seed text and internal integer for the preset if it is randomized, or the slot name if it not randomized
  • Enable websocket
    • This action will still be accessible even if the websocket is otherwise disabled. Intended to give moderators a way of turning on and off the websockets from chat
  • Update camera
    • Provides a new set of Core > Visual layout settings. Functions similarly to Randomize (seed), but expects a full JSON with the following format:
{
    "X":0.0,         // maps to "Position X"
    "Y":0.0,         // maps to "Position Y"
    "Z":0.0,         // maps to "Position Z"
    "tilt":0.0,      // maps to "Rotation X (roll)"
    "rotate":0.0,    // maps to "Rotation Y (up/down)"
    "roll":0.0,      // maps to "Rotation Z (left/right)"
    "localRoll":0.0, // maps to "Origin Y"
    "FOV":0.0        // maps to "Field-of-view"
}

This also forces the layout to be in Manual mode. The original purpose of this action was to switch augmented-reality camera angles for JonathanOng➚ when switching his IRL angle, but theoretically it could also be used to have an external tool choreograph camera movement inside Keysight.

Outbound

Keysight also has an outbound websocket intended to output simulation and colour information from Keysight.

Outbound

The provided output frequency is bound by the framerate of Keysight, and does not run on a seperate thread. If you set a frequency of 120Hz but Keysight is running at 60 frames per second, you're only going to get an output frequency of 60Hz.

Basic output

While Send basic lighting and colour information is enabled, a small JSON containing a colour hex and float value is broadcast. The colour is derived from the colour settings used by the Impact lights of the current preset, and forced to the Cycling colour mode with the given shift speed. The float value is the current total activity (measured at the keyboard, if in top-down mode). The JSON is as follows:

{
    "bCol":"#FFFFFF",
    "bStr":1.2345
}

This is intended for controlling ambient lights in a room with colours that match the current Keysight Impact lights, optionally with some sort of brightness modifier based on activity.

Advanced output

While Send per-key lighting and colour information is enabled, a much larger JSON is sent. This is intended for LED strip control, and operates in two modes:

Send only colours and held notes disabled

This sends the current activity and colour hex for all 88 keys in two arrays (with colour coming from Impact lights):

{
    "aStr":[
        0,
        0.768, 
        0, 
        0.654,
        ... 
        0
    ],
    "aCol":[
        "",
        "#A700FF", 
        "", 
        "#8F00FF",
        ... 
        ""
    ]
}

Warning

Receiving this JSON at 60Hz can be too much for some microcontrollers!

Send only colours and held notes enabled

This sends a single array containing just the full-brightness colour hex of all 88 keys if that key is held down, otherwise the array contains a blank string:

{
    "aCol":[
        "",
        "#A700FF", 
        "", 
        "#8F00FF",
        ... 
        ""
    ]
}