diff --git a/src/net/torvald/terrarum/audio/AudioBank.kt b/src/net/torvald/terrarum/audio/AudioBank.kt index 26a520832..d038d0788 100644 --- a/src/net/torvald/terrarum/audio/AudioBank.kt +++ b/src/net/torvald/terrarum/audio/AudioBank.kt @@ -18,6 +18,9 @@ abstract class AudioBank : Disposable { abstract val totalSizeInSamples: Long abstract fun currentPositionInSamples(): Long + open fun sendMessage(msg: String) {} + open fun sendMessage(bits: Long) {} + abstract fun readSamples(bufferL: FloatArray, bufferR: FloatArray): Int abstract fun reset() diff --git a/src/net/torvald/terrarum/modulebasegame/audio/audiobank/AudioBankMusicBox.kt b/src/net/torvald/terrarum/modulebasegame/audio/audiobank/AudioBankMusicBox.kt index 0fab6c503..33308548f 100644 --- a/src/net/torvald/terrarum/modulebasegame/audio/audiobank/AudioBankMusicBox.kt +++ b/src/net/torvald/terrarum/modulebasegame/audio/audiobank/AudioBankMusicBox.kt @@ -1,6 +1,5 @@ package net.torvald.terrarum.modulebasegame.audio.audiobank -import com.badlogic.gdx.utils.Queue import net.torvald.terrarum.App import net.torvald.terrarum.INGAME import net.torvald.terrarum.audio.AudioBank @@ -13,17 +12,17 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {}) private 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 val name = "spieluhr" - override val samplingRate = 48000 + override val samplingRate = 48000 // 122880 // use 122880 to make each tick is 2048 samples override val channels = 1 private val getSample = // usage: getSample(noteNum 0..60) InstrumentLoader.load("spieluhr", "basegame", "audio/effects/notes/spieluhr.ogg", 29) - private val SAMEPLES_PER_TICK = samplingRate / App.TICK_SPEED // should be 800 on default setting + private val SAMPLES_PER_TICK = samplingRate / App.TICK_SPEED // should be 800 on default setting override val totalSizeInSamples = getSample(0).first.size.toLong() // length of lowest-pitch note - private val messageQueue = Queue() + private val messageQueue = ArrayList() private fun findSetBits(num: Long): List { val result = mutableListOf() @@ -38,7 +37,7 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {}) /** * Queues the notes such that they are played on the next tick */ - fun queuePlay(noteBits: Long) { + override fun sendMessage(noteBits: Long) { if (noteBits == 0L) return val tick = INGAME.WORLD_UPDATE_TIMER + 1 @@ -54,17 +53,34 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {}) } // actually queue it - messageQueue.addLast(Msg(tick, buf, buf)) + messageQueue.add(Msg(tick, buf, buf)) } - override fun currentPositionInSamples(): Long { - TODO("Not yet implemented") - } + override fun currentPositionInSamples() = 0L override fun readSamples(bufferL: FloatArray, bufferR: FloatArray): Int { val tickCount = INGAME.WORLD_UPDATE_TIMER + val bufferSize = bufferL.size - TODO("Not yet implemented") + // 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.samplesDispatched += bufferSize + } + + + // dequeue the finished messages + val messagesToKill = ArrayList(messageQueue.filter { it.samplesDispatched >= it.samplesL.size }) + if (messagesToKill.isNotEmpty()) messagesToKill.forEach { + messageQueue.remove(it) + } + + return bufferSize } override fun reset() { @@ -78,4 +94,23 @@ class AudioBankMusicBox(override var songFinishedHook: (AudioBank) -> Unit = {}) override fun dispose() { TODO("Not yet implemented") } + + private fun prel(n1: Int, n2: Int, n3: Int, n4: Int, n5: Int): List { + return listOf( + n1, n2, n3, n4, n5, n3, n4, n5, + n1, n2, n3, n4, n5, n3, n4, n5 + ) + } + + private val testNotes = prel(0,0,0,0,0)+ + prel(24,28,31,36,40) + + prel(24, 26,33,28,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) + } \ No newline at end of file diff --git a/src/net/torvald/terrarum/modulebasegame/audio/audiobank/InstrumentLoader.kt b/src/net/torvald/terrarum/modulebasegame/audio/audiobank/InstrumentLoader.kt index 0b67972e7..bee3d903f 100644 --- a/src/net/torvald/terrarum/modulebasegame/audio/audiobank/InstrumentLoader.kt +++ b/src/net/torvald/terrarum/modulebasegame/audio/audiobank/InstrumentLoader.kt @@ -24,6 +24,8 @@ object InstrumentLoader { * Will read the sample and create 61 copies of them. Rendered samples will be stored on the CommonResourcePool * with the naming rule of `"${idBase}_${noteNumber}"`, with format of Pair * + * The sample must be in two channels, 48 kHz sampling rate. + * * If `isDualMono` option is set, two values of a pair will point to the same FloatArray. * * @param idBase Base ID string @@ -77,10 +79,11 @@ object InstrumentLoader { } private val TAPS = 8 + private val RESAMPLE_RATE = 1.0// 122880.0 / 48000.0 private fun resample(input: FloatArray, output: FloatArray, rate: Double) { for (sampleIdx in 0 until output.size) { - val t = sampleIdx.toDouble() * rate + val t = sampleIdx.toDouble() * rate * RESAMPLE_RATE val leftBound = maxOf(0, (t - TAPS + 1).floorToInt()) val rightBound = minOf(input.size - 1, (t + TAPS).ceilToInt())