mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
audiobank now returns samples in floats
This commit is contained in:
@@ -25,7 +25,7 @@ abstract class AudioBank : Disposable {
|
||||
abstract val totalSizeInSamples: Long
|
||||
abstract fun currentPositionInSamples(): Long
|
||||
|
||||
abstract fun readBytes(buffer: ByteArray): Int
|
||||
abstract fun readSamples(bufferL: FloatArray, bufferR: FloatArray): Int
|
||||
abstract fun reset()
|
||||
|
||||
abstract val songFinishedHook: (AudioBank) -> Unit
|
||||
|
||||
@@ -25,7 +25,7 @@ private data class Frac(var nom: Int, val denom: Int) {
|
||||
*
|
||||
* Created by minjaesong on 2023-11-17.
|
||||
*/
|
||||
class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray) -> Int?, val onAudioFinished: () -> Unit) {
|
||||
class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (FloatArray, FloatArray) -> Int?, val onAudioFinished: () -> Unit) {
|
||||
|
||||
var pitch: Float = 1f
|
||||
var playbackSpeed = 1f
|
||||
@@ -144,7 +144,8 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
||||
private val fmidR = FloatArray((fetchSize * 2 + 1.0).toInt())
|
||||
private val foutL = FloatArray(internalBufferSize) // 640 for (44100, 48000), 512 for (48000, 48000) with BUFFER_SIZE = 512 * 4
|
||||
private val foutR = FloatArray(internalBufferSize) // 640 for (44100, 48000), 512 for (48000, 48000) with BUFFER_SIZE = 512 * 4
|
||||
private val readBuf = ByteArray(fetchSize * 4)
|
||||
private val readBufL = FloatArray(fetchSize)
|
||||
private val readBufR = FloatArray(fetchSize)
|
||||
|
||||
init {
|
||||
// printdbg(this, "App.audioMixerBufferSize=${App.audioBufferSize}")
|
||||
@@ -160,28 +161,26 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
||||
val readCount = if (samplesInBuf < App.audioBufferSize) fetchSize else 0
|
||||
val writeCount = (readCount / q).roundToInt()
|
||||
|
||||
fun getFromReadBuf(i: Int, bytesRead: Int) = if (i < bytesRead) readBuf[i].toUint() else 0
|
||||
fun getFromReadBufL(index: Int, samplesRead: Int) = if (index < samplesRead) readBufL[index] else 0f
|
||||
fun getFromReadBufR(index: Int, samplesRead: Int) = if (index < samplesRead) readBufR[index] else 0f
|
||||
|
||||
if (readCount > 0) {
|
||||
try {
|
||||
shift(finL, readCount)
|
||||
shift(finR, readCount)
|
||||
|
||||
val bytesRead = audioReadFun(readBuf)
|
||||
val samplesRead = audioReadFun(readBufL, readBufR)
|
||||
// printdbg(this, "Reading audio $readCount samples, got ${bytesRead?.div(4)} samples")
|
||||
|
||||
if (bytesRead == null || bytesRead <= 0) {
|
||||
if (samplesRead == null || samplesRead <= 0) {
|
||||
// printdbg(this, "Music finished; bytesRead = $bytesRead")
|
||||
|
||||
onAudioFinished()
|
||||
}
|
||||
else {
|
||||
for (c in 0 until readCount) {
|
||||
val sl = (getFromReadBuf(4 * c + 0, bytesRead) or getFromReadBuf(4 * c + 1, bytesRead).shl(8)).toShort()
|
||||
val sr = (getFromReadBuf(4 * c + 2, bytesRead) or getFromReadBuf(4 * c + 3, bytesRead).shl(8)).toShort()
|
||||
|
||||
val fl = sl / 32767f
|
||||
val fr = sr / 32767f
|
||||
val fl = getFromReadBufL(c, samplesRead)
|
||||
val fr = getFromReadBufR(c, samplesRead)
|
||||
|
||||
finL[2 * PADSIZE + c] = fl
|
||||
finR[2 * PADSIZE + c] = fr
|
||||
@@ -217,6 +216,7 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
||||
// printdbg(this, "phase = $fPhaseL")
|
||||
}
|
||||
|
||||
// return the copy of the foutL/R
|
||||
fun getLR(): Pair<FloatArray, FloatArray> {
|
||||
val samplesInBuf = validSamplesInBuf
|
||||
|
||||
|
||||
@@ -88,29 +88,33 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud
|
||||
|
||||
private fun allocateStreamBuf(track: TerrarumAudioMixerTrack) {
|
||||
printdbg("Allocating a StreamBuf with rate ${track.currentTrack!!.samplingRate}")
|
||||
streamBuf = AudioProcessBuf(track.currentTrack!!.samplingRate, { buffer ->
|
||||
var bytesRead = track.currentTrack?.readBytes(buffer) ?: 0
|
||||
streamBuf = AudioProcessBuf(track.currentTrack!!.samplingRate, { bufL, bufR ->
|
||||
var samplesRead = track.currentTrack?.readSamples(bufL, bufR) ?: 0
|
||||
|
||||
// do gapless fetch if there is space in the buffer
|
||||
if (track.doGaplessPlayback && bytesRead < buffer.size) {
|
||||
if (track.doGaplessPlayback && samplesRead < bufL.size) {
|
||||
track.currentTrack?.reset()
|
||||
track.pullNextTrack()
|
||||
|
||||
bytesRead += read0(buffer, bytesRead)
|
||||
samplesRead += read00(bufL, bufR, samplesRead)
|
||||
}
|
||||
|
||||
bytesRead
|
||||
samplesRead
|
||||
}, { purgeStreamBuf() }).also {
|
||||
// it.jitterMode = jitterMode
|
||||
// it.jitterIntensity = jitterIntensity
|
||||
}
|
||||
}
|
||||
|
||||
private fun read0(buffer: ByteArray, bytesRead: Int): Int {
|
||||
val tmpBuf = ByteArray(buffer.size - bytesRead)
|
||||
val newRead = track.currentTrack?.readBytes(tmpBuf) ?: 0
|
||||
private fun read00(bufL: FloatArray, bufR: FloatArray, samplesRead: Int): Int {
|
||||
val bufSize = bufL.size - samplesRead
|
||||
val tmpBufL = FloatArray(bufSize)
|
||||
val tmpBufR = FloatArray(bufSize)
|
||||
|
||||
System.arraycopy(tmpBuf, 0, buffer, bytesRead, tmpBuf.size)
|
||||
val newRead = track.currentTrack?.readSamples(tmpBufL, tmpBufR) ?: 0
|
||||
|
||||
System.arraycopy(tmpBufL, 0, bufL, samplesRead, tmpBufL.size)
|
||||
System.arraycopy(tmpBufR, 0, bufR, samplesRead, tmpBufR.size)
|
||||
|
||||
return newRead
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import javazoom.jl.decoder.Bitstream
|
||||
import net.torvald.reflection.extortField
|
||||
import net.torvald.reflection.forceInvoke
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import net.torvald.terrarum.serialise.toUint
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
import net.torvald.unsafe.UnsafePtr
|
||||
import java.io.File
|
||||
@@ -121,16 +122,38 @@ class MusicContainer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun read0(buffer: ByteArray, bytesRead: Int): Int {
|
||||
val tmpBuf = ByteArray(buffer.size - bytesRead)
|
||||
val newRead = readBytes(tmpBuf)
|
||||
override fun readSamples(bufferL: FloatArray, bufferR: FloatArray): Int {
|
||||
assert(bufferL.size == bufferR.size)
|
||||
|
||||
System.arraycopy(tmpBuf, 0, buffer, bytesRead, tmpBuf.size)
|
||||
val byteSize = bufferL.size * bytesPerSample
|
||||
val bytesBuf = ByteArray(byteSize)
|
||||
val bytesRead = readBytes(bytesBuf)
|
||||
val samplesRead = bytesRead / bytesPerSample
|
||||
|
||||
return newRead
|
||||
if (channels == 2) {
|
||||
for (i in 0 until samplesRead) {
|
||||
val sl = (bytesBuf[i * 4 + 0].toUint() or bytesBuf[i * 4 + 1].toUint().shl(8)).toShort()
|
||||
val sr = (bytesBuf[i * 4 + 2].toUint() or bytesBuf[i * 4 + 3].toUint().shl(8)).toShort()
|
||||
val fl = sl / 32767f
|
||||
val fr = sr / 32767f
|
||||
bufferL[i] = fl
|
||||
bufferR[i] = fr
|
||||
}
|
||||
}
|
||||
else if (channels == 1) {
|
||||
for (i in 0 until samplesRead) {
|
||||
val s = (bytesBuf[i * 2 + 0].toUint() or bytesBuf[i * 2 + 1].toUint().shl(8)).toShort()
|
||||
val f = s / 32767f
|
||||
bufferL[i] = f
|
||||
bufferR[i] = f
|
||||
}
|
||||
}
|
||||
else throw IllegalStateException("Unsupported channel count: $channels")
|
||||
|
||||
return samplesRead
|
||||
}
|
||||
|
||||
override fun readBytes(buffer: ByteArray): Int {
|
||||
private fun readBytes(buffer: ByteArray): Int {
|
||||
if (soundBuf == null) {
|
||||
val bytesRead = gdxMusic.forceInvoke<Int>("read", arrayOf(buffer)) ?: 0
|
||||
samplesReadCount += bytesRead / bytesPerSample
|
||||
|
||||
Reference in New Issue
Block a user