Refactor KeyboardComponent with constants for note and key handling

Replaced hardcoded values for octaves, keys, and dimensions with named constants for improved readability and maintainability. Simplified calculations and loops using these constants. Enhanced clarity in key rendering and MIDI note calculations.
This commit is contained in:
2025-06-07 11:39:21 +02:00
parent 9ab909cf6c
commit 5c16b57ae9

View File

@@ -47,8 +47,8 @@ class KeyboardComponent(
get() = _octave
set(value) {
_octave = when {
value < 0 -> 0
value > 9 -> 9
value < MIN_OCTAVE -> MIN_OCTAVE
value > MAX_OCTAVE -> MAX_OCTAVE
else -> value
}
requestUpdate()
@@ -57,14 +57,14 @@ class KeyboardComponent(
// Set to track which notes are currently pressed
private val pressedNotes = mutableSetOf<Int>()
// MIDI note numbers for C4 to B4 (one octave)
private val whiteKeys = listOf(60, 62, 64, 65, 67, 69, 71)
private val blackKeys = listOf(61, 63, 66, 68, 70)
// MIDI note numbers for one octave
private val whiteKeys = BASE_WHITE_KEYS
private val blackKeys = BASE_BLACK_KEYS
// Key dimensions
private val whiteKeyWidth = keyboardWidth / 7
private val blackKeyWidth = (keyboardWidth / 9)
private val blackKeyHeight = keyboardHeight * 60 / 100
private val whiteKeyWidth = keyboardWidth / WHITE_KEYS_PER_OCTAVE
private val blackKeyWidth = (keyboardWidth / BLACK_KEY_WIDTH_DIVISOR)
private val blackKeyHeight = keyboardHeight * BLACK_KEY_HEIGHT_PERCENTAGE / 100
// Calculate positions for black keys
private val blackKeyPositions = listOf(
@@ -97,12 +97,12 @@ class KeyboardComponent(
pressedNotes.clear()
}
private fun getOctaveOffset(): Int = (octave - 5) * 12
private fun getOctaveOffset(): Int = (octave - OCTAVE_BASE) * NOTES_PER_OCTAVE
private fun getMidiNoteFromMousePosition(x: Double, y: Double): Int? {
// Check if click is on a black key (black keys are on top of white keys)
if (y <= blackKeyHeight) {
for (j in 0 until 5) {
for (j in 0 until BLACK_KEYS_PER_OCTAVE) {
if (x >= blackKeyPositions[j] && x <= blackKeyPositions[j] + blackKeyWidth) {
return blackKeys[j] + getOctaveOffset()
}
@@ -110,13 +110,13 @@ class KeyboardComponent(
// If no black key was pressed, check for white key
val keyIndex = (x / whiteKeyWidth).toInt()
if (keyIndex in 0..6) {
if (keyIndex in 0 until WHITE_KEYS_PER_OCTAVE) {
return whiteKeys[keyIndex] + getOctaveOffset()
}
} else {
// If y > blackKeyHeight, it's definitely a white key
val keyIndex = (x / whiteKeyWidth).toInt()
if (keyIndex in 0..6) {
if (keyIndex in 0 until WHITE_KEYS_PER_OCTAVE) {
return whiteKeys[keyIndex] + getOctaveOffset()
}
}
@@ -125,7 +125,7 @@ class KeyboardComponent(
override fun HtmlBuilder.render() {
div(KeyboardCls.name) {
style = "width: ${keyboardWidth}px; height: ${keyboardHeight + 60}px"
style = "width: ${keyboardWidth}px; height: ${keyboardHeight + KEYBOARD_CONTROLS_HEIGHT}px"
onMouseLeaveFunction = { event ->
if (event is MouseEvent) {
@@ -196,7 +196,7 @@ class KeyboardComponent(
}
// Draw white keys
for (i in 0 until 7) {
for (i in 0 until WHITE_KEYS_PER_OCTAVE) {
val midiNote = whiteKeys[i] + getOctaveOffset()
val isPressed = pressedNotes.contains(midiNote)
rect(
@@ -210,7 +210,7 @@ class KeyboardComponent(
}
// Draw black keys
for (i in 0 until 5) {
for (i in 0 until BLACK_KEYS_PER_OCTAVE) {
val midiNote = blackKeys[i] + getOctaveOffset()
val isPressed = pressedNotes.contains(midiNote)
rect(
@@ -228,6 +228,7 @@ class KeyboardComponent(
}
companion object : CssId("keyboard") {
// CSS class names
object KeyboardCls : CssName()
object KeyboardControlsCls : CssName()
object KeyboardInfoCls : CssName()
@@ -240,6 +241,21 @@ class KeyboardComponent(
object WhiteKeyPressedCls : CssName()
object BlackKeyPressedCls : CssName()
// Constants
private const val OCTAVE_BASE = 5
private const val NOTES_PER_OCTAVE = 12
private const val BLACK_KEY_HEIGHT_PERCENTAGE = 60
private const val MIN_OCTAVE = 0
private const val MAX_OCTAVE = 9
private const val WHITE_KEYS_PER_OCTAVE = 7
private const val BLACK_KEYS_PER_OCTAVE = 5
private const val BLACK_KEY_WIDTH_DIVISOR = 9
private const val KEYBOARD_CONTROLS_HEIGHT = 60
// MIDI note numbers for C5 to B5 (one octave)
private val BASE_WHITE_KEYS = listOf(60, 62, 64, 65, 67, 69, 71) // C, D, E, F, G, A, B
private val BASE_BLACK_KEYS = listOf(61, 63, 66, 68, 70) // C#, D#, F#, G#, A#
init {
defineCss {
select(cls(KeyboardCls)) {