Update MIDI message handling and version increment

Refactored MIDI message classes to improve modularity and flexibility, introducing separate classes for distinct MIDI message types. Updated `build.gradle.kts` version to `0.2.0` to reflect these changes. Removed `.idea/.name` file as part of cleanup.
This commit is contained in:
2024-12-16 20:13:41 +01:00
parent 00d8a67ed0
commit a592e91882
8 changed files with 188 additions and 5 deletions

View File

@@ -50,7 +50,7 @@ class TimedMidiMessage() : MidiMessage(
Type("midi", DataType.BLOB, 48),
) {
var timeToPlay by double("timeToPlay")
var midi by blob("data")
var midi by blob("midi")
init {
this.type = MidiMessageTypes.MIDI_DATA.typeId

View File

@@ -0,0 +1,78 @@
package nl.astraeus.midi.message
class SortedTimedMidiMessageList(
val reservedSize: Int = 1024
) {
val list = Array<TimedMidiMessage>(reservedSize) { TimedMidiMessage(0.0) }
var full = false
var readPointer = 0
var writePointer = 0
private fun Int.wrappedAdd(delta:Int): Int = (this + reservedSize + delta) % reservedSize
fun size(): Int = (writePointer - readPointer + reservedSize) % reservedSize
fun isEmpty(): Boolean = !full && size() == 0
fun isNotEmpty(): Boolean = !isEmpty()
fun nextTimestamp(): Double? = if (isNotEmpty()) {
list[readPointer].timeToPlay
} else {
null
}
fun lastTimestamp(): Double? = if (isNotEmpty()) {
val lastPointer = writePointer.wrappedAdd(-1)
list[lastPointer].timeToPlay
} else {
null
}
fun add(message: TimedMidiMessage) {
check(!full) {
"SortedTimedMidiMessageList is full!"
}
val time = message.timeToPlay
if (message.timeToPlay < (nextTimestamp() ?: 0.0)) {
readPointer = readPointer.wrappedAdd(-1)
list[readPointer] = message
} else if (message.timeToPlay > (lastTimestamp() ?: 0.0)) {
list[writePointer] = message
writePointer = writePointer.wrappedAdd(1)
} else {
var index = readPointer
while(index != writePointer && list[index].timeToPlay < time) {
index = index.wrappedAdd(1)
}
if (index == writePointer) {
writePointer = writePointer.wrappedAdd(1)
list[writePointer] = message
} else {
val writePosition = index
while(index != writePointer) {
list[index.wrappedAdd(1)] = list[index]
index = index.wrappedAdd(1)
}
writePointer = writePointer.wrappedAdd(1)
list[writePosition] = message
}
}
full = readPointer == writePointer
}
fun read(): TimedMidiMessage {
check(isNotEmpty()) {
"Can't read from an empty list!"
}
val message = list[readPointer]
readPointer = readPointer.wrappedAdd(1)
full = false
return message
}
}

View File

@@ -0,0 +1,61 @@
package nl.astraeus.midi.message
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class SortedTimedMidiMessageListTest {
@Test
fun testInsert() {
val list = SortedTimedMidiMessageList(5)
list.add(TimedMidiMessage(1.0, 1, 2, 3))
list.add(TimedMidiMessage(2.0, 2, 3, 4))
list.add(TimedMidiMessage(1.5, 3, 4, 5))
list.add(TimedMidiMessage(0.5, 4, 5, 6))
assertEquals(0.5, list.nextTimestamp())
assertEquals(0.5, list.read().timeToPlay)
assertEquals(1.0, list.read().timeToPlay)
assertEquals(1.5, list.read().timeToPlay)
assertEquals(2.0, list.read().timeToPlay)
}
@Test
fun testEmpty() {
assertFailsWith(IllegalStateException::class) {
val list = SortedTimedMidiMessageList(5)
list.read()
}
}
@Test
fun testFull() {
assertFailsWith(IllegalStateException::class) {
val list = SortedTimedMidiMessageList(2)
list.add(TimedMidiMessage(1.0, 1, 2, 3))
list.add(TimedMidiMessage(2.0, 2, 3, 4))
list.add(TimedMidiMessage(1.5, 3, 4, 5))
}
}
@Test
fun testFull2() {
val list = SortedTimedMidiMessageList(2)
list.add(TimedMidiMessage(1.0, 1, 2, 3))
list.add(TimedMidiMessage(2.0, 2, 3, 4))
assertEquals(true, list.full)
list.read()
assertEquals(false, list.full)
list.add(TimedMidiMessage(1.5, 3, 4, 5))
}
}