[orx-midi] provide dummy MIDI device, improve logging (#312)

This commit is contained in:
Abe Pazos
2023-05-26 09:08:38 +02:00
committed by GitHub
parent d4ddf8494d
commit e5e82425f2
2 changed files with 36 additions and 11 deletions

View File

@@ -35,7 +35,7 @@ class MidiConsole : Extension {
fun register(transceiver: MidiTransceiver) { fun register(transceiver: MidiTransceiver) {
transceiver.controlChanged.listen { transceiver.controlChanged.listen {
synchronized(messages) { synchronized(messages) {
messages.add("CC ${it.control}: ${it.value}") messages.add("Ch=${it.channel} CC=${it.control}: ${it.value}")
if (messages.size > historySize) { if (messages.size > historySize) {
messages.removeAt(0) messages.removeAt(0)
} }

View File

@@ -8,6 +8,7 @@ import javax.sound.midi.*
private val logger = KotlinLogging.logger { } private val logger = KotlinLogging.logger { }
data class MidiDeviceName(val name: String, val vendor: String) data class MidiDeviceName(val name: String, val vendor: String)
class MidiDeviceCapabilities { class MidiDeviceCapabilities {
var receive: Boolean = false var receive: Boolean = false
var transmit: Boolean = false var transmit: Boolean = false
@@ -56,7 +57,7 @@ data class MidiDeviceDescription(
fun open(program: Program): MidiTransceiver { fun open(program: Program): MidiTransceiver {
require(receive && transmit) { require(receive && transmit) {
"device should be a receiver and transmitter" "MIDI device should be a receiver and transmitter"
} }
return MidiTransceiver.fromDeviceVendor(program, name, vendor) return MidiTransceiver.fromDeviceVendor(program, name, vendor)
@@ -76,23 +77,23 @@ class MidiTransceiver(program: Program, val receiverDevice: MidiDevice?, val tra
val device = MidiSystem.getMidiDevice(info) val device = MidiSystem.getMidiDevice(info)
if (device !is Sequencer && device !is Synthesizer) { if (device !is Sequencer && device !is Synthesizer) {
if ((vendor == null || info.vendor == vendor) && info.name == name) { if ((vendor == null || info.vendor == vendor) && info.name == name) {
logger.info { "found matching device $name / $vendor" } logger.info { "found matching MIDI device $name / $vendor" }
if (device.maxTransmitters != 0 && device.maxReceivers == 0) { if (device.maxTransmitters != 0 && device.maxReceivers == 0) {
transmitterDevice = device transmitterDevice = device
logger.debug { logger.debug {
"found transmitter" "found MIDI transmitter"
} }
} }
if (device.maxReceivers != 0 && device.maxTransmitters == 0) { if (device.maxReceivers != 0 && device.maxTransmitters == 0) {
receiverDevice = device receiverDevice = device
logger.debug { logger.debug {
"found receiver" "found MIDI receiver"
} }
} }
} }
} }
} catch (e: MidiUnavailableException) { } catch (e: MidiUnavailableException) {
throw IllegalStateException("no midi available") error("no MIDI available")
} }
} }
@@ -101,7 +102,7 @@ class MidiTransceiver(program: Program, val receiverDevice: MidiDevice?, val tra
transmitterDevice.open() transmitterDevice.open()
return MidiTransceiver(program, receiverDevice, transmitterDevice) return MidiTransceiver(program, receiverDevice, transmitterDevice)
} else { } else {
throw IllegalArgumentException("midi device not found ${name}:${vendor} $receiverDevice $transmitterDevice") error("MIDI device not found ${name}:${vendor} $receiverDevice $transmitterDevice")
} }
} }
} }
@@ -279,9 +280,21 @@ fun listMidiDevices() = MidiDeviceDescription.list()
* Open a MIDI device by name * Open a MIDI device by name
* @param name the name of the MIDI device to open. Either the * @param name the name of the MIDI device to open. Either the
* exact name or the first characters of the name. * exact name or the first characters of the name.
* Throws an exception if the device name is not found.
* @since 0.4.3 * @since 0.4.3
*/ */
fun Program.openMidiDevice(name: String): MidiTransceiver { fun Program.openMidiDevice(name: String) =
openMidiDeviceOrNull(name) ?: error("MIDI device not found for query '$name'")
/**
* Open a MIDI device by name
*
* @param name the name of the MIDI device to open. Either the
* exact name or the first characters of the name.
* Returns null if the device name is not found.
* @since 0.4.3
*/
fun Program.openMidiDeviceOrNull(name: String): MidiTransceiver? {
val devices = listMidiDevices() val devices = listMidiDevices()
val matchingDevice = devices.firstOrNull { val matchingDevice = devices.firstOrNull {
@@ -291,7 +304,19 @@ fun Program.openMidiDevice(name: String): MidiTransceiver {
// Existing device name starts with `name` // Existing device name starts with `name`
it.name.startsWith(name) it.name.startsWith(name)
} }
val actualName = matchingDevice?.name ?: name
return MidiTransceiver.fromDeviceVendor(this, actualName) return if(matchingDevice != null)
} MidiTransceiver.fromDeviceVendor(this, matchingDevice.name)
else
null
}
/**
* Open a dummy MIDI device
*
* Enables running programs that depend on a specific MIDI device
* when that device is not available.
* Usage: `val dev = openMidiDeviceOrNull("Twister") ?: dummyMidiDevice()`
* @since 0.4.3
*/
fun Program.dummyMidiDevice() = MidiTransceiver(this, null, null)