afterglow.controllers
Provides shared services for all controller implementations.
activate-cue!
(activate-cue! grid x y id)
Records the fact that the cue at the specified grid coordinates was activated in a show, and assigned the specified id
, which can be used later to determine whether the same cue is still running. If id
is nil
, the cue is deactivated rather than activated.
Sends appropriate MIDI feedback events to any non-grid controllers which have requested them for that cue, so they can update their interfaces appropriately, then calls any registered functions that want updates about the cue state letting them know it has started, its effect keyword, and the id
of the effect that was created or ended.
active-bindings
(active-bindings)
Returns the set of controllers which are currently bound to shows.
add-active-binding
(add-active-binding controller)
Registers a controller which has been bound to a show, and which should be deactivated when deactivate-all is called or the JVM is shutting down, to gracefully clean up the binding.
add-beat-feedback!
(add-beat-feedback! metronome device channel kind note & {:keys [on off], :or {on 127, off 0}})
Arranges for the specified non-grid MIDI controller to receive feedback events to make a particular LED flash on each beat of the specified metronome.
add-control-held-feedback-overlay
(add-control-held-feedback-overlay state control-num f)
Builds a simple overlay which just adds something to the user interface until a particular control (identified by control-num
) is released, and adds it to the controller. The overlay will end when a control-change message with value 0 is sent to the specified control number. Other than that, all it does is call the supplied function every time the interface is being updated, passing it the metronome snapshot which represents the moment at which the interface is being drawn. If the function returns a falsey value, the overlay will be ended.
As with add-overlay, state
must be a value created by create-overlay-state and tracked by the controller.
add-cue-feedback!
(add-cue-feedback! grid x y device channel kind note & {:keys [on off], :or {on 127, off 0}})
Arranges for the specified non-grid MIDI controller to receive feedback events when the cue grid location activates or deactivates.
add-cue-fn!
(add-cue-fn! grid x y f)
Arranges for the supplied function to be called when the cue grid location activates or deactivates. It will be called with three arguments: the first, a keyword identifying the state to which the cue has transitioned, either :started
, :ending
, or :ended
, the keyword with which the cue created an effect in the show, and the unique numeric ID assigned to the effect when it was started. The last two argumetnts can be used with end-effect! and its :when-id
argument to avoid accidentally ending a different cue.
add-overlay
(add-overlay state overlay & {:keys [priority], :or {priority 0}})
Add a temporary overlay to the interface. The state
argument must be a value created by create-overlay-state, and overlay
an implementation of the IOverlay protocol to be added as the most recent overlay to that state. The optional keyword argument :priority
can be used to modify the sorting order of overlays, which is that more recent ones run later, so they get the last word when it comes to rendering. The default priority is 0
.
auto-bind
(auto-bind show & {:keys [device-filter], :as args})
Watches for a recognized grid controller to be connected, and as soon as it is, binds it to the specified show using bind-to-show. If that controller ever gets disconnected, it will be re-bound once it reappears.
If you would like to limit the controllers that Afterglow will automatically bind to, you may supply a filter with the optional keyword argument :device-filter
which uniquely matches the MIDI ports used by the devices you want to be auto-bound. The values returned by afterglow.midi/open-inputs-if-needed! and afterglow.midi/open-outputs-if-needed! will be searched, and any pair of identically-named ports that are accepted by your :device-filter
with filter-devices will be bound if they are attached to a controller type that Afterglow knows how to work with.
The controller binding implementation chosen will be determined by calling identify with the ports found, and seeing which member of recognizers recognizes the result and returns a dispatch value. That value will be used to call bind-to-show-impl with the ports and other arguments, and it will do the appropriate things to work with the controller that was found.
If you are watching for a specific controller type whose mapping accepts other optional keyword arguments, you can include them as well, and they will be passed along to bind-to-show when it is detected.
All rich controller binding implementations accept a couple of standard optional keyword arguments to adjust their behavior. The controller will be identified in the user interface (for the purposes of linking it to the web cue grid) with a default name based on its type (for example “Ableton Push”). If you would like to use a different name (for example, if you are lucky enough to have more than one Push), you can pass in a custom value after the optional keyword argument :display-name
.
If you want the user interface to be refreshed at a different rate than the default for the controller type, pass your desired number of milliseconds after :refresh-interval
.
Controllers which perform their own startup animation, or which need to be given extra time to become ready after their ports appear in the MIDI environment can look for the optional keyword argument :new-connection
to indicate the device has just been connected, and react appropriately.
beat-refresh-interval
How often, in milliseconds, are the controllers requesting beat feedback refreshed.
bind-to-show
(bind-to-show show device-filter & {:keys [auto-binding], :as args})
Establish a rich user-interface binding on a supported grid controller for show
.
To locate the controller that you want to bind to, you need to supply a device-filter
which uniquely matches the ports to be used to communicate with it. The values returned by afterglow.midi/open-inputs-if-needed! and afterglow.midi/open-outputs-if-needed! will be searched, and the first port that matches with filter-devices will be used. There must be both an input and output matching the filter for the binding to succeed.
The controller binding implementation chosen will be determined by calling identify with the ports found, and seeing which member of recognizers recognizes the result and returns a non-null value. The corresponding dispatch key will be used with the result value to call bind-to-show-impl with the ports and other arguments, and it will do the appropriate things to work with the controller that was found.
All rich controller binding implementations accept a couple of standard optional keyword arguments to adjust their behavior. The controller will be identified in the user interface (for the purposes of linking it to the web cue grid) with a default name based on its type (for example “Ableton Push”). If you would like to use a different name (for example, if you are lucky enough to have more than one Push), you can pass in a custom value after the optional keyword argument :display-name
.
If you want the user interface to be refreshed at a different rate than the default for the controller type, pass your desired number of milliseconds after :refresh-interval
.
If you are binding to a specific controller type whose mapping accepts other optional keyword arguments, you can include them as well, and they will be passed on to the binding implementation function.
If the controller was bound, the binding will be returned, and you can later call deactivate with it. If the binding failed, nil
will be returned, and there will be messages explaining why in the log file.
bind-to-show-impl
multimethod
Establish a rich user-interface binding on a supported grid controller for show
. A multimethod which selects the appropriate implementation based on passing the value returned by identify to all functions registered in recognizers. The port used to receive MIDI messages from the controller is passed as port-in
, and the port used to send messages to it is passed as port-out
.
New controller binding implementations simply need to define an appropriate implementation of this multimethod, and add their recognition function to recognizers.
All rich controller binding implementations should honor the :display-name
and :refresh-interval
optional keyword arguments described in bind-rich-controller. They may also support additional optional keyword arguments specific to the details of their implementation, which the caller can supply when they know they are binding to such a controller.
clear-beat-feedback!
(clear-beat-feedback! metronome device channel kind note)
Ceases flashing the specified non-grid MIDI controller element on beats of the specified metronome.
clear-cue!
(clear-cue! grid x y)
Removes any cue which existed at the specified coordinates in the cue grid. If one was there, updates the grid dimensions if needed. Also clears any variables that were saved for that cue.
clear-cue-feedback!
(clear-cue-feedback! grid x y device channel kind note)
Ceases sending the specified non-grid MIDI controller feedback events when the cue grid location activates or deactivates, returning the feedback values that had been in place if there were any.
clear-cue-fn!
(clear-cue-fn! grid x y f)
Ceases calling the supplied function when the cue grid location activates or deactivates.
clear-saved-cue-vars!
(clear-saved-cue-vars! grid x y)
Remove any saved starting values assigned to the cue at the specified grid location.
create-overlay-state
(create-overlay-state)
Return the state information needed to manage user-interface overlays implementing the IOverlay protocol. Controllers implementing this protocol will need to pass this object to the functions that manipulate and invoke overlays.
cue-grid
(cue-grid)
Return a two dimensional arrangement for launching and monitoring cues, suitable for both a web interface and control surfaces with a pad grid. Cues are laid out with [0, 0] being the bottom left corner. The width of the grid is the highest x coordinate of a cue, and the height is the highest y coordinate.
cue-vars-saved-at
(cue-vars-saved-at grid x y)
Return the saved starting values, if any, assigned to the cue at the specified grid location.
deactivate
multimethod
Deactivates a controller binding established by bind-to-show. If :disconnected
is passed with a true
value, it means that the controller has already been removed from the MIDI environment, so no effort will be made to clear its display or take it out of User mode.
The implementation of this multimethod is chosen by using the :type
key in the controller
map as the dispatch value, so rich controller implementations simply need to register their own implementations appropriately when their namespaces are loaded.
deactivate-all
(deactivate-all)
Deactivates all controller bindings which are currently active. This will be registered as a shutdown hook to be called when the Java environment is shutting down, to clean up gracefully.
identify
(identify port-in port-out)
Sends a MIDI Device Inquiry message to the specified device and returns the response, waiting for up to a second, and trying up to three times if no response is received in that second. If the third attempt fails, returns nil
.
IGridController
protocol
A controller which provides an interface for a section of the cue) grid, and which can be linked to the web interface so they scroll in unison.
members
add-move-listener
(add-move-listener this f)
Registers a function that will be called whenever the controller’s viewport on the overall cue grid is moved, or the controller is deactivated. The function will be called with two arguments, the controller and a keyword which will be either :move or :deactivated. In the latter case, the function will never be called again.
current-bottom
(current-bottom this)
(current-bottom this y)
Returns the cue grid row currently displayed at the bottom of the controller, or sets it.
current-left
(current-left this)
(current-left this x)
Returns the cue grid column currently displayed at the left of the controller, or sets it.
display-name
(display-name this)
Returns the name by which the controller can be identified in user interfaces.
physical-height
(physical-height this)
Returns the height of the cue grid on the controller.
physical-width
(physical-width this)
Returns the width of the cue grid on the controller.
remove-move-listener
(remove-move-listener this f)
Unregisters a move listener function so it will no longer be called when the controller’s origin is moved.
IOverlay
protocol
An activity which takes over part of the user interface while it is active.
members
adjust-interface
(adjust-interface this snapshot)
Set values for the next frame of the controller interface, however that may be done; return a falsey value if the overlay is finished and should be removed. The snapshot
is an IMetroSnapshot that specifies the instant in musical time at which the interface is being rendered, so this overlay can be drawn in sync with the rest of the interface.
captured-controls
(captured-controls this)
Returns the MIDI control-change events that will be consumed by this overlay while it is active, a set of integers.
captured-notes
(captured-notes this)
Returns the MIDI note events that will be consumed by this overlay while it is active, a set of integers.
handle-aftertouch
(handle-aftertouch this message)
Called when a MIDI aftertouch event matching the captured-notes lists has been received. Return a truthy value if the overlay has consumed the event, so it should not be processed further. If the special value :done
is returned, it further indicates the overlay is finished and should be removed.
handle-control-change
(handle-control-change this message)
Called when a MIDI control-change event matching the captured-controls lists has been received. Return a truthy value if the overlay has consumed the event, so it should not be processed further. If the special value :done
is returned, it further indicates the overlay is finished and should be removed.
handle-note-off
(handle-note-off this message)
Called when a MIDI note-off event matching the captured-notes lists has been received. Return a truthy value if the overlay has consumed the event, so it should not be processed further. If the special value :done
is returned, it further indicates the overlay is finished and should be removed.
handle-note-on
(handle-note-on this message)
Called when a MIDI note-on event matching the captured-notes lists has been received. Return a truthy value if the overlay has consumed the event, so it should not be processed further. If the special value :done
is returned, it further indicates the overlay is finished and should be removed.
handle-pitch-bend
(handle-pitch-bend this message)
Called when a MIDI pitch-bend event has been received. Return a truthy value if the overlay has consumed the event, so it should not be processed further. If the special value :done
is returned, it further indicates the overlay is finished and should be removed.
overlay-handled?
(overlay-handled? state message)
See if there is an interface overlay active which wants to consume this message; if so, send it, and see if the overlay consumes it. Returns truthy if an overlay consumed the message, and it should not be given to anyone else. state
must be a value created by create-overlay-state and tracked by the controller.
More recent (and higher priority) overlays get the first chance to decide if they want to consume the message, so the overlay list is traversed in reverse order.
recognizers
A map whose keywords are dispatch values registered with bind-to-show-impl and whose values are functions which are called with three arguments: The identify response for a controller and the MIDI input and output ports it registered. The recognizer functions examine the device’s identify response and ports, if the device is recognized as a controller which is supported by the particular binding implementation associated with the dispatch keyword, return the binding information needed by their controller implementations to complete a binding to that device. In other words, non-nil
responses mean the corresponding dispatch value, function result, and input and output ports should be used with bind-to-show-impl to establish a binding with that controller.
New controller binding implementations simply need to add an appropriate implementation of that multimethod, and register their recognition function in this map.
remove-active-binding
(remove-active-binding controller)
Removes a controller from the set of active bindings, so it will no longer be deactivated when deactivate-all is called or the JVM is shutting down.
report-cue-ending
(report-cue-ending grid x y id)
Calls any registered functions that want updates about the cue state to inform them it has begun to gracefully end, its effect keyword, and the id
of the effect that is ending.
run-overlays
(run-overlays state snapshot)
Add any contributions from interface overlays, removing them if they report being finished. Most recent and higher priority overlays run last, having the opportunity to override older ones. state
must be a value created by create-overlay-state and tracked by the controller. The snapshot
is an IMetroSnapshot that captures the instant in time at which the interface is being rendered, and is passed in to the overlay so it can be rendered in sync with all other interface elements.
save-cue-vars!
(save-cue-vars! grid x y vars)
Save a set of variable starting values to be applied when launching a cue. If there is no cue at the specified grid location, nothing will be saved.
set-cue!
(set-cue! grid x y cue)
Puts the supplied cue at the specified coordinates in the cue grid. Replaces any cue which formerly existed at that location, and clears any variables that might have been saved for it. If cue
is nil, delegates to clear-cue!
starting-vars-for-velocity
(starting-vars-for-velocity cue velocity)
Given a cue and the velocity of the MIDI message which is causing it to start, gather all cue variables which have been configured to respond to MIDI velocity, and assign their initial values based on the velocity of the MIDI message. Returns a map suitable for use with the :var-overrides
argument to show/add-effect-from-cue-grid!.
value-for-velocity
(value-for-velocity v velocity)
Given a cue variable which has been configured to respond to MIDI velocity, and the velocity of a MIDI message affecting it (presumably either Note On or Aftertouch / Poly Pressure), calculate the value which should be assigned to that variable.