Skip to content

Commit

Permalink
[orx-midi] provide dummy MIDI device, improve logging (#312)
Browse files Browse the repository at this point in the history
  • Loading branch information
hamoid authored May 26, 2023
1 parent d4ddf84 commit e5e8242
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 11 deletions.
2 changes: 1 addition & 1 deletion orx-jvm/orx-midi/src/main/kotlin/MidiConsole.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class MidiConsole : Extension {
fun register(transceiver: MidiTransceiver) {
transceiver.controlChanged.listen {
synchronized(messages) {
messages.add("CC ${it.control}: ${it.value}")
messages.add("Ch=${it.channel} CC=${it.control}: ${it.value}")
if (messages.size > historySize) {
messages.removeAt(0)
}
Expand Down
45 changes: 35 additions & 10 deletions orx-jvm/orx-midi/src/main/kotlin/MidiTransceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import javax.sound.midi.*
private val logger = KotlinLogging.logger { }

data class MidiDeviceName(val name: String, val vendor: String)

class MidiDeviceCapabilities {
var receive: Boolean = false
var transmit: Boolean = false
Expand Down Expand Up @@ -56,7 +57,7 @@ data class MidiDeviceDescription(

fun open(program: Program): MidiTransceiver {
require(receive && transmit) {
"device should be a receiver and transmitter"
"MIDI device should be a receiver and transmitter"
}

return MidiTransceiver.fromDeviceVendor(program, name, vendor)
Expand All @@ -76,23 +77,23 @@ class MidiTransceiver(program: Program, val receiverDevice: MidiDevice?, val tra
val device = MidiSystem.getMidiDevice(info)
if (device !is Sequencer && device !is Synthesizer) {
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) {
transmitterDevice = device
logger.debug {
"found transmitter"
"found MIDI transmitter"
}
}
if (device.maxReceivers != 0 && device.maxTransmitters == 0) {
receiverDevice = device
logger.debug {
"found receiver"
"found MIDI receiver"
}
}
}
}
} catch (e: MidiUnavailableException) {
throw IllegalStateException("no midi available")
error("no MIDI available")
}
}

Expand All @@ -101,7 +102,7 @@ class MidiTransceiver(program: Program, val receiverDevice: MidiDevice?, val tra
transmitterDevice.open()
return MidiTransceiver(program, receiverDevice, transmitterDevice)
} else {
throw IllegalArgumentException("midi device not found ${name}:${vendor} $receiverDevice $transmitterDevice")
error("MIDI device not found ${name}:${vendor} $receiverDevice $transmitterDevice")
}
}
}
Expand Down Expand Up @@ -279,9 +280,21 @@ fun listMidiDevices() = MidiDeviceDescription.list()
* 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.
* Throws an exception if the device name is not found.
* @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 matchingDevice = devices.firstOrNull {
Expand All @@ -291,7 +304,19 @@ fun Program.openMidiDevice(name: String): MidiTransceiver {
// Existing device name starts with `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)

0 comments on commit e5e8242

Please sign in to comment.