MidiAutomationHandler
This class is a interface for modifying the MIDI control assignments in HISE through scripting.
You can:
- edit / change the list of assignments
- attach a callback (or broadcaster) that listen to changes of MIDI control assignments
- customize the behaviour / appearance of any MIDI assignment related interactions.
A common practice in plugins is the ability to right click on a control and assign it to a MIDI CC controller so that it can be controlled by hardware controllers (or MIDI clips from the host).
This can be achieved in HISE by setting the enableMidiLearn
property of any suitable component (slider / button / combobox) to true (or set the allowMidiAutomation
property in the JSON object that you pass into UserPresetHandler.setCustomAutomation()
if you're using the custom automation model).
The assignments can be modified using the MidiLearnPanel floating tile which allows you to remove connections, modify the range of how the parameter is mapped and invert the parameter.
However if you need more flexibility you can use this class and implement your own MIDI assignment interface.
Note that MIDI assignments are stored in the user preset system by default, so you don't need to use this class for data management.
Class methods
getAutomationDataObject
Returns an object that contains the MIDI automation data.
MidiAutomationHandler.getAutomationDataObject()
This method returns an array with JSON objects for every MIDI control assignment that is present. The JSON object will have these properties:
Property | Type | Description |
Controller
|
int | the CC number (zero based) of the MIDI assignment. |
Channel
|
int | the MIDI channel of the MIDI assignment (see below). This is one-based(!) and a omni connection that applies to all MIDI channels should have the value -1
. |
Processor
|
String | the ID of the module that connects to the MIDI control. This is most likely your Interface. |
Attribute
|
String | the ID (not the index!) of the attribute that the MIDI assignment is supposed to control. |
MacroIndex
|
int | if the control is mapped to a macro control, this will contain the index. |
Start
|
double | the current start of the mapped range as it was set in the MidiLearnPanel. By default this is equal to the FullStart
property. |
End
|
double | the current end of the mapped range as it was set in the MidiLearnPanel. By default this is equal to the FullEnd
property. |
'Inverted' | bool | whether the MIDI assignment should invert the value range (basically what the Invert button does on the MidiLearnPanel). Note that this does not affect the Start
and End
properties and it's still expected that Start < End
. |
FullStart
|
double | the lower limit of the range that can be set (in the MidiLearnPanel this would be the min value of the range sliders). |
FullEnd
|
double | the upper limit of the range that can be set (in the MidiLearnPanel this would be the min value of the range sliders). |
Skew
|
double | the logarithmic skew of the range that can be used for changing the gamma curve of the MIDI assignment. |
Interval
|
double | the step size of the MIDI assignments. For discrete controls this can be 1.0
. |
Converter
|
String | a spurious Base64 string that will contain the encoded text to value converter so that it displays the values correctly. |
Note about the Channel property
Starting with HISE 4.5.0 there is the ability of filtering MIDI CC messages by MIDI channel, so that you can eg. assign the modwheel of the MIDI channel 2 to another control than the modwheel of the MIDI channel 1.
By default this is deactivated (so in our example any modwheel message from any channel would control an assigned UI element). If you don't see the Channel
property in the JSON object, you have to enable the support for different MIDI channels by adding HISE_USE_MIDI_CHANNELS_FOR_AUTOMATION=1
to your Extra Definitions field
(you don't have to recompile HISE for it to be applied though).
Data Example
Here's one JSON object in its full glory:
[{
"Controller": 1,
"Channel": 0,
"Processor": "Interface",
"MacroIndex": -1,
"Start": 0.0,
"End": 1.0,
"FullStart": 0.0,
"FullEnd": 1.0,
"Skew": 1.0,
"Interval": 0.01,
"Converter": "37.nT6K8CBGgC..VEFa0U1Pu4lckIGckIG.ADPXiQWZ1UF.ADf...",
"Attribute": "Knob1",
"Inverted": false
}]
setAutomationDataFromObject
Sets the MIDI automation from the automation data object.
MidiAutomationHandler.setAutomationDataFromObject(var automationData)
This can be used to modify the list of MIDI assignments programmatically. It expects an array of JSON objects with the exact format as described in the method above and will replace all MIDI assignments with this data and send an update message to the MidiLearnPanel
and any attached callback
.
function modifySecondController()
{
// grab the existing list
var list = mh.getAutomationDataObject();
// set the second range start to 50%
list[1].Start = 0.5;
// send the list back to the automation handler.
mh.setAutomationDataObject(list);
}
setConsumeAutomatedControllers
Sets whether a automated MIDI CC message should be consumed by the automation handler (default is enabled).
MidiAutomationHandler.setConsumeAutomatedControllers(bool shouldBeConsumed)
This setting specifies whether a MIDI control that is assigned to a UI control should be excempted from further processing. The default value for this is true
(so HISE will not forward a MIDI control message to its internal processing chain if it was assigned to a UI control), but for some projects you might want to enable this to be able to process all MIDI messages, regardless of the MIDI assignments.
setControllerNumberNames
Replaces the names in the popup.
MidiAutomationHandler.setControllerNumberNames(var ccName, var nameArray)
This can be used to modify the appearance of the context menu. By default it displays the controller types as "CC #2"
, but if you don't like that, you can customize the strings used for the popup menu as well as the text "Add XXX" / "Remove XXX" for the ultimate UX customization!
ccName
must be a string and ccNames
an array with strings. Note that the length of ccNames
must be either 127 or the exact length of the array you passed into MidiAutomationHandler.setControllerNumbersInPopup()
mh.setControllerNumbersInPopup([1, 2, 7]);
mh.setControllerNumberNames("Funky Controller!!!", ["Modwheel", "Breath Controller", "Volume"]);
The context menu will then look like this:

setControllerNumbersInPopup
Sets the numbers that are displayed in the MIDI automation popup.
MidiAutomationHandler.setControllerNumbersInPopup(var numberArray)
This can be used to modify the appearance of the context menu. By default it displays all 127 CC numbers in a submenu, but if you don't like that, you can limit the list of available entries by supplying a list of CC numbers that you want to show.
setExclusiveMode
Enables the "exclusive" mode for MIDI automation (only one active parameter for each controller).
MidiAutomationHandler.setExclusiveMode(bool shouldBeExclusive)
By default you can assign a single MIDI controller to multiple UI controls so if you want to eg. control the volume of multiple channels with your modwheel this can be achieved by assigning it to those controls.
However this might be an unwanted behaviour for your project so if you want to ensure that there is only a single connection for each MIDI control present, call this function with true
and it will change the behaviour of the context menu:
- It will grey out MIDI assignments that are already connected to another MIDI controller.
- When you enable MIDI learn and then assign a controller to a knob, it will remove any existing connection to other controls for this particular MIDI controller. Note that if you are using
HISE_USE_MIDI_CHANNELS_FOR_AUTOMATION=1
to support different assignments for MIDI channels, it will retain connections from different MIDI channels, but remove "Omni" connections as well as connections with the same channel.
Note that this logic will not be used to check the data you pass into MidiAutomationHandler.setAutomationDataFromObject()
so you must take care of avoiding duplicates in there yourself.
setUpdateCallback
Set a function (with one parameter containing the automation data as JSON) that will be executed whenever the MIDI automation changes.
MidiAutomationHandler.setUpdateCallback(var callback)
This can be used to attach a function (or Broadcaster
) to be notified whenever the MIDI assignments change). The events that cause this call back are:
- adding / removing connections through the context menu selection
- when MIDI learn is active and a suitable MIDI message was received
- removing connections with the MidiLearnPanel .
- calling MidiAutomationHandler.setAutomationDataFromObject()
- loading user presets (this includes the initial preset)
Note that changing the properties of a connection (eg. the range) in the MIDI learn panel does not send an update message.
Whenever one of these events is happening, it will asynchronously call this function. It expects a callable object with a single parameter which contains the JS array with JSON objects exactly as returned by MidiAutomationHandler.getAutomationDataObject() .
const var mh = Engine.createMidiAutomationHandler();
mh.setUpdateCallback(function(obj)
{
Console.print(trace(obj));
});
Never call MidiAutomationHandler.setAutomationDataFromObject() inside this function or it will cause an endless loop of callbacks! Note that trying to outsmart this rule by using a simple recursion protection would not work as the update message is asynchronous.
const var mh = Engine.createMidiAutomationHandler();
// This freezes your computer.
mh.setUpdateCallback(function(obj)
{
obj[0].Start = 0.5;
mh.setAutomationDataFromObject(obj);
});
var recursion = false;
// Good idea and extra points for using scoped statements,
// but this freezes your computer too because the update message
// will be called asynchronously...
mh.setUpdateCallback(function(obj)
{
if(!recursion)
{
.set(recursion, true);
obj[0].Start = 0.5;
mh.setAutomationDataFromObject(obj);
}
});