mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
musicbox wip
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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<Msg>()
|
||||
private val messageQueue = ArrayList<Msg>()
|
||||
|
||||
private fun findSetBits(num: Long): List<Int> {
|
||||
val result = mutableListOf<Int>()
|
||||
@@ -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<Msg>(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<Int> {
|
||||
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)
|
||||
|
||||
}
|
||||
@@ -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<FloatArray, FloatArray>
|
||||
*
|
||||
* 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())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user