From 62c7b36a4684ac7a38184e9f667d9e21aeffaa60 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 18 Nov 2023 13:13:19 +0900 Subject: [PATCH] music playlist is working again --- src/net/torvald/terrarum/audio/AudioMixer.kt | 2 +- .../torvald/terrarum/audio/AudioProcessBuf.kt | 22 ++++++++++++++ .../terrarum/audio/MixerTrackProcessor.kt | 29 ++++++++++++------- .../terrarum/audio/TerrarumAudioFilter.kt | 2 +- .../terrarum/audio/TerrarumAudioMixerTrack.kt | 6 +++- .../modulebasegame/TerrarumMusicGovernor.kt | 14 +++++---- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/net/torvald/terrarum/audio/AudioMixer.kt b/src/net/torvald/terrarum/audio/AudioMixer.kt index 5ed1e04bc..a3050d6b1 100644 --- a/src/net/torvald/terrarum/audio/AudioMixer.kt +++ b/src/net/torvald/terrarum/audio/AudioMixer.kt @@ -32,7 +32,7 @@ object AudioMixer: Disposable { private val masterTrack = TerrarumAudioMixerTrack("Master", true).also { master -> 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 diff --git a/src/net/torvald/terrarum/audio/AudioProcessBuf.kt b/src/net/torvald/terrarum/audio/AudioProcessBuf.kt index a4442c4b7..85749e06f 100644 --- a/src/net/torvald/terrarum/audio/AudioProcessBuf.kt +++ b/src/net/torvald/terrarum/audio/AudioProcessBuf.kt @@ -34,6 +34,28 @@ class AudioProcessBuf(val size: Int) { 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 getR0(volume: Double) = FloatArray(size / 4) { (volume * fbuf0[2*it+1]).toFloat() } fun getL1(volume: Double) = FloatArray(size / 4) { (volume * fbuf1[2*it]).toFloat() } diff --git a/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt b/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt index f30f8dc9b..c5a91ef54 100644 --- a/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt +++ b/src/net/torvald/terrarum/audio/MixerTrackProcessor.kt @@ -3,6 +3,7 @@ package net.torvald.terrarum.audio import com.badlogic.gdx.utils.Queue import net.torvald.reflection.forceInvoke import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE +import kotlin.math.absoluteValue /** * 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 fout1 = listOf(emptyBuf, emptyBuf) + var maxSigLevel = arrayOf(0.0, 0.0); private set + private var breakBomb = false 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 if (!track.isMaster && track.streamPlaying) { streamBuf.fetchBytes { - track.currentTrack?.gdxMusic?.forceInvoke("read", arrayOf(it)) + val bytesRead = track.currentTrack?.gdxMusic?.forceInvoke("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("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 if (!track.isMaster) { + fout1.map { it.maxBy { it.absoluteValue } }.forEachIndexed { index, fl -> maxSigLevel[index] = fl.toDouble() } + this.pause() } else { @@ -156,7 +167,7 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru Thread.sleep(1) } -// printdbg("Pushing to queue (queue size: ${track.pcmQueue.size})") +// printdbg("PUSHE; Queue size: ${track.pcmQueue.size}") track.pcmQueue.addLast(fout1) } @@ -216,20 +227,18 @@ class FeedSamplesToAdev(val bufferSize: Int, val rate: Int, val track: TerrarumA while (!exit) { val writeQueue = track.pcmQueue - - if (writeQueue.notEmpty()) { -// printdbg("Taking samples from queue (queue size: ${writeQueue.size})") - + val queueSize = writeQueue.size + if (queueSize > 0) { +// printdbg("PULL; Queue size: $queueSize") val samples = writeQueue.removeFirst() track.adev!!.writeSamples(samples) } - else if (writeQueue.isEmpty) { -// printdbg("!! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED !! QUEUE EXHAUSTED ") - } +// else { +// printdbg("QUEUE EMPTY QUEUE EMPTY QUEUE EMPTY ") +// } Thread.sleep((bufferSize / 8L / rate).coerceAtLeast(1L)) } -// printdbg("FeedSamplesToAdev EXIT") } fun stop() { diff --git a/src/net/torvald/terrarum/audio/TerrarumAudioFilter.kt b/src/net/torvald/terrarum/audio/TerrarumAudioFilter.kt index 68a6c3319..5e339036a 100644 --- a/src/net/torvald/terrarum/audio/TerrarumAudioFilter.kt +++ b/src/net/torvald/terrarum/audio/TerrarumAudioFilter.kt @@ -46,4 +46,4 @@ class Lowpass(cutoff: Int, rate: Int): TerrarumAudioFilter() { } } -} \ No newline at end of file +} diff --git a/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt b/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt index 3cb8effd6..70aea352d 100644 --- a/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt +++ b/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt @@ -116,10 +116,14 @@ class TerrarumAudioMixerTrack(val name: String, val isMaster: Boolean = false): 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 // - val BUFFER_SIZE = 8192 + val BUFFER_SIZE = 16384 internal var processor = MixerTrackProcessor(BUFFER_SIZE, SAMPLING_RATE, this) private val processorThread = Thread(processor).also { diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumMusicGovernor.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumMusicGovernor.kt index 80836d1f6..5fb453eab 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumMusicGovernor.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumMusicGovernor.kt @@ -12,8 +12,13 @@ import java.io.File data class MusicContainer( val name: String, 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 } @@ -26,11 +31,8 @@ class TerrarumMusicGovernor : MusicGovernor() { MusicContainer( it.nameWithoutExtension.replace('_', ' ').split(" ").map { it.capitalize() }.joinToString(" "), it, - Gdx.audio.newMusic(Gdx.files.absolute(it.absolutePath)).also { - it.setOnCompletionListener { - stopMusic() - } - } + Gdx.audio.newMusic(Gdx.files.absolute(it.absolutePath)), + { stopMusic() } ) } catch (e: GdxRuntimeException) {