music playlist is working again

This commit is contained in:
minjaesong
2023-11-18 13:13:19 +09:00
parent 7219b95542
commit 62c7b36a46
6 changed files with 56 additions and 19 deletions

View File

@@ -32,7 +32,7 @@ object AudioMixer: Disposable {
private val masterTrack = TerrarumAudioMixerTrack("Master", true).also { master -> private val masterTrack = TerrarumAudioMixerTrack("Master", true).also { master ->
tracks.forEach { master.addSidechainInput(it, 1.0) } tracks.forEach { master.addSidechainInput(it, 1.0) }
// master.filters[0] = Lowpass(240, TerrarumAudioMixerTrack.SAMPLING_RATE) master.filters[0] = Lowpass(48000, TerrarumAudioMixerTrack.SAMPLING_RATE)
} }
private val musicTrack: TerrarumAudioMixerTrack private val musicTrack: TerrarumAudioMixerTrack

View File

@@ -34,6 +34,28 @@ class AudioProcessBuf(val size: Int) {
updateFloats() updateFloats()
} }
// reusing a buffer causes tons of blips in the sound? how??
/*private val L0buf = FloatArray(size / 4)
private val R0buf = FloatArray(size / 4)
private val L1buf = FloatArray(size / 4)
private val R1buf = FloatArray(size / 4)
fun getL0(volume: Double): FloatArray {
for (i in L0buf.indices) { L0buf[i] = (volume * fbuf0[2*i]).toFloat() }
return L0buf
}
fun getR0(volume: Double): FloatArray {
for (i in R0buf.indices) { R0buf[i] = (volume * fbuf0[2*i+1]).toFloat() }
return R0buf
}
fun getL1(volume: Double): FloatArray {
for (i in L1buf.indices) { L1buf[i] = (volume * fbuf1[2*i]).toFloat() }
return L1buf
}
fun getR1(volume: Double): FloatArray {
for (i in R1buf.indices) { R1buf[i] = (volume * fbuf1[2*i+1]).toFloat() }
return R1buf
}*/
fun getL0(volume: Double) = FloatArray(size / 4) { (volume * fbuf0[2*it]).toFloat() } fun getL0(volume: Double) = FloatArray(size / 4) { (volume * fbuf0[2*it]).toFloat() }
fun getR0(volume: Double) = FloatArray(size / 4) { (volume * fbuf0[2*it+1]).toFloat() } fun getR0(volume: Double) = FloatArray(size / 4) { (volume * fbuf0[2*it+1]).toFloat() }
fun getL1(volume: Double) = FloatArray(size / 4) { (volume * fbuf1[2*it]).toFloat() } fun getL1(volume: Double) = FloatArray(size / 4) { (volume * fbuf1[2*it]).toFloat() }

View File

