mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-11 11:04: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,80 +53,84 @@ 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
|
||||||
prel(24,28,31,36,40) +
|
|
||||||
prel(24,26,33,38,41) +
|
@Transient val testNotes = List(16*TICK_DIVISOR) { 0L } +
|
||||||
prel(23,26,31,38,41) +
|
prel(24,28,31,36,40) +
|
||||||
prel(24,28,31,36,40) +
|
prel(24,26,33,38,41) +
|
||||||
prel(24,28,33,40,45) +
|
prel(23,26,31,38,41) +
|
||||||
prel(24,26,30,33,38) +
|
prel(24,28,31,36,40) +
|
||||||
prel(23,26,31,38,43) +
|
prel(24,28,33,40,45) +
|
||||||
prel(23,24,28,31,36) +
|
prel(24,26,30,33,38) +
|
||||||
prel(21,24,28,31,36) +
|
prel(23,26,31,38,43) +
|
||||||
prel(14,21,26,30,36) +
|
prel(23,24,28,31,36) +
|
||||||
prel(19,23,26,31,35) +
|
prel(21,24,28,31,36) +
|
||||||
prel(19,22,28,31,37) +
|
prel(14,21,26,30,36) +
|
||||||
prel(17,21,26,33,38) +
|
prel(19,23,26,31,35) +
|
||||||
prel(17,20,26,29,35) +
|
prel(19,22,28,31,37) +
|
||||||
prel(16,19,24,31,36) +
|
prel(17,21,26,33,38) +
|
||||||
prel(16,17,21,24,29) +
|
prel(17,20,26,29,35) +
|
||||||
prel(14,17,21,24,29) +
|
prel(16,19,24,31,36) +
|
||||||
prel( 7,14,19,23,29) +
|
prel(16,17,21,24,29) +
|
||||||
prel(12,16,19,24,28) +
|
prel(14,17,21,24,29) +
|
||||||
prel(12,19,22,24,28) +
|
prel( 7,14,19,23,29) +
|
||||||
prel( 5,17,21,24,28) +
|
prel(12,16,19,24,28) +
|
||||||
prel( 6,12,21,24,27) +
|
prel(12,19,22,24,28) +
|
||||||
prel( 8,17,23,24,26) +
|
prel( 5,17,21,24,28) +
|
||||||
prel( 7,17,19,23,26) +
|
prel( 6,12,21,24,27) +
|
||||||
prel( 7,16,19,24,28) +
|
prel( 8,17,23,24,26) +
|
||||||
prel( 7,14,19,24,29) +
|
prel( 7,17,19,23,26) +
|
||||||
prel( 7,14,19,23,29) +
|
prel( 7,16,19,24,28) +
|
||||||
prel( 7,15,21,24,30) +
|
prel( 7,14,19,24,29) +
|
||||||
prel( 7,16,19,24,31) +
|
prel( 7,14,19,23,29) +
|
||||||
prel( 7,14,19,24,29) +
|
prel( 7,15,21,24,30) +
|
||||||
prel( 7,14,19,23,29) +
|
prel( 7,16,19,24,31) +
|
||||||
prel( 0,12,19,22,28) +
|
prel( 7,14,19,24,29) +
|
||||||
end1( 0,12,17,21,24,29,21,17,14) +
|
prel( 7,14,19,23,29) +
|
||||||
end2( 0,11,31,35,38,41,26,29,28) +
|
prel( 0,12,19,22,28) +
|
||||||
end3( 0,12,28,31,36)
|
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> {
|
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