mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-13 20:14:05 +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 val totalSizeInSamples: Long
|
||||||
abstract fun currentPositionInSamples(): Long
|
abstract fun currentPositionInSamples(): Long
|
||||||
|
|
||||||
abstract fun readBytes(buffer: ByteArray): Int
|
abstract fun readSamples(bufferL: FloatArray, bufferR: FloatArray): Int
|
||||||
abstract fun reset()
|
abstract fun reset()
|
||||||
|
|
||||||
abstract val songFinishedHook: (AudioBank) -> Unit
|
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.
|
* 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 pitch: Float = 1f
|
||||||
var playbackSpeed = 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 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 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 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 {
|
init {
|
||||||
// printdbg(this, "App.audioMixerBufferSize=${App.audioBufferSize}")
|
// 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 readCount = if (samplesInBuf < App.audioBufferSize) fetchSize else 0
|
||||||
val writeCount = (readCount / q).roundToInt()
|
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) {
|
if (readCount > 0) {
|
||||||
try {
|
try {
|
||||||
shift(finL, readCount)
|
shift(finL, readCount)
|
||||||
shift(finR, readCount)
|
shift(finR, readCount)
|
||||||
|
|
||||||
val bytesRead = audioReadFun(readBuf)
|
val samplesRead = audioReadFun(readBufL, readBufR)
|
||||||
// printdbg(this, "Reading audio $readCount samples, got ${bytesRead?.div(4)} samples")
|
// 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")
|
// printdbg(this, "Music finished; bytesRead = $bytesRead")
|
||||||
|
|
||||||
onAudioFinished()
|
onAudioFinished()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (c in 0 until readCount) {
|
for (c in 0 until readCount) {
|
||||||
val sl = (getFromReadBuf(4 * c + 0, bytesRead) or getFromReadBuf(4 * c + 1, bytesRead).shl(8)).toShort()
|
val fl = getFromReadBufL(c, samplesRead)
|
||||||
val sr = (getFromReadBuf(4 * c + 2, bytesRead) or getFromReadBuf(4 * c + 3, bytesRead).shl(8)).toShort()
|
val fr = getFromReadBufR(c, samplesRead)
|
||||||
|
|
||||||
val fl = sl / 32767f
|
|
||||||
val fr = sr / 32767f
|
|
||||||
|
|
||||||
finL[2 * PADSIZE + c] = fl
|
finL[2 * PADSIZE + c] = fl
|
||||||
finR[2 * PADSIZE + c] = fr
|
finR[2 * PADSIZE + c] = fr
|
||||||
@@ -217,6 +216,7 @@ class AudioProcessBuf(val inputSamplingRate: Int, val audioReadFun: (ByteArray)
|
|||||||
// printdbg(this, "phase = $fPhaseL")
|
// printdbg(this, "phase = $fPhaseL")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return the copy of the foutL/R
|
||||||
fun getLR(): Pair<FloatArray, FloatArray> {
|
fun getLR(): Pair<FloatArray, FloatArray> {
|
||||||
val samplesInBuf = validSamplesInBuf
|
val samplesInBuf = validSamplesInBuf
|
||||||
|
|
||||||
|
|||||||
@@ -88,29 +88,33 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud
|
|||||||
|
|
||||||
private fun allocateStreamBuf(track: TerrarumAudioMixerTrack) {
|
private fun allocateStreamBuf(track: TerrarumAudioMixerTrack) {
|
||||||
printdbg("Allocating a StreamBuf with rate ${track.currentTrack!!.samplingRate}")
|
printdbg("Allocating a StreamBuf with rate ${track.currentTrack!!.samplingRate}")
|
||||||
streamBuf = AudioProcessBuf(track.currentTrack!!.samplingRate, { buffer ->
|
streamBuf = AudioProcessBuf(track.currentTrack!!.samplingRate, { bufL, bufR ->
|
||||||
var bytesRead = track.currentTrack?.readBytes(buffer) ?: 0
|
var samplesRead = track.currentTrack?.readSamples(bufL, bufR) ?: 0
|
||||||
|
|
||||||
// do gapless fetch if there is space in the buffer
|
// 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.currentTrack?.reset()
|
||||||
track.pullNextTrack()
|
track.pullNextTrack()
|
||||||
|
|
||||||
bytesRead += read0(buffer, bytesRead)
|
samplesRead += read00(bufL, bufR, samplesRead)
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesRead
|
samplesRead
|
||||||
}, { purgeStreamBuf() }).also {
|
}, { purgeStreamBuf() }).also {
|
||||||
// it.jitterMode = jitterMode
|
// it.jitterMode = jitterMode
|
||||||
// it.jitterIntensity = jitterIntensity
|
// it.jitterIntensity = jitterIntensity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun read0(buffer: ByteArray, bytesRead: Int): Int {
|
private fun read00(bufL: FloatArray, bufR: FloatArray, samplesRead: Int): Int {
|
||||||
val tmpBuf = ByteArray(buffer.size - bytesRead)
|
val bufSize = bufL.size - samplesRead
|
||||||
val newRead = track.currentTrack?.readBytes(tmpBuf) ?: 0
|
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
|
return newRead
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import javazoom.jl.decoder.Bitstream
|
|||||||
import net.torvald.reflection.extortField
|
import net.torvald.reflection.extortField
|
||||||
import net.torvald.reflection.forceInvoke
|
import net.torvald.reflection.forceInvoke
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.terrarum.serialise.toUint
|
||||||
import net.torvald.unsafe.UnsafeHelper
|
import net.torvald.unsafe.UnsafeHelper
|
||||||
import net.torvald.unsafe.UnsafePtr
|
import net.torvald.unsafe.UnsafePtr
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -121,16 +122,38 @@ class MusicContainer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun read0(buffer: ByteArray, bytesRead: Int): Int {
|
override fun readSamples(bufferL: FloatArray, bufferR: FloatArray): Int {
|
||||||
val tmpBuf = ByteArray(buffer.size - bytesRead)
|
assert(bufferL.size == bufferR.size)
|
||||||
val newRead = readBytes(tmpBuf)
|
|
||||||
|
|
||||||
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) {
|
if (soundBuf == null) {
|
||||||
val bytesRead = gdxMusic.forceInvoke<Int>("read", arrayOf(buffer)) ?: 0
|
val bytesRead = gdxMusic.forceInvoke<Int>("read", arrayOf(buffer)) ?: 0
|
||||||
samplesReadCount += bytesRead / bytesPerSample
|
samplesReadCount += bytesRead / bytesPerSample
|
||||||
|
|||||||
Reference in New Issue
Block a user