Ktmidi
Kotlin multiplatform library for MIDI access abstraction and data processing for MIDI 1.0, MIDI 2.0, SMF, SMF2 (MIDI Clip File), and MIDI-CI.
Install / Use
/learn @atsushieno/KtmidiREADME
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:
- MIDI 1.0 bytestream messages and 2.0 UMPs everywhere.
MidiAccess: MIDI access abstraction API like Web MIDI API.- There are actual implementations for some platform specific MIDI API within this library, and you can implement your own backend if you need.
- It also supports MIDI 2.0 UMP ports, if the underlying API supports them.
- Unlike
javax.sound.midiAPI, this API also covers creating virtual ports wherever possible.ktmidi-jvm-desktopmodule contains the following extra backends:- ALSA (
AlsaMidiAccess) - libremidi (
LibreMidiAccess) via atsushieno/libremidi-panama for Linux, MacOS, and Windows - (legacy) RtMidi (
RtMidiAccess) via atsushieno/rtmidi-javacpp for Linux and MacOS- Windows needs JavaCPP build improvements and left unsupported (it does not matter, WinMM does not support virtual ports either way)
- ALSA (
ktmidi-native-extmodule contains RtMidi native backend (RtMidiNativeAccess) for Kotlin-Native.input-sampleand player-sample` Multiplatform apps support it.
- For Kotlin/Native on Apple OSes (macOS, iOS, etc.) there are
UmpCoreMidiAccess(supports access to MIDI 2.0 and 1.0 devices, only on newer OSes) andTraditionalCoreMidiAccess(supports access to MIDI 1.0 devices). - For Kotlin/JS,
JzzMidiAccesswhich wraps Jazz-Soft JZZ is included inktmidimodule. It should cover both node.js and web browsers. - For Kotlin/Wasm on browsers,
WebMidiAccessinktmidimodule makes use of Web MIDI API directly. (Node/Deno via wasmWasi is not covered yet.)
MidiMusicandMidi2Music: represents Standard MIDI File format structure, with reader and writer. (MIDI 2.0 support only partially based on standard;Midi2Trackfollows MIDI Clip File specification but there is no multi-track comparable specification to SMF for MIDI 2.0 yet.)- No strongly-typed message types (something like NoteOnMessage, NoteOffMessage, and so on). There is no point of defining strongly-typed messages for each mere MIDI status byte - you wouldn't need message type abstraction.
- No worries, there are constants of Int or Byte in
MidiChannelStatus,MidiCC,MidiRpn,MidiMetaTypeetc. so that you don't have to remember the actual constant numbers.
- No worries, there are constants of Int or Byte in
MidiMusic.read()reads andMidiMusic.write()writes to SMF (standard MIDI format) files with MIDI messages, withMidi1TrackMerger,Midi2TrackMerger,Midi1TrackSplitterandMidi2TrackSplitterthat help you implement sequential event processing for your own MIDI players, or per-track editors if needed.UmpFactoryandUmpRetrieverprovides various accessors to MIDI 2.0Umpdata class.UmpTranslatorcovers the standard conversion between MIDI 1.0 and MIDI 2.0 protocols, with a set of extensive options.Midi1MachineandMidi2Machinework as a potential MIDI device internal state machine, which is also to cover MIDI-CI Process Inquiry "MIDI Message Report" feature.
- No strongly-typed message types (something like NoteOnMessage, NoteOffMessage, and so on). There is no point of defining strongly-typed messages for each mere MIDI status byte - you wouldn't need message type abstraction.
MidiPlayerandMidi2Player: provides MIDI player functionality: play/pause/stop and fast-forwarding.- Midi messages are sent to its "message listeners". If you don't pass a Midi Access instance or a Midi Output instance, it will do nothing but event dispatching.
- It is based on customizible scheduler
MidiPlayerTimer. You can pass a stub implementation that does not wait, for testing. - Not realtime strict (as on GC-ed language / VM), but would suffice for general usage.
In ktmidi-ci module (the overall API is unstable and subject to change):
MidiCIDeviceclass 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.Messageimplements the sturecures for each MIDI-CI message type.- primitive MIDI-CI SysEx byte stream processor in
CIFactoryandCIRetrievalclasses.
See MIDI-CI design doc for more details.
There are handful of sample project modules:
player-sampleis an example console MIDI player for Kotlin/JVM desktop.player-sample-nativeis almost the same, but for Kotlin/Native desktop.input-sampleis an example console MIDI input receiver that dumps the MIDI messages it received, for Kotlin/JVM desktop.ktmidi-ci-toolis 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:
// for some complicated reason we don't have simple "default" MidiAccess API instance
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:+" // replace + with the actual version
}
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:+" // replace + with the actual version
}
... 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:
AndroidMidiAccess: Android MIDI API (in Kotlin)AlsaMidiAccess: ALSA sequencerLibreMidiAccess: libremidi (which covers Windows, Mac, and Linux). Supports both MIDI 1.0 and 2.0 where available.RtMidiAccess: rtmidi (which covers Windows, Mac, Linux, and iOS, but iOS is in general excluded in JVM solution. Note that rtmidi-javacpp contains prebuilt binaries only for those x86_64 desktop targets. For other platforms, you are supposed to set up rtmidi 5.0.x locally..)RtMidiNativeAccess: rtmidi access for Kotln/Native implementation. Note tha there is a static linking issue to be resolved.UmpCoreMidiAccess: Apple CoreMIDI API on Kotlin/Native. MIDI 2.0 or 1.0, but only on newer OSes.TraditionalCoreMidiAccess: Apple CoreMIDI API on Kotlin/Native. MIDI 1.0 only.JvmMidiAccess: javax.sound.midi API (has limited feature set by Java API nature).WebMidiAccess: Web MIDI API for Kotlin/Wasm target (browser only).JzzMidiAccess: Web MIDI API for Kotlin/JS target (browser and nodejs, experimental, untested).
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 f
Related Skills
node-connect
349.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.0kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.0kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
