ktmidi: Kotlin Multiplatform library for MIDI 1.0 and MIDI 2.0

ktmidi is a Kotlin Multiplatform library for MIDI Access API and MIDI data processing that covers MIDI 1.0 and MIDI 2.0.

Features
It provides various MIDI features, including implementations for MIDI 1.0, Standard MIDI File Format, MIDI 2.0 UMP, MIDI-CI and related specifications.
In ktmidi module:
In ktmidi-ci module (the overall API is unstable and subject to change):
MidiCIDevice class implements MIDI-CI agent models that conforms to MIDI-CI, Common Rules for MIDI-CI Profile Inquiry, and Common Rules for MIDI-CI Property Exchange specifications.
Message implements the sturecures for each MIDI-CI message type.
- primitive MIDI-CI SysEx byte stream processor in
CIFactory and CIRetrieval classes.
See MIDI-CI design doc for more details.
There are handful of sample project modules:
player-sample is an example console MIDI player for Kotlin/JVM desktop.
player-sample-native is almost the same, but for Kotlin/Native desktop.
input-sample is an example console MIDI input receiver that dumps the MIDI messages it received, for Kotlin/JVM desktop.
ktmidi-ci-tool is a comprehensive MIDI-CI functionality demo that connects to another MIDI-CI device (through a pair of MIDI connections so far).
Using ktmidi
Here is an example code excerpt to set up platform MIDI device access, load an SMF from some file, and play it:
val access = if(File("/dev/snd/seq").exists()) AlsaMidiAccess() else JvmMidiAccess()
val bytes = Files.readAllBytes(Path.of(fileName)).toList()
val music = MidiMusic()
music.read(bytes)
val player = MidiPlayer(music, access)
player.play()
To use ktmidi, add the following lines in the dependencies section in build.gradle(.kts):
dependencies {
implementation "dev.atsushieno:ktmidi:+"
}
The actual artifact might be platform dependent like dev.atsushieno:ktmidi-android:+ or dev.atsushieno:ktmidi-js:+, depending on the project targets.
If you want to bring better user experience on desktop (which @atsushieno recommends because javax.sound.midi on Linux is quite featureless), add ktmidi-jvm-desktop too,
dependencies {
implementation "dev.atsushieno:ktmidi-jvm-desktop:+"
}
... and use LibreMidiAccess for best cross-platform compatibility as well as best MIDI 2.0 support state.
NOTE: if you are building a desktop MIDI library using RtMidiAccess in ktmidi-jvm-desktop, your application needs to add javacpp-platform Gradle plugin:
plugins {
id("org.bytedeco.gradle-javacpp-platform") version "1.5.10"
}
and the following lines for dependencies:
dependencies {
(...)
api(libs.rtmidi.javacpp.platform)
}
The JavaCPP Platform Gradle plugin replaces the reference to *.javacpp.platform library with the actual platform-specific ones. (You should NOT do this in your library build, as it will result in that your library is useful only on the same platform as your building environment(!))
Also note that JavaCPP Platform Gradle plugin has problem that it fails to retrieve its native dependency from Maven package. You are supposed to publish rtmidi-javacpp or libremidi-javacpp (if you resort to it) to mavenLocal. (It is really annoying so we deprecated them.)
ktmidi is released at sonatype and hence available at Maven Central.
Platform Access API
For platform MIDI access API, we cover the following APIs:
For dependency resolution reason, ALSA implementation, libremidi implementation, and rtmidi implementation are split from ktmidi-jvm and formed as ktmidi-jvm-desktop.
ktmidi builds for Kotlin/JVM, Kotlin/JS and Kotlin/Native (though I only develop with Kotlin/JVM and Kotlin/JS so far).
The entire API is still subject to change, and it had been actually radically changing when development was most active.
MIDI 2.0 support
ktmidi supports MIDI 2.0 UMPs, and MIDI-CI if you count it as part of MIDI 2.0.
UMPs It can be sent and received to and from device where the underlying API supports them. MidiAccess supports either MIDI 1.0 or 2.0, sometimes both. MidiPort and MidiPortDetails have midiTransportProtocol property to identify which is supported.
Potential field of usages
ktmidi assumes there are various other use-cases without those message exchanges e.g. use of UMPs in MIDI 2.0-only messaging in apps or audio plugins (for example, Audio Plugins For Android along with resident-midi-keyboard).
Since you can derive from MidiAccess abstract API, you can create your own MIDI access implementation and don't have to wait for platform native API to support MIDI 2.0.
It would be useful for general MIDI 2.0 software tools such as MIDI 2.0 UMP player. kmdsp aims to achieve it (once MIDI 2.0 devices are available).
Implemented features
Here is a list of MIDI 2.0 extensibility in this API:
atsushieno/kmmk, a virtual MIDI keyboard app, supports "MIDI 2.0 mode" which sends MIDI messages in MIDI 2.0 UMPs. There is also an ongoing experimental project to process MIDI 2.0 UMPs in audio plugins on Android.
atsushieno/kmdsp, a visual MIDI player, has MIDI 2.0 mode as well (unverified and not known to work, we need MIDI 2.0 devices).
atsushieno/compose-audio-controls comes with a keyboard control for Compose Multiplatform, with option ktmidi integration.
SMF alternative format
MIDI 2.0 June 2023 updates comes with a brand-new MIDI Clip File specification, which calls itself "SMF2". Though it is not a multi-track music file format like SMF. Therefore, we still have our own format. See docs/MIDI2_FORMATS.md for details.
It is implemented as Midi2Music (read() and write()), and mugene-ng makes use of it to generate music files that are based on this format.
Historical background
It started as the Kotlin port of C# managed-midi library. Also it started with partial copy of fluidsynth-midi-service-j project.
However everything in this project went far beyond them and now we are making it usable for MIDI 2.0.
Some of the MIDI 2.0 related bits are ported from cmidi2 library.
Historically ktmidi-jvm-desktop used to reside in its own repository to avoid complicated dependency resolution, so there would be some outdated information that tells it was isolated from this project/repository.
Resources
We use GitHub issues for bug reports etc., and GitHub Discussions boards open to everyone.
For hacking and/or contributing to ktmidi, please have a look at docs/HACKING.md.
There is Application/library showcase discussions thread.
API documentation is published at: https://atsushieno.github.io/ktmidi/
(The documentation can be built using ./gradlew dokkaHtml and it will be generated locally at build/dokka/html.)
There are couple of API/implementation design docs:
You can also find some real-world usage examples of these API components:
License
ktmidi is distributed under the MIT license.
jazz-soft/JZZ is included in ktmidi-js package and is distributed under the MIT license.
rtmidi is included in ktmidi-native-ext package and is distributed under the MIT license. (It is also indirectly referenced via rtmidi-jna, which may be a different version.)
midi-ci-tool uses Wavesonics/compose-multiplatform-file-picker which is distributed under the MIT license.