working musicbox

This commit is contained in:
minjaesong
2024-04-15 22:18:08 +09:00
parent c19184a55f
commit 24b5204560
4 changed files with 66 additions and 67 deletions

View File

@@ -12,8 +12,7 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
override val notCopyable = true
// TODO don't store samples (1MB each!), store numbers instead and synthesize on readSamples()
internal data class Msg(val tick: Long, val samplesL: FloatArray, val samplesR: FloatArray, var samplesDispatched: Int = 0) { // in many cases, samplesL and samplesR will point to the same object
internal data class Msg(val tick: Long, val notes: IntArray, val maxlen: Int, var samplesDispatched: Int = 0) { // in many cases, samplesL and samplesR will point to the same object
override fun toString(): String {
return "Msg(tick=$tick, samplesDispatched=$samplesDispatched)"
}
@@ -59,19 +58,11 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
private fun queue(tick: Long, noteBits: Long) {
if (noteBits == 0L) return
val notes = findSetBits(noteBits)
val buf = FloatArray(getSample(0).first.size)
// combine all those samples
notes.forEach { note ->
getSample(note).first.forEachIndexed { index, fl ->
buf[index] += fl
}
}
val notes = findSetBits(noteBits).toIntArray()
val maxlen = getSample(notes.first()).first.size
// actually queue it
val msg = Msg(tick, buf, buf)
val msg = Msg(tick, notes, maxlen)
messageQueue.add(messageQueue.size, msg)
}
@@ -87,9 +78,15 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
// only copy over the past and current messages
messageQueue.filter { it.tick <= tickCount }.forEach {
// copy over the samples
for (i in 0 until minOf(bufferSize, it.samplesL.size - it.samplesDispatched)) {
bufferL[i] += it.samplesL[i + it.samplesDispatched]
bufferR[i] += it.samplesR[i + it.samplesDispatched]
it.notes.forEach { note ->
val noteSamples = getSample(note)
val start = it.samplesDispatched
val end = minOf(start + bufferSize, noteSamples.first.size)
for (i in start until end) {
bufferL[i - start] += noteSamples.first[i]
bufferR[i - start] += noteSamples.second[i]
}
}
it.samplesDispatched += bufferSize
@@ -99,7 +96,7 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
var rc = 0
while (rc < messageQueue.size) {
val it = messageQueue[rc]
if (it.samplesDispatched >= it.samplesL.size) {
if (it.samplesDispatched >= it.maxlen) {
messageQueue.removeAt(rc)
rc -= 1
}
@@ -107,8 +104,6 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
rc += 1
}
printdbg(this, "Queuelen: ${messageQueue.size}")
return bufferSize
}

View File

@@ -53,80 +53,84 @@ class FixtureMechanicalTines : Electric {
}
@Transient private var testRollCursor = 0
@Transient private val TICK_DIVISOR = 12
override fun updateSignal() {
// TODO update using network port
if (isSignalHigh(0, 1)) {
if (INGAME.WORLD_UPDATE_TIMER % TICK_DIVISOR == 0L) {
audioBank.sendMessage(testNotes[testRollCursor])
testRollCursor = (testRollCursor + 1) % testNotes.size
}
// advance every tick
audioBank.sendMessage(testNotes[testRollCursor])
testRollCursor = (testRollCursor + 1) % testNotes.size
}
}
companion object {
@Transient val testNotes =
prel(24,28,31,36,40) +
prel(24,26,33,38,41) +
prel(23,26,31,38,41) +
prel(24,28,31,36,40) +
prel(24,28,33,40,45) +
prel(24,26,30,33,38) +
prel(23,26,31,38,43) +
prel(23,24,28,31,36) +
prel(21,24,28,31,36) +
prel(14,21,26,30,36) +
prel(19,23,26,31,35) +
prel(19,22,28,31,37) +
prel(17,21,26,33,38) +
prel(17,20,26,29,35) +
prel(16,19,24,31,36) +
prel(16,17,21,24,29) +
prel(14,17,21,24,29) +
prel( 7,14,19,23,29) +
prel(12,16,19,24,28) +
prel(12,19,22,24,28) +
prel( 5,17,21,24,28) +
prel( 6,12,21,24,27) +
prel( 8,17,23,24,26) +
prel( 7,17,19,23,26) +
prel( 7,16,19,24,28) +
prel( 7,14,19,24,29) +
prel( 7,14,19,23,29) +
prel( 7,15,21,24,30) +
prel( 7,16,19,24,31) +
prel( 7,14,19,24,29) +
prel( 7,14,19,23,29) +
prel( 0,12,19,22,28) +
end1( 0,12,17,21,24,29,21,17,14) +
end2( 0,11,31,35,38,41,26,29,28) +
end3( 0,12,28,31,36)
@Transient private val TICK_DIVISOR = 10
@Transient val testNotes = List(16*TICK_DIVISOR) { 0L } +
prel(24,28,31,36,40) +
prel(24,26,33,38,41) +
prel(23,26,31,38,41) +
prel(24,28,31,36,40) +
prel(24,28,33,40,45) +
prel(24,26,30,33,38) +
prel(23,26,31,38,43) +
prel(23,24,28,31,36) +
prel(21,24,28,31,36) +
prel(14,21,26,30,36) +
prel(19,23,26,31,35) +
prel(19,22,28,31,37) +
prel(17,21,26,33,38) +
prel(17,20,26,29,35) +
prel(16,19,24,31,36) +
prel(16,17,21,24,29) +
prel(14,17,21,24,29) +
prel( 7,14,19,23,29) +
prel(12,16,19,24,28) +
prel(12,19,22,24,28) +
prel( 5,17,21,24,28) +
prel( 6,12,21,24,27) +
prel( 8,17,23,24,26) +
prel( 7,17,19,23,26) +
prel( 7,16,19,24,28) +
prel( 7,14,19,24,29) +
prel( 7,14,19,23,29) +
prel( 7,15,21,24,30) +
prel( 7,16,19,24,31) +
prel( 7,14,19,24,29) +
prel( 7,14,19,23,29) +
prel( 0,12,19,22,28) +
end1( 0,12,17,21,24,29,21,17,14) +
end2( 0,11,31,35,38,41,26,29,28) +
end3( 0,12,28,31,36) + List(16*TICK_DIVISOR - 5) { 0L }
private fun prel(n1: Int, n2: Int, n3: Int, n4: Int, n5: Int): List<Long> {
return listOf(
return toPianoRoll(
1L shl n1, 1L shl n2, 1L shl n3, 1L shl n4, 1L shl n5, 1L shl n3, 1L shl n4, 1L shl n5,
1L shl n1, 1L shl n2, 1L shl n3, 1L shl n4, 1L shl n5, 1L shl n3, 1L shl n4, 1L shl n5)
}
private fun end1(n1: Int, n2: Int, n3: Int, n4: Int, n5: Int, n6: Int, n7: Int, n8: Int, n9: Int): List<Long> {
return listOf(
return toPianoRoll(
1L shl n1, 1L shl n2, 1L shl n3, 1L shl n4, 1L shl n5, 1L shl n6, 1L shl n5, 1L shl n4,
1L shl n5, 1L shl n7, 1L shl n8, 1L shl n7, 1L shl n8, 1L shl n9, 1L shl n8, 1L shl n9)
}
private fun end2(n1: Int, n2: Int, n3: Int, n4: Int, n5: Int, n6: Int, n7: Int, n8: Int, n9: Int): List<Long> {
return listOf(
return toPianoRoll(
1L shl n1, 1L shl n2, 1L shl n3, 1L shl n4, 1L shl n5, 1L shl n6, 1L shl n5, 1L shl n4,
1L shl n5, 1L shl n4, 1L shl n3, 1L shl n4, 1L shl n7, 1L shl n8, 1L shl n9, 1L shl n7)
}
private fun end3(vararg ns: Int): List<Long> {
return listOf(ns.map { 1L shl it }.fold(0L) { acc, note -> acc or note }) + List(15) { 0L }
return ns.map { 1L shl it } // arpeggiate
}
private fun toPianoRoll(vararg notes: Long) = List<Long>(notes.size * TICK_DIVISOR) {
if (it % TICK_DIVISOR == 0) notes[it / TICK_DIVISOR] else 0
}
}
}