From 0353b923e36efc6835acbbea71b94350a49ffded Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Sat, 29 Apr 2023 09:51:45 +0200 Subject: [PATCH] [orx-midi] Update README.md, demos and docstrings --- orx-jvm/orx-midi/README.md | 6 +-- .../src/demo/kotlin/DemoMidiBinding01.kt | 14 +++-- .../src/demo/kotlin/DemoMidiConsole01.kt | 19 +++++++ .../src/demo/kotlin/DemoMidiDevices.kt | 16 ------ .../orx-midi/src/main/kotlin/MidiBindings.kt | 53 ++++++++++++++++++- .../orx-midi/src/main/kotlin/MidiConsole.kt | 22 ++++++-- orx-jvm/orx-midi/src/main/kotlin/MidiEvent.kt | 8 +-- .../src/main/kotlin/MidiTransceiver.kt | 10 ++++ 8 files changed, 115 insertions(+), 33 deletions(-) create mode 100644 orx-jvm/orx-midi/src/demo/kotlin/DemoMidiConsole01.kt delete mode 100644 orx-jvm/orx-midi/src/demo/kotlin/DemoMidiDevices.kt diff --git a/orx-jvm/orx-midi/README.md b/orx-jvm/orx-midi/README.md index 51f9fd91..def1a44b 100644 --- a/orx-jvm/orx-midi/README.md +++ b/orx-jvm/orx-midi/README.md @@ -3,19 +3,19 @@ MIDI support for keyboards and controllers. Send and receive note and control change events. Bind inputs to variables. -Orx-midi is a wrapper around javax.midi. +Orx-midi is a wrapper around `javax.midi`. ## Usage ```kotlin // -- list all midi devices -MidiDeviceDescription.list().forEach { +listMidiDevices().forEach { println("${it.name}, ${it.vendor} r:${it.receive} t:${it.transmit}") } // -- open a midi controller and listen for control changes -val dev = MidiTransceiver.fromDeviceVendor(this, "BCR2000 [hw:2,0,0]", "ALSA (http://www.alsa-project.org)") +val dev = openMidiDevice("BCR2000 [hw:2,0,0]") dev.controlChanged.listen { println("${it.channel} ${it.control} ${it.value}") } diff --git a/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiBinding01.kt b/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiBinding01.kt index 34f604ca..b90e1949 100644 --- a/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiBinding01.kt +++ b/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiBinding01.kt @@ -1,35 +1,39 @@ import org.openrndr.application import org.openrndr.color.ColorRGBa -import org.openrndr.extra.midi.MidiTransceiver import org.openrndr.extra.midi.bindMidiControl +import org.openrndr.extra.midi.openMidiDevice import org.openrndr.extra.parameters.ColorParameter import org.openrndr.extra.parameters.DoubleParameter import org.openrndr.math.Vector2 +/** + * Demonstration of two-way binding using [bindMidiControl] + */ fun main() { application { program { - val midi = MidiTransceiver.fromDeviceVendor(this,"MIDI2x2 [hw:3,0,0]", "ALSA (http://www.alsa-project.org)") + val midi = openMidiDevice("MIDI2x2 [hw:3,0,0]") val settings = object { @DoubleParameter("radius", 0.0, 100.0) var radius = 0.0 @DoubleParameter("x", -100.0, 100.0) var x = 0.0 + @DoubleParameter("y", -100.0, 100.0) var y = 0.0 @ColorParameter("fill") var color = ColorRGBa.WHITE - } + bindMidiControl(settings::radius, midi, 0, 1) bindMidiControl(settings::x, midi, 0, 2) bindMidiControl(settings::y, midi, 0, 3) - bindMidiControl(settings::color, midi, 0, 4) + extend { - drawer.fill = settings.color + drawer.fill = settings.color drawer.circle(drawer.bounds.center + Vector2(settings.x, settings.y), settings.radius) } } diff --git a/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiConsole01.kt b/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiConsole01.kt new file mode 100644 index 00000000..08791d6e --- /dev/null +++ b/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiConsole01.kt @@ -0,0 +1,19 @@ +import org.openrndr.application +import org.openrndr.extra.midi.MidiConsole +import org.openrndr.extra.midi.listMidiDevices +import org.openrndr.extra.midi.openMidiDevice + +/** + * Demonstration of [MidiConsole] + */ +fun main() { + application { + program { + listMidiDevices().forEach { println(it.toString()) } + val midi = openMidiDevice("Launchpad [hw:4,0,0]") + extend(MidiConsole()) { + register(midi) + } + } + } +} \ No newline at end of file diff --git a/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiDevices.kt b/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiDevices.kt deleted file mode 100644 index fee94f0a..00000000 --- a/orx-jvm/orx-midi/src/demo/kotlin/DemoMidiDevices.kt +++ /dev/null @@ -1,16 +0,0 @@ -import org.openrndr.application -import org.openrndr.extra.midi.MidiConsole -import org.openrndr.extra.midi.MidiDeviceDescription -import org.openrndr.extra.midi.MidiTransceiver - -fun main() { - application { - program { - MidiDeviceDescription.list().forEach { println(it.toString()) } - val midi = MidiTransceiver.fromDeviceVendor(this,"Launchpad [hw:4,0,0]", "ALSA (http://www.alsa-project.org)") - extend(MidiConsole()) { - register(midi) - } - } - } -} \ No newline at end of file diff --git a/orx-jvm/orx-midi/src/main/kotlin/MidiBindings.kt b/orx-jvm/orx-midi/src/main/kotlin/MidiBindings.kt index 74009078..201936a1 100644 --- a/orx-jvm/orx-midi/src/main/kotlin/MidiBindings.kt +++ b/orx-jvm/orx-midi/src/main/kotlin/MidiBindings.kt @@ -27,6 +27,14 @@ fun bindMidiNote(on: () -> Unit, off: () -> Unit, transceiver: MidiTransceiver, } } +/** + * Bind MIDI control change to [Double] property + * @param property the [KMutableProperty0] to bind to + * @param transceiver the midi device to bind to + * @param channel the midi channel to use + * @param control the midi control to use + * @since 0.4.3 + */ @JvmName("bindMidiControlDouble") fun Program.bindMidiControl( property: KMutableProperty0, @@ -58,6 +66,14 @@ fun Program.bindMidiControl( } } +/** + * Bind MIDI control change to [Boolean] property + * @param property the [KMutableProperty0] to bind to + * @param transceiver the midi device to bind to + * @param channel the midi channel to use + * @param control the midi control to use + * @since 0.4.3 + */ @JvmName("bindMidiControlBoolean") fun Program.bindMidiControl( property: KMutableProperty0, @@ -83,7 +99,16 @@ fun Program.bindMidiControl( } } - +/** + * Bind MIDI control change to [Vector2] property + * @param property the [KMutableProperty0] to bind to + * @param transceiver the midi device to bind to + * @param channelX the midi channel to use for the [Vector2.x] component + * @param controlX the midi control to use for the [Vector2.x] component + * @param channelY the midi channel to use for the [Vector2.y] component + * @param controlY the midi control to use for the [Vector2.y] component + * @since 0.4.3 + */ @JvmName("bindMidiControlVector2") fun Program.bindMidiControl( property: KMutableProperty0, transceiver: MidiTransceiver, @@ -131,6 +156,18 @@ fun Program.bindMidiControl( } } +/** + * Bind MIDI control change to [Vector3] property + * @param property the [KMutableProperty0] to bind to + * @param transceiver the midi device to bind to + * @param channelX the midi channel to use for the [Vector3.x] component + * @param controlX the midi control to use for the [Vector3.x] component + * @param channelY the midi channel to use for the [Vector3.y] component + * @param controlY the midi control to use for the [Vector3.y] component + * @param channelZ the midi channel to use for the [Vector3.z] component + * @param controlZ the midi control to use for the [Vector3.z] component + * @since 0.4.3 + */ @JvmName("bindMidiControlVector3") fun Program.bindMidiControl( property: KMutableProperty0, transceiver: MidiTransceiver, @@ -187,6 +224,20 @@ fun Program.bindMidiControl( } } +/** + * Bind MIDI control change to [ColorRGBa] property + * @param property the [KMutableProperty0] to bind to + * @param transceiver the midi device to bind to + * @param channelR the midi channel to use for the [ColorRGBa.r] component + * @param controlR the midi control to use for the [ColorRGBa.r] component + * @param channelG the midi channel to use for the [ColorRGBa.g] component + * @param controlG the midi control to use for the [ColorRGBa.g] component + * @param channelB the midi channel to use for the [ColorRGBa.b] component + * @param controlB the midi control to use for the [ColorRGBa.b] component + * @param channelA the midi channel to use for the [ColorRGBa.alpha] component + * @param controlA the midi control to use for the [ColorRGBa.alpha] component + * @since 0.4.3 + */ @JvmName("bindMidiControlColorRGBa") fun Program.bindMidiControl( property: KMutableProperty0, transceiver: MidiTransceiver, diff --git a/orx-jvm/orx-midi/src/main/kotlin/MidiConsole.kt b/orx-jvm/orx-midi/src/main/kotlin/MidiConsole.kt index 9b919336..084a7425 100644 --- a/orx-jvm/orx-midi/src/main/kotlin/MidiConsole.kt +++ b/orx-jvm/orx-midi/src/main/kotlin/MidiConsole.kt @@ -9,15 +9,29 @@ import org.openrndr.math.Vector2 import org.openrndr.shape.Rectangle import java.io.File -class MidiConsole: Extension { +/** + * A console for monitoring MIDI events + */ +class MidiConsole : Extension { override var enabled = true + /** + * placement of the console text + */ var box = Rectangle(0.0, 0.0, 130.0, 200.0) - val messages = mutableListOf() + + private val messages = mutableListOf() + + /** + * number of entries in the visible history + */ var historySize = 2 - val demoFont = File("demo-data/fonts/IBMPlexMono-Regular.ttf").exists() + private val demoFont = File("demo-data/fonts/IBMPlexMono-Regular.ttf").exists() + /** + * register a Midi device for monitoring + */ fun register(transceiver: MidiTransceiver) { transceiver.controlChanged.listen { synchronized(messages) { @@ -46,7 +60,7 @@ class MidiConsole: Extension { } } - override fun afterDraw(drawer: Drawer, program: Program) { + override fun afterDraw(drawer: Drawer, program: Program) { drawer.defaults() synchronized(messages) { box = Rectangle(drawer.width - box.width, 0.0, box.width, drawer.height * 1.0) diff --git a/orx-jvm/orx-midi/src/main/kotlin/MidiEvent.kt b/orx-jvm/orx-midi/src/main/kotlin/MidiEvent.kt index cc16ecb1..feda1720 100644 --- a/orx-jvm/orx-midi/src/main/kotlin/MidiEvent.kt +++ b/orx-jvm/orx-midi/src/main/kotlin/MidiEvent.kt @@ -41,7 +41,7 @@ class MidiEvent(val eventType: MidiEventType) { return midiEvent } - fun controlChange(channel:Int, control: Int, value: Int): MidiEvent { + fun controlChange(channel: Int, control: Int, value: Int): MidiEvent { val midiEvent = MidiEvent(MidiEventType.CONTROL_CHANGED) midiEvent.channel = channel midiEvent.control = control @@ -49,21 +49,21 @@ class MidiEvent(val eventType: MidiEventType) { return midiEvent } - fun programChange(channel:Int, program: Int): MidiEvent { + fun programChange(channel: Int, program: Int): MidiEvent { val midiEvent = MidiEvent(MidiEventType.PROGRAM_CHANGE) midiEvent.channel = channel midiEvent.program = program return midiEvent } - fun channelPressure(channel:Int, pressure: Int): MidiEvent { + fun channelPressure(channel: Int, pressure: Int): MidiEvent { val midiEvent = MidiEvent(MidiEventType.CHANNEL_PRESSURE) midiEvent.channel = channel midiEvent.pressure = pressure return midiEvent } - fun pitchBend(channel:Int, pitchBend: Int): MidiEvent { + fun pitchBend(channel: Int, pitchBend: Int): MidiEvent { val midiEvent = MidiEvent(MidiEventType.PITCH_BEND) midiEvent.channel = channel midiEvent.pitchBend = pitchBend diff --git a/orx-jvm/orx-midi/src/main/kotlin/MidiTransceiver.kt b/orx-jvm/orx-midi/src/main/kotlin/MidiTransceiver.kt index 3b4531e1..6e01d44e 100644 --- a/orx-jvm/orx-midi/src/main/kotlin/MidiTransceiver.kt +++ b/orx-jvm/orx-midi/src/main/kotlin/MidiTransceiver.kt @@ -268,6 +268,16 @@ class MidiTransceiver(program: Program, val receiverDevice: MidiDevice?, val tra transmitterDevicer?.close() } } + +/** + * List all available MIDI devices + * @since 0.4.3 + */ fun listMidiDevices() = MidiDeviceDescription.list() +/** + * Open a MIDI device by name + * @param name the name of the MIDI device to open + * @since 0.4.3 + */ fun Program.openMidiDevice(name: String) = MidiTransceiver.fromDeviceVendor(this, name) \ No newline at end of file