From 51b0454fbc836c52851d06afcee2d69d6a521233 Mon Sep 17 00:00:00 2001 From: NoMathExpectation <85624722+NoMathExpectation@users.noreply.github.com> Date: Sat, 7 Mar 2026 17:45:46 +0800 Subject: [PATCH] Added SetRowXsEvent. --- .../cn/rdlevel/rdkt/core/data/RowPattern.kt | 6 +- .../rdkt/core/events/EventProperties.kt | 2 +- .../rdlevel/rdkt/core/events/SetRowXsEvent.kt | 201 ++++++++++++++++++ 3 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/SetRowXsEvent.kt diff --git a/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/data/RowPattern.kt b/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/data/RowPattern.kt index 78ef44e..a2b7067 100644 --- a/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/data/RowPattern.kt +++ b/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/data/RowPattern.kt @@ -14,7 +14,7 @@ public class RowPattern { /** * The pattern string representing the pulse pattern of the row. It must be exactly 6 characters long, and each character must be one of the allowed characters defined in [ALLOWED_CHARS]. */ - public var pattern: String = "------" + public var pattern: String = DEFAULT_PATTERN_STRING set(value) { require(value.length == 6) { "Pulse pattern must be 6 characters long." } require(value.all { it in ALLOWED_CHARS }) { @@ -50,7 +50,7 @@ public class RowPattern { * Constructs a [RowPattern] with the specified pattern string. The pattern string must be exactly 6 characters long, and each character must be one of the allowed characters defined in [ALLOWED_CHARS]. */ public constructor( - pattern: String = "------", + pattern: String = DEFAULT_PATTERN_STRING, ) { this.pattern = pattern } @@ -118,6 +118,8 @@ public class RowPattern { * Characters allowed in the pattern string, corresponding to the defined pulse types. */ public const val ALLOWED_CHARS: String = "-xudbr" + + public const val DEFAULT_PATTERN_STRING: String = "------" } @OptIn(RDKTInternalAPI::class) diff --git a/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/EventProperties.kt b/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/EventProperties.kt index f607e6d..fa852e6 100644 --- a/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/EventProperties.kt +++ b/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/EventProperties.kt @@ -22,7 +22,7 @@ public interface BeatSpecificEvent : Event { } /** - * An [Event] that is specific to a Y position, aka the row position in the editor. + * An [Event] that is specific to a Y position, usually the row position in the editor. */ public interface YSpecificEvent : Event { /** diff --git a/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/SetRowXsEvent.kt b/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/SetRowXsEvent.kt new file mode 100644 index 0000000..8f4edca --- /dev/null +++ b/core/src/commonMain/kotlin/cn/rdlevel/rdkt/core/events/SetRowXsEvent.kt @@ -0,0 +1,201 @@ +@file:OptIn(RDKTInternalAPI::class) + +package cn.rdlevel.rdkt.core.events + + +import cn.rdlevel.rdkt.core.annotations.RDKTInternalAPI +import cn.rdlevel.rdkt.core.data.RowPattern +import cn.rdlevel.rdkt.core.serialization.TransformSerializer +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlin.jvm.JvmStatic + +/** + * Sets the row pattern and synco settings for a row. + * + * @property pattern The [RowPattern] representing the pulse pattern of the row. + * @property synco The [SyncoSettings] representing the synco settings of the row. + */ +@Serializable(SetRowXsEvent.Serializer::class) +@SerialName("SetRowXs") +public data class SetRowXsEvent( + var pattern: RowPattern = RowPattern(), + var synco: SyncoSettings = SyncoSettings.Disabled, +) : RowEvent() { + /** + * Represents the synco settings of a row. It can either be [Disabled] or [Enabled], where [Enabled] allows for further customization of the synco settings such as beat, swing, volume, pitch, and style. + */ + public sealed interface SyncoSettings { + public val beat: Int + + /** + * The synco beat is disabled. + */ + public object Disabled : SyncoSettings { + override val beat: Int = -1 + } + + /** + * The synco beat is enabled. + */ + public class Enabled : SyncoSettings { + /** + * The beat where the synco is active. It must be between 0 and 5, where 0 is the first beat. + * + * If you just want to disable the synco beat, consider use [SyncoSettings.Disabled] instead. + */ + override var beat: Int = 0 + set(value) { + require(value in 0..5) { "Synco beat must be between 0 and 5, but found: $value." } + field = value + } + + /** + * The reduced percentage of the [AddClassicBeatEvent.tick] on the synco [beat]. It must be between 0.0 and 1.0. Setting this to 0 will use the default 50% reduction. + */ + public var swing: Double = 0.0 + set(value) { + require(value in 0.0..1.0) { "Synco swing must be between 0.0 and 1.0, but found: $value." } + field = value + } + + /** + * The volume of the synco sound. It must be between 0 and 200. + */ + public var volume: Int = 70 + set(value) { + require(value in 0..200) { "Synco volume must be between 0 and 200, but found: $value." } + field = value + } + + /** + * The pitch of the synco sound. It must be between 0 and 200. + */ + public var pitch: Int = 100 + set(value) { + require(value in 0..200) { "Synco volume must be between 0 and 200, but found: $value." } + field = value + } + + /** + * The style of the synco sound. + */ + public var style: SyncoStyle = SyncoStyle.Chirp() + } + + public companion object { + /** + * Creates a [SyncoSettings] with the synco beat disabled. + */ + @JvmStatic + public fun disabled(): Disabled = Disabled + + /** + * Creates a [SyncoSettings] with the synco beat enabled and configures with the provided [block]. + */ + @JvmStatic + public fun enabled(block: Enabled.() -> Unit): Enabled { + val enabled = Enabled() + enabled.block() + return enabled + } + } + } + + /** + * Represents the style of the synco sound. + */ + public sealed class SyncoStyle(public val style: String) { + /** + * The chirp style. + * + * @property playModifierSound Whether to play sound when the synco is turned on. Default is true. + * @property playModifierOffSound Whether to play sound when the synco is turned off. Default is true. + */ + public data class Chirp( + var playModifierSound: Boolean = true, + var playModifierOffSound: Boolean = true, + ) : SyncoStyle("Chirp") + + /** + * The beep style. + */ + public data object Beep : SyncoStyle("Beep") + + public companion object { + /** + * Creates a [SyncoStyle] with the chirp style and configures with the provided parameters. + */ + @JvmStatic + public fun chirp( + playModifierSound: Boolean = true, + playModifierOffSound: Boolean = true, + ): Chirp = Chirp(playModifierSound, playModifierOffSound) + + /** + * Creates a [SyncoStyle] with the beep style. + */ + @JvmStatic + public fun beep(): Beep = Beep + } + } + + public object Serializer : TransformSerializer(Data.serializer()) { + override fun toData(value: SetRowXsEvent): Data { + return Data(pattern = value.pattern).apply { + val synco = value.synco + syncoBeat = synco.beat + if (synco !is SyncoSettings.Enabled) { + return@apply + } + + syncoSwing = synco.swing + syncoVolume = synco.volume + syncoPitch = synco.pitch + + val style = synco.style + syncoStyle = style.style + if (style is SyncoStyle.Chirp) { + syncoPlayModifierSound = style.playModifierSound + syncoPlayModifierOffSound = style.playModifierOffSound + } + } + } + + override fun fromData(data: Data): SetRowXsEvent { + val synco = if (data.syncoBeat == -1) { + SyncoSettings.disabled() + } else { + SyncoSettings.enabled { + beat = data.syncoBeat + swing = data.syncoSwing + volume = data.syncoVolume + pitch = data.syncoPitch + style = when (data.syncoStyle) { + "Chirp" -> SyncoStyle.Chirp( + playModifierSound = data.syncoPlayModifierSound, + playModifierOffSound = data.syncoPlayModifierOffSound, + ) + + "Beep" -> SyncoStyle.Beep + else -> throw IllegalArgumentException("Unknown synco style: ${data.syncoStyle}") + } + } + } + return SetRowXsEvent(pattern = data.pattern, synco = synco) + } + + @Serializable + @RDKTInternalAPI + public data class Data( + var pattern: RowPattern = RowPattern(), + var syncoBeat: Int = -1, + var syncoSwing: Double = 0.0, + var syncoVolume: Int = 70, + var syncoPitch: Int = 100, + var syncoStyle: String = "Chirp", + var syncoPlayModifierSound: Boolean = true, + var syncoPlayModifierOffSound: Boolean = true, + ) + } +} \ No newline at end of file