diff --git a/audio-worklet/src/commonMain/kotlin/nl/astraeus/vst/midi/MidiMessageHandler.kt b/audio-worklet/src/commonMain/kotlin/nl/astraeus/vst/midi/MidiMessageHandler.kt new file mode 100644 index 0000000..1464f37 --- /dev/null +++ b/audio-worklet/src/commonMain/kotlin/nl/astraeus/vst/midi/MidiMessageHandler.kt @@ -0,0 +1,82 @@ +package nl.astraeus.vst.midi + +typealias MidiHandler = (Byte, Byte, Byte) -> Unit + +val Byte.channel: Byte + get() { + return (this.toInt() and 0x0F).toByte() + } + +val Byte.command: Byte + get() { + return ((this.toInt() and 0xF0) shr 4).toByte() + } + +val Byte.channelCommand: Boolean + get() { + return this.command >= 8 && this.command <= 13 + } + +class MidiMessageHandler( + var channel: Byte = -1 +) { + val singleByteHandlers = mutableMapOf() + val doubleByteHandlers = mutableMapOf>() + + fun addHandler( + byte1: Byte, + byte2: Byte = 0, + handler: MidiHandler + ) { + val b1 = if (byte1.channelCommand) { + (byte1.toInt() and 0xF0).toByte() + } else { + byte1 + } + if (byte2 == 0.toByte()) { + singleByteHandlers[b1] = handler + } else { + val map = doubleByteHandlers.getOrPut(b1) { + mutableMapOf() + } + map[byte2] = handler + } + } + + fun addHandler( + byte1: Int, + byte2: Int = 0, + handler: MidiHandler + ) = addHandler( + byte1.toByte(), + byte2.toByte(), + handler + ) + + fun handle( + byte1: Byte, + byte2: Byte, + byte3: Byte + ) { + if ( + channel < 0 || + !byte1.channelCommand || + (byte1.channelCommand && channel == byte1.channel) + ) { + val b1 = if (byte1.channelCommand) { + (byte1.toInt() and 0xF0).toByte() + } else { + byte1 + } + + if (doubleByteHandlers.containsKey(b1)) { + doubleByteHandlers[b1]?.get(byte2)?.invoke(byte1, byte2, byte3) + } else if (singleByteHandlers.containsKey(b1)) { + singleByteHandlers[b1]?.invoke(byte1, byte2, byte3) + } else { + println("Unhandled message: $byte1 $byte2 $byte3") + } + } + } + +}