mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-14 04:24:05 +09:00
working musicbox
This commit is contained in:
Binary file not shown.
@@ -12,8 +12,7 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
|
|||||||
|
|
||||||
override val notCopyable = true
|
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 notes: IntArray, val maxlen: Int, var samplesDispatched: Int = 0) { // in many cases, samplesL and samplesR will point to the same object
|
||||||
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
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Msg(tick=$tick, samplesDispatched=$samplesDispatched)"
|
return "Msg(tick=$tick, samplesDispatched=$samplesDispatched)"
|
||||||
}
|
}
|
||||||
@@ -59,19 +58,11 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
|
|||||||
private fun queue(tick: Long, noteBits: Long) {
|
private fun queue(tick: Long, noteBits: Long) {
|
||||||
if (noteBits == 0L) return
|
if (noteBits == 0L) return
|
||||||
|
|
||||||
val notes = findSetBits(noteBits)
|
val notes = findSetBits(noteBits).toIntArray()
|
||||||
|
val maxlen = getSample(notes.first()).first.size
|
||||||
val buf = FloatArray(getSample(0).first.size)
|
|
||||||
|
|
||||||
// combine all those samples
|
|
||||||
notes.forEach { note ->
|
|
||||||
getSample(note).first.forEachIndexed { index, fl ->
|
|
||||||
buf[index] += fl
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// actually queue it
|
// actually queue it
|
||||||
val msg = Msg(tick, buf, buf)
|
val msg = Msg(tick, notes, maxlen)
|
||||||
messageQueue.add(messageQueue.size, msg)
|
messageQueue.add(messageQueue.size, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,9 +78,15 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
|
|||||||
// only copy over the past and current messages
|
// only copy over the past and current messages
|
||||||
messageQueue.filter { it.tick <= tickCount }.forEach {
|
messageQueue.filter { it.tick <= tickCount }.forEach {
|
||||||
// copy over the samples
|
// copy over the samples
|
||||||
for (i in 0 until minOf(bufferSize, it.samplesL.size - it.samplesDispatched)) {
|
it.notes.forEach { note ->
|
||||||
bufferL[i] += it.samplesL[i + it.samplesDispatched]
|
val noteSamples = getSample(note)
|
||||||
bufferR[i] += it.samplesR[i + it.samplesDispatched]
|
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
|
it.samplesDispatched += bufferSize
|
||||||
@@ -99,7 +96,7 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
|
|||||||
var rc = 0
|
var rc = 0
|
||||||
while (rc < messageQueue.size) {
|
while (rc < messageQueue.size) {
|
||||||
val it = messageQueue[rc]
|
val it = messageQueue[rc]
|
||||||
if (it.samplesDispatched >= it.samplesL.size) {
|
if (it.samplesDispatched >= it.maxlen) {
|
||||||
messageQueue.removeAt(rc)
|
messageQueue.removeAt(rc)
|
||||||
rc -= 1
|
rc -= 1
|
||||||
}
|
}
|
||||||
@@ -107,8 +104,6 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {})
|
|||||||
rc += 1
|
rc += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
printdbg(this, "Queuelen: ${messageQueue.size}")
|
|
||||||
|
|
||||||
return bufferSize
|
return bufferSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,24 +53,24 @@ class FixtureMechanicalTines : Electric {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transient private var testRollCursor = 0
|
@Transient private var testRollCursor = 0
|
||||||
@Transient private val TICK_DIVISOR = 12
|
|
||||||
|
|
||||||
override fun updateSignal() {
|
override fun updateSignal() {
|
||||||
// TODO update using network port
|
// TODO update using network port
|
||||||
|
|
||||||
|
|
||||||
if (isSignalHigh(0, 1)) {
|
if (isSignalHigh(0, 1)) {
|
||||||
if (INGAME.WORLD_UPDATE_TIMER % TICK_DIVISOR == 0L) {
|
// advance every tick
|
||||||
audioBank.sendMessage(testNotes[testRollCursor])
|
audioBank.sendMessage(testNotes[testRollCursor])
|
||||||
testRollCursor = (testRollCursor + 1) % testNotes.size
|
testRollCursor = (testRollCursor + 1) % testNotes.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@Transient val testNotes =
|
@Transient private val TICK_DIVISOR = 10
|
||||||
|
|
||||||
|
@Transient val testNotes = List(16*TICK_DIVISOR) { 0L } +
|
||||||
prel(24,28,31,36,40) +
|
prel(24,28,31,36,40) +
|
||||||
prel(24,26,33,38,41) +
|
prel(24,26,33,38,41) +
|
||||||
prel(23,26,31,38,41) +
|
prel(23,26,31,38,41) +
|
||||||
@@ -105,28 +105,32 @@ class FixtureMechanicalTines : Electric {
|
|||||||
prel( 0,12,19,22,28) +
|
prel( 0,12,19,22,28) +
|
||||||
end1( 0,12,17,21,24,29,21,17,14) +
|
end1( 0,12,17,21,24,29,21,17,14) +
|
||||||
end2( 0,11,31,35,38,41,26,29,28) +
|
end2( 0,11,31,35,38,41,26,29,28) +
|
||||||
end3( 0,12,28,31,36)
|
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> {
|
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,
|
||||||
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> {
|
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 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)
|
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> {
|
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 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)
|
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> {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
Reference in New Issue
Block a user