[orx-midi] provide dummy MIDI device, improve logging (#312)
This commit is contained in:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user