@@ -3,6 +3,7 @@ package net.torvald.terrarum.audio
import com.badlogic.gdx.utils.Queue import com.badlogic.gdx.utils.Queue
import net.torvald.reflection.forceInvoke import net.torvald.reflection.forceInvoke
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
import kotlin.math.absoluteValue
/** /**
* Created by minjaesong on 2023-11-17. * Created by minjaesong on 2023-11-17.
@@ -22,6 +23,8 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
private var fout0 = listOf(emptyBuf, emptyBuf) private var fout0 = listOf(emptyBuf, emptyBuf)
private var fout1 = listOf(emptyBuf, emptyBuf) private var fout1 = listOf(emptyBuf, emptyBuf)
var maxSigLevel = arrayOf(0.0, 0.0); private set
private var breakBomb = false private var breakBomb = false
private fun printdbg(msg: Any) { private fun printdbg(msg: Any) {
@@ -58,7 +61,13 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
// fetch deviceBufferSize amount of sample from the disk // fetch deviceBufferSize amount of sample from the disk
if (!track.isMaster && track.streamPlaying) { if (!track.isMaster && track.streamPlaying) {
streamBuf.fetchBytes { streamBuf.fetchBytes {
track.currentTrack?.gdxMusic?.forceInvoke<Int>("read", arrayOf(it)) val bytesRead = track.currentTrack?.gdxMusic?.forceInvoke<Int>("read", arrayOf(it))
if (bytesRead == null || bytesRead <= 0) { // some class (namely Mp3) may return 0 instead of negative value
// printdbg("Finished reading audio stream")
track.currentTrack?.gdxMusic?.forceInvoke<Int>("reset", arrayOf())
track.streamPlaying = false
track.fireSongFinishHook()
}
} }
} }
@@ -146,6 +155,8 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
// by this time, the output buffer is filled with processed results, pause the execution // by this time, the output buffer is filled with processed results, pause the execution
if (!track.isMaster) { if (!track.isMaster) {
fout1.map { it.maxBy { it.absoluteValue } }.forEachIndexed { index, fl -> maxSigLevel[index] = fl.toDouble() }
this.pause() this.pause()
} }
else { else {
@@ -156,7 +167,7 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
Thread.sleep(1) Thread.sleep(1)
} }
// printdbg("Pushing to queue (queue size: ${track.pcmQueue.size})") // printdbg("PUSHE; Queue size: ${track.pcmQueue.size}")
track.pcmQueue.addLast(fout1) track.pcmQueue.addLast(fout1)
} }
@@ -216,20 +227,18 @@ class FeedSamplesToAdev(val bufferSize: Int, val rate: Int, val track: TerrarumA
while (!exit) { while (!exit) {
val writeQueue = track.pcmQueue val writeQueue = track.pcmQueue
val queueSize = writeQueue.size
if (writeQueue.notEmpty()) { if (queueSize > 0) {
// printdbg("Taking samples from queue (queue size: ${writeQueue.size})") // printdbg("PULL; Queue size: $queueSize")
val samples = writeQueue.removeFirst() val samples = writeQueue.removeFirst()
track.adev!!.writeSamples(samples) track.adev!!.writeSamples(samples)
} }
else if (writeQueue.isEmpty) { // else {
// printdbg("!! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED ") // printdbg("QUEUE EMPTY QUEUE EMPTY QUEUE EMPTY ")
} // }
Thread.sleep((bufferSize / 8L / rate).coerceAtLeast(1L)) Thread.sleep((bufferSize / 8L / rate).coerceAtLeast(1L))
} }
// printdbg("FeedSamplesToAdev EXIT")
} }
fun stop() { fun stop() {

View File

@@ -46,4 +46,4 @@ class Lowpass(cutoff: Int, rate: Int): TerrarumAudioFilter() {
} }
} }
} }

View File

@@ -116,10 +116,14 @@ class TerrarumAudioMixerTrack(val name: String, val isMaster: Boolean = false):
override fun equals(other: Any?) = this.hash == (other as TerrarumAudioMixerTrack).hash override fun equals(other: Any?) = this.hash == (other as TerrarumAudioMixerTrack).hash
fun fireSongFinishHook() {
currentTrack?.songFinishedHook?.invoke(currentTrack!!.gdxMusic)
}
// 1st ring of the hell: the THREADING HELL // // 1st ring of the hell: the THREADING HELL //
val BUFFER_SIZE = 8192 val BUFFER_SIZE = 16384
internal var processor = MixerTrackProcessor(BUFFER_SIZE, SAMPLING_RATE, this) internal var processor = MixerTrackProcessor(BUFFER_SIZE, SAMPLING_RATE, this)
private val processorThread = Thread(processor).also { private val processorThread = Thread(processor).also {

View File

@@ -12,8 +12,13 @@ import java.io.File
data class MusicContainer( data class MusicContainer(
val name: String, val name: String,
val file: File, val file: File,
val gdxMusic: Music val gdxMusic: Music,
val songFinishedHook: (Music) -> Unit
) { ) {
init {
gdxMusic.setOnCompletionListener(songFinishedHook)
}
override fun toString() = if (name.isEmpty()) file.nameWithoutExtension else name override fun toString() = if (name.isEmpty()) file.nameWithoutExtension else name
} }
@@ -26,11 +31,8 @@ class TerrarumMusicGovernor : MusicGovernor() {
MusicContainer( MusicContainer(
it.nameWithoutExtension.replace('_', ' ').split(" ").map { it.capitalize() }.joinToString(" "), it.nameWithoutExtension.replace('_', ' ').split(" ").map { it.capitalize() }.joinToString(" "),
it, it,
Gdx.audio.newMusic(Gdx.files.absolute(it.absolutePath)).also { Gdx.audio.newMusic(Gdx.files.absolute(it.absolutePath)),
it.setOnCompletionListener { { stopMusic() }
stopMusic()
}
}
) )
} }
catch (e: GdxRuntimeException) { catch (e: GdxRuntimeException) {