diff --git a/ktmidi-ci/api/android/ktmidi-ci.api b/ktmidi-ci/api/android/ktmidi-ci.api index aef269945..736acb2e8 100644 --- a/ktmidi-ci/api/android/ktmidi-ci.api +++ b/ktmidi-ci/api/android/ktmidi-ci.api @@ -112,9 +112,22 @@ public final class dev/atsushieno/ktmidi/ci/CISubId2 { public static final field TEST_NEW_PROTOCOL_R2I B } +public final class dev/atsushieno/ktmidi/ci/ChannelInfoPropertyNames { + public static final field BANK_PC Ljava/lang/String; + public static final field CHANNEL Ljava/lang/String; + public static final field CLUSTER_CHANNEL_START Ljava/lang/String; + public static final field CLUSTER_LENGTH Ljava/lang/String; + public static final field CLUSTER_MIDI_MODE Ljava/lang/String; + public static final field CLUSTER_TYPE Ljava/lang/String; + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/ChannelInfoPropertyNames; + public static final field PROGRAM_TITLE Ljava/lang/String; + public static final field TITLE Ljava/lang/String; +} + public final class dev/atsushieno/ktmidi/ci/ClientConnection { public fun (Ldev/atsushieno/ktmidi/ci/MidiCIDevice;ILdev/atsushieno/ktmidi/ci/DeviceDetails;BLjava/lang/String;)V public synthetic fun (Ldev/atsushieno/ktmidi/ci/MidiCIDevice;ILdev/atsushieno/ktmidi/ci/DeviceDetails;BLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getChannelList ()Ldev/atsushieno/ktmidi/ci/MidiCIChannelList; public final fun getDeviceInfo ()Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo; public final fun getJsonSchema ()Ldev/atsushieno/ktmidi/ci/json/Json$JsonValue; public final fun getMaxSimultaneousPropertyRequests ()B @@ -122,6 +135,7 @@ public final class dev/atsushieno/ktmidi/ci/ClientConnection { public final fun getProfileClient ()Ldev/atsushieno/ktmidi/ci/ProfileClientFacade; public final fun getPropertyClient ()Ldev/atsushieno/ktmidi/ci/PropertyClientFacade; public final fun getTargetMUID ()I + public final fun setChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun setDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun setJsonSchema (Ldev/atsushieno/ktmidi/ci/json/Json$JsonValue;)V public final fun setMaxSimultaneousPropertyRequests (B)V @@ -156,6 +170,23 @@ public final class dev/atsushieno/ktmidi/ci/ClientSubscription { public fun toString ()Ljava/lang/String; } +public final class dev/atsushieno/ktmidi/ci/ClusterMidiMode { + public static final field DEFAULT B + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/ClusterMidiMode; + public static final field MONO_MODE B + public static final field NONE B + public static final field OMNI_OFF B + public static final field OMNI_ON B + public static final field POLY_MODE B +} + +public final class dev/atsushieno/ktmidi/ci/ClusterType { + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/ClusterType; + public static final field MPE1 Ljava/lang/String; + public static final field OTHER Ljava/lang/String; + public static final field PROFILE Ljava/lang/String; +} + public final class dev/atsushieno/ktmidi/ci/ConnectionChange : java/lang/Enum { public static final field Added Ldev/atsushieno/ktmidi/ci/ConnectionChange; public static final field Removed Ldev/atsushieno/ktmidi/ci/ConnectionChange; @@ -653,6 +684,77 @@ public final class dev/atsushieno/ktmidi/ci/Messenger { public final fun setProcessUnknownCIMessage (Lkotlin/jvm/functions/Function2;)V } +public final class dev/atsushieno/ktmidi/ci/MidiCIChannel { + public static final field Companion Ldev/atsushieno/ktmidi/ci/MidiCIChannel$Companion; + public fun (Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;)V + public synthetic fun (Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component10 ()Z + public final fun component11 ()Ljava/lang/String; + public final fun component2 ()I + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()B + public final fun component5 ()B + public final fun component6 ()B + public final fun component7 ()I + public final fun component8 ()I + public final fun component9 ()Z + public final fun copy (Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;)Ldev/atsushieno/ktmidi/ci/MidiCIChannel; + public static synthetic fun copy$default (Ldev/atsushieno/ktmidi/ci/MidiCIChannel;Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;ILjava/lang/Object;)Ldev/atsushieno/ktmidi/ci/MidiCIChannel; + public fun equals (Ljava/lang/Object;)Z + public final fun getBankLSB ()B + public final fun getBankMSB ()B + public final fun getBankPC ()[Ljava/lang/Byte; + public final fun getChannel ()I + public final fun getClusterChannelStart ()I + public final fun getClusterLength ()I + public final fun getClusterMidiMode ()B + public final fun getClusterType ()Ljava/lang/String; + public final fun getProgram ()B + public final fun getProgramTitle ()Ljava/lang/String; + public final fun getTitle ()Ljava/lang/String; + public fun hashCode ()I + public final fun isOmniOn ()Z + public final fun isPolyMode ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannel$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/MidiCIChannel$$serializer; + public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ldev/atsushieno/ktmidi/ci/MidiCIChannel; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ldev/atsushieno/ktmidi/ci/MidiCIChannel;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannel$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannelList { + public static final field Companion Ldev/atsushieno/ktmidi/ci/MidiCIChannelList$Companion; + public fun ()V + public final fun getChannels ()Ljava/util/List; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannelList$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/MidiCIChannelList$$serializer; + public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ldev/atsushieno/ktmidi/ci/MidiCIChannelList; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannelList$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public abstract interface class dev/atsushieno/ktmidi/ci/MidiCIClientPropertyRules { public abstract fun createDataRequestHeader (Ljava/lang/String;Ljava/util/Map;)Ljava/util/List; public abstract fun createStatusHeader (I)Ljava/util/List; @@ -717,6 +819,7 @@ public final class dev/atsushieno/ktmidi/ci/MidiCIDevice { public final fun sendDiscovery ()V public final fun sendProfileSpecificData (BILdev/atsushieno/ktmidi/ci/MidiCIProfileId;Ljava/util/List;)V public final fun setMidiMessageReporter (Ldev/atsushieno/ktmidi/ci/MidiMessageReporter;)V + public final fun updateChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun updateDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun updateJsonSchema (Ljava/lang/String;)V } @@ -731,6 +834,7 @@ public final class dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration { public final fun getAutoSendProfileInquiry ()Z public final fun getAutoSendPropertyExchangeCapabilitiesInquiry ()Z public final fun getCapabilityInquirySupported ()B + public final fun getChannelList ()Ldev/atsushieno/ktmidi/ci/MidiCIChannelList; public final fun getDeviceInfo ()Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo; public final fun getFunctionBlock ()B public final fun getGroup ()B @@ -755,6 +859,7 @@ public final class dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration { public final fun setAutoSendProfileInquiry (Z)V public final fun setAutoSendPropertyExchangeCapabilitiesInquiry (Z)V public final fun setCapabilityInquirySupported (B)V + public final fun setChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun setDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun setFunctionBlock (B)V public final fun setGroup (B)V @@ -1126,6 +1231,7 @@ public final class dev/atsushieno/ktmidi/ci/PropertyHostFacade { public final fun setPropertyValue (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Z)V public final fun shutdownSubscription (ILjava/lang/String;)V public final fun terminateSubscriptionsToAllSubsctibers (B)V + public final fun updateCommonRulesChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun updateCommonRulesDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun updateJsonSchema (Ljava/lang/String;)V public final fun updatePropertyMetadata (Ljava/lang/String;Ldev/atsushieno/ktmidi/ci/PropertyMetadata;)V diff --git a/ktmidi-ci/api/jvm/ktmidi-ci.api b/ktmidi-ci/api/jvm/ktmidi-ci.api index 582e2fd7a..4fca213d0 100644 --- a/ktmidi-ci/api/jvm/ktmidi-ci.api +++ b/ktmidi-ci/api/jvm/ktmidi-ci.api @@ -112,9 +112,22 @@ public final class dev/atsushieno/ktmidi/ci/CISubId2 { public static final field TEST_NEW_PROTOCOL_R2I B } +public final class dev/atsushieno/ktmidi/ci/ChannelInfoPropertyNames { + public static final field BANK_PC Ljava/lang/String; + public static final field CHANNEL Ljava/lang/String; + public static final field CLUSTER_CHANNEL_START Ljava/lang/String; + public static final field CLUSTER_LENGTH Ljava/lang/String; + public static final field CLUSTER_MIDI_MODE Ljava/lang/String; + public static final field CLUSTER_TYPE Ljava/lang/String; + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/ChannelInfoPropertyNames; + public static final field PROGRAM_TITLE Ljava/lang/String; + public static final field TITLE Ljava/lang/String; +} + public final class dev/atsushieno/ktmidi/ci/ClientConnection { public fun (Ldev/atsushieno/ktmidi/ci/MidiCIDevice;ILdev/atsushieno/ktmidi/ci/DeviceDetails;BLjava/lang/String;)V public synthetic fun (Ldev/atsushieno/ktmidi/ci/MidiCIDevice;ILdev/atsushieno/ktmidi/ci/DeviceDetails;BLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getChannelList ()Ldev/atsushieno/ktmidi/ci/MidiCIChannelList; public final fun getDeviceInfo ()Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo; public final fun getJsonSchema ()Ldev/atsushieno/ktmidi/ci/json/Json$JsonValue; public final fun getMaxSimultaneousPropertyRequests ()B @@ -122,6 +135,7 @@ public final class dev/atsushieno/ktmidi/ci/ClientConnection { public final fun getProfileClient ()Ldev/atsushieno/ktmidi/ci/ProfileClientFacade; public final fun getPropertyClient ()Ldev/atsushieno/ktmidi/ci/PropertyClientFacade; public final fun getTargetMUID ()I + public final fun setChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun setDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun setJsonSchema (Ldev/atsushieno/ktmidi/ci/json/Json$JsonValue;)V public final fun setMaxSimultaneousPropertyRequests (B)V @@ -156,6 +170,23 @@ public final class dev/atsushieno/ktmidi/ci/ClientSubscription { public fun toString ()Ljava/lang/String; } +public final class dev/atsushieno/ktmidi/ci/ClusterMidiMode { + public static final field DEFAULT B + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/ClusterMidiMode; + public static final field MONO_MODE B + public static final field NONE B + public static final field OMNI_OFF B + public static final field OMNI_ON B + public static final field POLY_MODE B +} + +public final class dev/atsushieno/ktmidi/ci/ClusterType { + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/ClusterType; + public static final field MPE1 Ljava/lang/String; + public static final field OTHER Ljava/lang/String; + public static final field PROFILE Ljava/lang/String; +} + public final class dev/atsushieno/ktmidi/ci/ConnectionChange : java/lang/Enum { public static final field Added Ldev/atsushieno/ktmidi/ci/ConnectionChange; public static final field Removed Ldev/atsushieno/ktmidi/ci/ConnectionChange; @@ -653,6 +684,77 @@ public final class dev/atsushieno/ktmidi/ci/Messenger { public final fun setProcessUnknownCIMessage (Lkotlin/jvm/functions/Function2;)V } +public final class dev/atsushieno/ktmidi/ci/MidiCIChannel { + public static final field Companion Ldev/atsushieno/ktmidi/ci/MidiCIChannel$Companion; + public fun (Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;)V + public synthetic fun (Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun component10 ()Z + public final fun component11 ()Ljava/lang/String; + public final fun component2 ()I + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()B + public final fun component5 ()B + public final fun component6 ()B + public final fun component7 ()I + public final fun component8 ()I + public final fun component9 ()Z + public final fun copy (Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;)Ldev/atsushieno/ktmidi/ci/MidiCIChannel; + public static synthetic fun copy$default (Ldev/atsushieno/ktmidi/ci/MidiCIChannel;Ljava/lang/String;ILjava/lang/String;BBBIIZZLjava/lang/String;ILjava/lang/Object;)Ldev/atsushieno/ktmidi/ci/MidiCIChannel; + public fun equals (Ljava/lang/Object;)Z + public final fun getBankLSB ()B + public final fun getBankMSB ()B + public final fun getBankPC ()[Ljava/lang/Byte; + public final fun getChannel ()I + public final fun getClusterChannelStart ()I + public final fun getClusterLength ()I + public final fun getClusterMidiMode ()B + public final fun getClusterType ()Ljava/lang/String; + public final fun getProgram ()B + public final fun getProgramTitle ()Ljava/lang/String; + public final fun getTitle ()Ljava/lang/String; + public fun hashCode ()I + public final fun isOmniOn ()Z + public final fun isPolyMode ()Z + public fun toString ()Ljava/lang/String; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannel$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/MidiCIChannel$$serializer; + public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ldev/atsushieno/ktmidi/ci/MidiCIChannel; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ldev/atsushieno/ktmidi/ci/MidiCIChannel;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannel$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannelList { + public static final field Companion Ldev/atsushieno/ktmidi/ci/MidiCIChannelList$Companion; + public fun ()V + public final fun getChannels ()Ljava/util/List; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannelList$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Ldev/atsushieno/ktmidi/ci/MidiCIChannelList$$serializer; + public fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ldev/atsushieno/ktmidi/ci/MidiCIChannelList; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public fun serialize (Lkotlinx/serialization/encoding/Encoder;Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class dev/atsushieno/ktmidi/ci/MidiCIChannelList$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public abstract interface class dev/atsushieno/ktmidi/ci/MidiCIClientPropertyRules { public abstract fun createDataRequestHeader (Ljava/lang/String;Ljava/util/Map;)Ljava/util/List; public abstract fun createStatusHeader (I)Ljava/util/List; @@ -717,6 +819,7 @@ public final class dev/atsushieno/ktmidi/ci/MidiCIDevice { public final fun sendDiscovery ()V public final fun sendProfileSpecificData (BILdev/atsushieno/ktmidi/ci/MidiCIProfileId;Ljava/util/List;)V public final fun setMidiMessageReporter (Ldev/atsushieno/ktmidi/ci/MidiMessageReporter;)V + public final fun updateChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun updateDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun updateJsonSchema (Ljava/lang/String;)V } @@ -731,6 +834,7 @@ public final class dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration { public final fun getAutoSendProfileInquiry ()Z public final fun getAutoSendPropertyExchangeCapabilitiesInquiry ()Z public final fun getCapabilityInquirySupported ()B + public final fun getChannelList ()Ldev/atsushieno/ktmidi/ci/MidiCIChannelList; public final fun getDeviceInfo ()Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo; public final fun getFunctionBlock ()B public final fun getGroup ()B @@ -755,6 +859,7 @@ public final class dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration { public final fun setAutoSendProfileInquiry (Z)V public final fun setAutoSendPropertyExchangeCapabilitiesInquiry (Z)V public final fun setCapabilityInquirySupported (B)V + public final fun setChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun setDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun setFunctionBlock (B)V public final fun setGroup (B)V @@ -1126,6 +1231,7 @@ public final class dev/atsushieno/ktmidi/ci/PropertyHostFacade { public final fun setPropertyValue (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Z)V public final fun shutdownSubscription (ILjava/lang/String;)V public final fun terminateSubscriptionsToAllSubsctibers (B)V + public final fun updateCommonRulesChannelList (Ldev/atsushieno/ktmidi/ci/MidiCIChannelList;)V public final fun updateCommonRulesDeviceInfo (Ldev/atsushieno/ktmidi/ci/MidiCIDeviceInfo;)V public final fun updateJsonSchema (Ljava/lang/String;)V public final fun updatePropertyMetadata (Ljava/lang/String;Ldev/atsushieno/ktmidi/ci/PropertyMetadata;)V diff --git a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/ClientConnection.kt b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/ClientConnection.kt index 603be19f6..091d7cf9d 100644 --- a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/ClientConnection.kt +++ b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/ClientConnection.kt @@ -29,6 +29,7 @@ class ClientConnection( "", "" ) + var channelList = MidiCIChannelList() var jsonSchema: Json.JsonValue? = null val profileClient = ProfileClientFacade(parent, this) diff --git a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIChannelList.kt b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIChannelList.kt new file mode 100644 index 000000000..f81ca99f5 --- /dev/null +++ b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIChannelList.kt @@ -0,0 +1,57 @@ +package dev.atsushieno.ktmidi.ci + +import kotlinx.serialization.Serializable + +@Serializable +class MidiCIChannelList { + val channels = mutableListOf() +} + +// 1-4 in the spec doc, 0-3 in the data model. They must be adjusted before sending and after receiving. +object ClusterMidiMode { + const val NONE: Byte = 0 + const val OMNI_OFF: Byte = 0 + const val OMNI_ON: Byte = 1 + const val MONO_MODE: Byte = 0 + const val POLY_MODE: Byte = 2 + const val DEFAULT: Byte = (OMNI_OFF + POLY_MODE).toByte() +} + +object ClusterType { + const val OTHER = "other" + const val PROFILE = "profile" + const val MPE1 = "mpe1" +} + +object ChannelInfoPropertyNames { + const val TITLE = "title" + const val CHANNEL = "channel" + const val PROGRAM_TITLE = "programTitle" + const val BANK_PC = "bankPC" + const val CLUSTER_CHANNEL_START = "clusterChannelStart" + const val CLUSTER_LENGTH = "clusterLength" + const val CLUSTER_MIDI_MODE = "clusterMidiMode" + const val CLUSTER_TYPE = "clusterType" +} + +@Serializable +data class MidiCIChannel( + val title: String, + // Note that ChannelList property specification expects 1-256, not 0.255 + val channel: Int, + val programTitle: String? = null, + val bankMSB: Byte = 0, + val bankLSB: Byte = 0, + val program: Byte = 0, + // Note that ChannelList property specification expects 1-256, not 0.255 + val clusterChannelStart: Int = 1, + val clusterLength: Int = 1, + val isOmniOn: Boolean = true, + val isPolyMode: Boolean = true, + val clusterType: String? = ClusterType.OTHER +) { + // value range is 1-4, while it is 0-3 in code. + val clusterMidiMode: Byte = ((if (isOmniOn) 1 else 0) + (if (isPolyMode) 2 else 0) + 1).toByte() + + val bankPC = arrayOf(bankMSB, bankLSB, program) +} diff --git a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDevice.kt b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDevice.kt index 02bd940ce..ab68805e1 100644 --- a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDevice.kt +++ b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDevice.kt @@ -69,4 +69,9 @@ class MidiCIDevice(val muid: Int, val config: MidiCIDeviceConfiguration, config.jsonSchemaString = stringValue propertyHost.updateJsonSchema(stringValue) } + + fun updateChannelList(channelList: MidiCIChannelList) { + config.channelList = channelList + propertyHost.updateCommonRulesChannelList(channelList) + } } diff --git a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration.kt b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration.kt index 4fee230ef..c705b94c4 100644 --- a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration.kt +++ b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/MidiCIDeviceConfiguration.kt @@ -17,6 +17,8 @@ class MidiCIDeviceConfiguration { var deviceInfo = MidiCIDeviceInfo(0x123456,0x1234,0x5678,0x00000001, "atsushieno", "KtMidi", "KtMidi-CI-Tool", "0.1") + var channelList = MidiCIChannelList() + var jsonSchemaString: String = "" var capabilityInquirySupported: Byte = MidiCISupportedCategories.THREE_P diff --git a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/PropertyHostFacade.kt b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/PropertyHostFacade.kt index 95e5e911d..f72a8372e 100644 --- a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/PropertyHostFacade.kt +++ b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/PropertyHostFacade.kt @@ -37,6 +37,12 @@ class PropertyHostFacade(private val device: MidiCIDevice) { p.deviceInfo = deviceInfo } + fun updateCommonRulesChannelList(channelList: MidiCIChannelList) { + val p = propertyService + if (p is CommonRulesPropertyService) + p.channelList = channelList + } + fun updateJsonSchema(stringValue: String) { val p = propertyService if (p is CommonRulesPropertyService) diff --git a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Client.kt b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Client.kt index 28dd0a870..b22509df7 100644 --- a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Client.kt +++ b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Client.kt @@ -62,6 +62,31 @@ class CommonRulesPropertyClient(private val device: MidiCIDevice, private val co json.getObjectValue(DeviceInfoPropertyNames.SERIAL_NUMBER)?.stringValue ?: "", ) } + // If it is about DeviceInfo, then store the list internally. + PropertyResourceNames.CHANNEL_LIST -> { + val json = convertApplicationJsonBytesToJson(data) + conn.channelList = MidiCIChannelList().apply { + json.arrayValue.map { + val bankPC = json.getObjectValue(ChannelInfoPropertyNames.BANK_PC)?.arrayValue?.toList() + val midiMode = json.getObjectValue(ChannelInfoPropertyNames.CLUSTER_MIDI_MODE)?.numberValue?.toInt() + channels.add( + MidiCIChannel( + json.getObjectValue(ChannelInfoPropertyNames.TITLE)?.stringValue ?: "", + (json.getObjectValue(ChannelInfoPropertyNames.CHANNEL)?.numberValue?.toInt() ?: 1) - 1, + json.getObjectValue(ChannelInfoPropertyNames.PROGRAM_TITLE)?.stringValue, + (if (bankPC == null) 0 else bankPC[0].numberValue).toByte(), + (if (bankPC == null) 0 else bankPC[1].numberValue).toByte(), + (if (bankPC == null) 0 else bankPC[2].numberValue).toByte(), + (json.getObjectValue(ChannelInfoPropertyNames.CLUSTER_CHANNEL_START)?.numberValue?.toInt() ?: 1) - 1, + json.getObjectValue(ChannelInfoPropertyNames.CLUSTER_LENGTH)?.numberValue?.toInt() ?: 1, + if (midiMode == null) false else ((midiMode - 1) and 1) != 0, + if (midiMode == null) false else ((midiMode - 1) and 2) != 0, + json.getObjectValue(ChannelInfoPropertyNames.CLUSTER_TYPE)?.stringValue + ) + ) + } + } + } PropertyResourceNames.JSON_SCHEMA -> conn.jsonSchema = convertApplicationJsonBytesToJson(data) diff --git a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Service.kt b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Service.kt index d331f8aa9..6f106c673 100644 --- a/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Service.kt +++ b/ktmidi-ci/src/commonMain/kotlin/dev/atsushieno/ktmidi/ci/propertycommonrules/PropertyCommonRules.Service.kt @@ -8,7 +8,7 @@ import kotlin.random.Random private val defaultPropertyList = listOf( CommonRulesPropertyMetadata(PropertyResourceNames.DEVICE_INFO).apply { originator = CommonRulesPropertyMetadata.Originator.SYSTEM }, - //PropertyResource(PropertyResourceNames.CHANNEL_LIST), + CommonRulesPropertyMetadata(PropertyResourceNames.CHANNEL_LIST).apply { originator = CommonRulesPropertyMetadata.Originator.SYSTEM }, CommonRulesPropertyMetadata(PropertyResourceNames.JSON_SCHEMA).apply { originator = CommonRulesPropertyMetadata.Originator.SYSTEM } ) @@ -56,6 +56,11 @@ class CommonRulesPropertyService(private val device: MidiCIDevice) get() = device.config.deviceInfo @JvmName("set_deviceInfo") set(value) { device.config.deviceInfo = value } + internal var channelList + @JvmName("get_channelList") + get() = device.config.channelList + @JvmName("set_channelList") + set(value) { device.config.channelList = value } internal var jsonSchemaString @JvmName("get_jsonSchemaString") get() = device.config.jsonSchemaString @@ -67,7 +72,6 @@ class CommonRulesPropertyService(private val device: MidiCIDevice) private val metadataList @JvmName("get_metadataList") get() = device.config.propertyMetadataList - private val channelList: Json.JsonValue? = null // MidiCIPropertyService implementation override val subscriptions = mutableListOf() @@ -192,6 +196,23 @@ class CommonRulesPropertyService(private val device: MidiCIDevice) ) } + private fun MidiCIChannel.toJson() = Json.JsonValue(mapOf( + Json.JsonValue(ChannelInfoPropertyNames.TITLE) to Json.JsonValue(title), + Json.JsonValue(ChannelInfoPropertyNames.CHANNEL) to Json.JsonValue(channel.toDouble()), + Json.JsonValue(ChannelInfoPropertyNames.PROGRAM_TITLE) to + if (programTitle == null) null else Json.JsonValue(programTitle), + Json.JsonValue(ChannelInfoPropertyNames.BANK_PC) to + if (bankPC.all { it.toInt() == 0 }) null else Json.JsonValue(bankPC.map { Json.JsonValue(it.toDouble()) }), + Json.JsonValue(ChannelInfoPropertyNames.CLUSTER_CHANNEL_START) to + if (clusterChannelStart <= 1) null else Json.JsonValue(clusterChannelStart.toDouble()), + Json.JsonValue(ChannelInfoPropertyNames.CLUSTER_LENGTH) to + if (clusterChannelStart <= 1) null else Json.JsonValue(clusterLength.toDouble()), + Json.JsonValue(ChannelInfoPropertyNames.CLUSTER_MIDI_MODE) to + if (clusterMidiMode.toInt() == 3) null else Json.JsonValue(clusterMidiMode.toDouble()), + Json.JsonValue(ChannelInfoPropertyNames.CLUSTER_TYPE) to + if (clusterType == null || clusterType == ClusterType.OTHER) null else Json.JsonValue(clusterType) + ).filterValues { it != null }.map { Pair(it.key, it.value!!) }.toMap()) + private fun getPropertyHeader(json: Json.JsonValue) = PropertyCommonRequestHeader( json.getObjectValue(PropertyCommonHeaderKeys.RESOURCE)?.stringValue ?: "", @@ -221,10 +242,14 @@ class CommonRulesPropertyService(private val device: MidiCIDevice) private fun getPropertyDataJson(header: PropertyCommonRequestHeader): Pair { val body = when(header.resource) { - PropertyResourceNames.RESOURCE_LIST -> Json.JsonValue(getMetadataList().map { (it as CommonRulesPropertyMetadata).toJsonValue() }) - PropertyResourceNames.DEVICE_INFO -> getDeviceInfoJson() - PropertyResourceNames.CHANNEL_LIST -> channelList - PropertyResourceNames.JSON_SCHEMA -> if (device.config.jsonSchemaString.isNotBlank()) Json.parse(device.config.jsonSchemaString) else null + PropertyResourceNames.RESOURCE_LIST -> + Json.JsonValue(getMetadataList().map { (it as CommonRulesPropertyMetadata).toJsonValue() }) + PropertyResourceNames.DEVICE_INFO -> + getDeviceInfoJson() + PropertyResourceNames.CHANNEL_LIST -> + if (channelList.channels.isEmpty()) null else Json.JsonValue(channelList.channels.map { it.toJson() }) + PropertyResourceNames.JSON_SCHEMA -> + if (device.config.jsonSchemaString.isNotBlank()) Json.parse(device.config.jsonSchemaString) else null else -> { val bytes = linkedResources[header.resId] ?: values.firstOrNull { it.id == header.resource }?.body ?: throw PropertyExchangeException("Unknown property: ${header.resource} (resId: ${header.resId}") diff --git a/ktmidi-ci/src/commonTest/kotlin/dev/atsushieno/ktmidi/ci/PropertyFacadesTest.kt b/ktmidi-ci/src/commonTest/kotlin/dev/atsushieno/ktmidi/ci/PropertyFacadesTest.kt index 3e894e521..e92ca3ff8 100644 --- a/ktmidi-ci/src/commonTest/kotlin/dev/atsushieno/ktmidi/ci/PropertyFacadesTest.kt +++ b/ktmidi-ci/src/commonTest/kotlin/dev/atsushieno/ktmidi/ci/PropertyFacadesTest.kt @@ -61,4 +61,18 @@ class PropertyFacadesTest { assertEquals(0, client.subscriptions.size, "client subscriptions.size after unsubscription by host") assertEquals(0, host.subscriptions.size, "host subscriptions.size after unsubscription by host") } + + @Test + fun propertyExchange2() { + val mediator = TestCIMediator() + val device1 = mediator.device1 + val device2 = mediator.device2 + + device2.config.channelList.channels.add(MidiCIChannel("TestChannel1", 1)) + + device1.sendDiscovery() + val conn = device1.connections[device2.muid]!! + val channelList = conn.propertyClient.properties.getProperty("ChannelList") + assertNotNull(channelList, "ChannelList should not be null") + } }