afterglow.midi
Handles MIDI communication, including syncing a show metronome to MIDI clock pulses.
abs-tolerance
If we are going to adjust the BPM, the adjustment we are going to make needs to represent at least this many milliseconds per MIDI clock tick (to reduce jitter).
add-aftertouch-mapping
(add-aftertouch-mapping device-filter channel note f)
Register a handler function f
to be called whenever a MIDI aftertouch (polyphonic key pressure) message is received from the specified device, on the specified channel
and note
number. Any subsequent MIDI message which matches will be passed to f
as its single argument.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
add-control-mapping
(add-control-mapping device-filter channel control-number f)
Register a handler function f
to be called whenever a MIDI controller change message is received from the specified device, on the specified channel
and controller
number. Any subsequent MIDI message which matches will be passed to f
as its single argument.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
add-device-mapping
(add-device-mapping device-filter f)
Register a handler function f
to be called whenever any MIDI message is received from the specified device. Any subsequent MIDI message which matches will be passed to f
as its single argument.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
add-disconnected-device-handler!
(add-disconnected-device-handler! device f)
Add a function to be called whenever the specified device disappears from the MIDI environment. The device
argument is a :midi-device
map from overtone.midi
representing device whose removal is of interest. The function must return quickly so as not to stall the delay of other MIDI events; lengthy operations must be performed on another thread.
add-global-handler!
(add-global-handler! f)
Add a function to be called whenever any MIDI message is received. The function will be called with the message, and must return quickly, so as to not block delivery to other recipients.
add-new-device-handler!
(add-new-device-handler! f)
Add a function to be called whenever a new device appears in the MIDI environment. It will be passed a single argument, the :midi-device
map from overtone.midi
representing the new device. It must return quickly so as not to stall the delay of other MIDI events; lengthy operations must be performed on another thread.
add-note-mapping
(add-note-mapping device-filter channel note f)
Register a handler function f
to be called whenever a MIDI note message is received from the specified device, on the specified channel
and note
number. Any subsequent MIDI message which matches will be passed to f
as its single argument.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
add-sysex-mapping
(add-sysex-mapping device-filter f)
Register a handler function f
to be called whenever a MIDI System Exclusive message is received from the specified device. Any subsequent MIDI message which matches will be passed to f
as its single argument.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
bpm-to-interval
(bpm-to-interval bpm)
Given a BPM, calculate the interval between MIDI clock pulses in milliseconds.
cm4j-device?
(cm4j-device? device)
Checks whether a MIDI device was returned by the CoreMIDI4J MIDI extension.
create-tempo-tap-handler
(create-tempo-tap-handler metronome)
Returns a function which implements a simple tempo-tap algorithm on the supplied metronome.
current-clock-sources
(current-clock-sources)
Returns the set of MIDI input ports which are currently delivering MIDI clock messages.
current-traktor-beat-phase-sources
(current-traktor-beat-phase-sources)
Returns the set of MIDI input ports which are currently delivering beat phase information in the format provided by the Afterglow Traktor controller mapping.
describe-device-filter
(describe-device-filter device-filter)
Returns a description of a filter used to narrow down MIDI devices, if one was supplied, or the empty string if none was.
dev-tolerance
If we are going to adjust the BPM, the adjustment must be at least this many times the standard deviation in observed clock pulse timings, so we can avoid jitter due to unstable timing.
filter-devices
(filter-devices device-filter devices)
Return only those devices matching the supplied device-filter
.
The elements of devices
must all be :midi-device
maps as returned by overtone.midi
.
If device-filter
is nil
or an empty string, devices
is returned unfiltered. Otherwise it can be one of the following things:
-
A
java.util.regex.Pattern
, which will be matched against each device name and description. If either match succeeds, the device will be included in the results. -
A
String
, which will be turned into aPattern
which matches in a case-insensitive way, as above. So if the device name or filter contains the string, ignoring case, the device will be included. -
A
javax.sound.midi.MidiDevice
instance, which will match only the device that it implements. -
A
javax.sound.midi.MidiDevice.Info
instance, which will match only the device it describes. -
A
:midi-device
map, which will match only itself. -
A
vector
of device filters, which will match any device that matches any filter. -
A function, which will be called with each device, and the device will be included if the function returns a
true
value.
Anything else will be converted to a string and matched as above.
find-midi-in
(find-midi-in device-filter)
(find-midi-in device-filter required)
Find the first MIDI input port matching the specified device-filter
using filter-devices, or throw an exception if no matches can be found. The exception can be suppressed by passing a false value for the optional second argument required
.
find-midi-out
(find-midi-out device-filter)
(find-midi-out device-filter required)
Find the first MIDI output port matching the specified device-filter
using filter-devices, or throw an exception if no matches can be found. The exception can be suppressed by passing a false value for the optional second argument required
.
IClockSync
protocol
A simple protocol for our clock sync object, allowing it to be started and stopped, and the status checked.
members
sync-start
(sync-start this)
Start synchronizing your metronome.
sync-status
(sync-status this)
Report on how well synchronization is working. Returns a map with keys :type
(a keyword that uniquely identifies the kind of sync in effect, currently chosen from :manual
, :midi
, and :dj-link
), :current
(true if sync appears to be working at the present time), :level
(a keyword that indicates how strong of a sync is being performed; :bpm
means basic BPM following, :beat
adds tracking of beat locations, :bar
adds tracking of bar starts (down beats), and :phrase
would add tracking of phrase starts, if any sync mechanism ever offers that), and :status
, which is a human-oriented summmary of the status.
sync-stop
(sync-stop this)
Stop synchronizing your metronome.
identify-mapping
(identify-mapping)
(identify-mapping timeout)
Report on the next MIDI control or note message received, to aid in setting up a mapping to a button, fader, or knob. Call this, then twiddle the knob, press the button, or move the fader, and see what Afterglow received. Pass a timeout in ms to control how long it will wait for a message (the default is ten seconds). This is an upper limit; if a message is received before the timeout, it will be reported immediately.
interval-to-bpm
(interval-to-bpm interval)
Given an interval between MIDI clock pulses in milliseconds, calculate the implied beats per minute value, to the nearest hundredth of a beat.
midi-port-filter
Contains a filter which selects midi inputs and outputs we actually want to use. The first time the value is dereferenced, a filter appropriate to the current environment will be created, and that filter will be returned whenever the value is dereferenced again.
-
If this is a Mac, and the CoreMIDI4J MIDI extension is present and working, the filter will accept only its devices.
-
Otherwise, if the Humatic MMJ extension is operating (also on a Mac), the filter which will accept only MMJ’s versions of ports which it offers in parallel with the standard implementation, but will accept the standard SPI’s implementation of ports which MMJ does not offer.
-
Otherwise, the filter accepts all ports.
mmj-device?
(mmj-device? device)
Checks whether a MIDI device was returned by the Humatic mmj MIDI extension.
open-inputs-if-needed!
(open-inputs-if-needed!)
Make sure the MIDI input ports are open and ready to distribute events. Returns the :midi-device
maps returned by overtone.midi
representing the opened inputs.
open-outputs-if-needed!
(open-outputs-if-needed!)
Make sure the MIDI output ports are open and ready to receive events. Returns the :midi-device
maps returned by overtone.midi
representing the opened outputs.
remove-aftertouch-mapping
(remove-aftertouch-mapping device-filter channel note f)
Unregister a handler previously registered with add-aftertouch-mapping.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
remove-control-mapping
(remove-control-mapping device-filter channel control-number f)
Unregister a handler previously registered with add-control-mapping.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
remove-device-mapping
(remove-device-mapping device-filter f)
Unregister a handler previously registered with add-device-mapping.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
remove-disconnected-device-handler!
(remove-disconnected-device-handler! device f)
No longer call the specified function if specified device disappears from the MIDI environment. The device
argument is a :midi-device
map from overtone.midi
representing device whose removal is no longer of interest.
remove-global-handler!
(remove-global-handler! f)
Remove a function that was being called whenever any MIDI message is received.
remove-new-device-handler!
(remove-new-device-handler! f)
Stop calling the specified function to be called whenever a new device appears in the MIDI environment.
remove-note-mapping
(remove-note-mapping device-filter channel note f)
Unregister a handler previously registered with add-note-mapping.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
remove-sysex-mapping
(remove-sysex-mapping device-filter f)
Unregister a handler previously registered with add-sysex-mapping.
The first MIDI input source whose device matches the device-filter
(using filter-devices) will be chosen.
same-device?
(same-device? a b)
Checks whether two :midi-device
maps seem to refer to the same device, in a slightly more efficient way than comparing the entire map.
scan-interval
How often should we scan for changes in the MIDI environment (devices that have been disconnected, or new devices which have connected). This is used only when CoreMIDI4J is not installed, sine CoreMIDI4J gives us proactive notification of changes to the MIDI environment. The value is in milliseconds, so the default means to check every two seconds. Changes to this value will take effect after the next scan completes.
scan-midi-environment
(scan-midi-environment)
Called either periodically to check for changes, or, if CoreMidi4J is installed, proactively in response to a reported change in the MIDI environment. Updates our notion of what MIDI devices are available, and notifies registered listeners of any changes.
Also sets up the thread used to process incoming MIDI events if that is not already running, and arranges for this function to be called as needed to keep up with future changes in the MIDI environment.
std-dev
(std-dev samples)
(std-dev samples n mean)
Calculate the standard deviation of a set of samples.
sync-to-midi-clock
(sync-to-midi-clock)
(sync-to-midi-clock device-filter)
Returns a sync function that will cause the beats-per-minute setting of the supplied metronome to track the MIDI clock messages received from the named MIDI source. This is intended for use with afterglow.show/sync-to-external-clock.
The device-filter
argument is only needed if there is more than one connected device sending MIDI clock messages when this function is invoked; it will be used to filter the eligible devices using filter-devices. An exception will be thrown if there is not exactly one matching eligible MIDI clock source.
watch-for
(watch-for device-filter found-fn & {:keys [lost-fn sleep-time], :or {sleep-time 1000}})
Watches for a device that matches device-filter
(using filter-devices). If it is present when this function is called, or whenever a matching device is connected in the future (as long as none already was), found-fn
will be called, with no arguments. This is useful for setting up MIDI mappings to the device whenever it is present. If the device is disconnected and later reconnected, found-fn
will be called again, so those bindings can be counted on to be present whenver the device is available.
If there is any cleanup that you need to perform when the device is disconnected, you can pass the optional keyword argument :lost-fn
along with a function to be called (also with no arguments) whenever a device reported by found-fn
has disappeared. You do not need to use :lost-fn
to clean up MIDI bindings created by found-fn
, because Afterglow automatically cleans up any MIDI bindings for devices which have been disconnected. But if you have your own data structures or state that you want to update, you can use :lost-fn
to do that.
In order to give the newly-attached device time to stabilize before trying to send messages to it, watch-for
waits for a second after it is seen before calling found-fn
. If your device needs more (or less) time to stabilize, you can pass a number of milliseconds after the optional keyword argument :sleep-time
to configure this delay.
The return value of watch-for
is a function that you can call to cancel the watcher if you no longer need it.