From 63070a19d50f14d75d785bda47400c8db46a34c9 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sun, 7 Jul 2024 02:53:57 +0900 Subject: [PATCH] fix: continuous album now plays again --- .../musicplayer/gui/MusicPlayerControl.kt | 26 +++++++++++-------- src/net/torvald/terrarum/MusicService.kt | 16 +++++++++++- .../torvald/terrarum/TerrarumMusicPlaylist.kt | 17 ++++++------ src/net/torvald/terrarum/audio/AudioMixer.kt | 12 ++++----- .../audio/dsp/{Gain.kt => PreGain.kt} | 4 +-- .../gameactors/FixtureAlloyingFurnace.kt | 10 +++---- .../gameactors/FixtureFurnaceAndAnvil.kt | 10 +++---- .../gameactors/FixtureSmelterBasic.kt | 10 +++---- .../terrarum/transaction/Transaction.kt | 7 ++--- .../terrarum/ui/BasicDebugInfoWindow.kt | 9 +++++++ 10 files changed, 75 insertions(+), 46 deletions(-) rename src/net/torvald/terrarum/audio/dsp/{Gain.kt => PreGain.kt} (91%) diff --git a/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt b/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt index 46df447cf..f1c8d553a 100644 --- a/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt +++ b/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt @@ -709,6 +709,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() { // debug codes + //// transaction state if (MusicService.transactionLocked) { batch.color = Color.RED Toolkit.drawTextCentered(batch, App.fontSmallNumbers, "LOCKED", Toolkit.drawWidth, 0, _posY.toInt() + height + 5) @@ -717,11 +718,24 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() { batch.color = Color.WHITE Toolkit.drawTextCentered(batch, App.fontSmallNumbers, "UNLOCKED", Toolkit.drawWidth, 0, _posY.toInt() + height + 5) } - + //// MusicService internal state batch.color = Color.WHITE val musicState = MusicService.currentPlaybackState.get() val str = "State: $musicState Wait: ${MusicService.waitAkku.toIntAndFrac(2)}/${MusicService.waitTime}" Toolkit.drawTextCentered(batch, App.fontSmallNumbers, str, Toolkit.drawWidth, 0, _posY.toInt() + height + 18) + //// playlist internal indices + MusicService.currentPlaylist?.let { + val indices = it.extortField>("internalIndices")!! + val currentIndex = it.extortField("currentIndexCursor")!! + + for (k in 0 until indices.size) { + batch.color = if (k == currentIndex) Color.RED else Color.WHITE + App.fontSmallNumbers.draw(batch, "${indices[k]+1}", 28f + 18f * (k), App.scr.hf - 16f) + } + } + batch.color = Color.LIGHT_GRAY + App.fontSmallNumbers.draw(batch, "Playlist InternalIndices", 10f, App.scr.hf - 30f) + App.fontSmallNumbers.draw(batch, "..", 10f, App.scr.hf - 16f) // end of debug codes @@ -1347,16 +1361,6 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() { private fun loadNewAlbum(albumDir: File): TerrarumMusicPlaylist { val albumProp = albumPropCache[albumDir] - App.audioMixer.musicTrack.let { track -> - track.doGaplessPlayback = (albumProp.diskJockeyingMode == "continuous") - if (track.doGaplessPlayback) { - track.pullNextTrack = { - track.currentTrack = MusicService.currentPlaylist!!.queueNext() - setMusicName(track.currentTrack?.name ?: "") - } - } - } - currentlySelectedAlbum = albumProp return registerPlaylist(albumDir.absolutePath, albumProp.fileToName, albumProp.shuffled, albumProp.diskJockeyingMode) diff --git a/src/net/torvald/terrarum/MusicService.kt b/src/net/torvald/terrarum/MusicService.kt index 3e4594fec..48381ea0f 100644 --- a/src/net/torvald/terrarum/MusicService.kt +++ b/src/net/torvald/terrarum/MusicService.kt @@ -166,6 +166,7 @@ object MusicService : TransactionListener() { stopPlaylistPlayback {} } + /** * Puts the given playlist to this object if the transaction successes. If the given playlist is same as the * current playlist, the transaction will successfully finish immediately; otherwise the given playlist will @@ -213,11 +214,22 @@ object MusicService : TransactionListener() { oldPlaylist?.dispose() (state["currentPlaylist"] as TerrarumMusicPlaylist?)?.let { + // set songFinishedHook for every song it.musicList.forEach { it.songFinishedHook = { onMusicFinishing(it) } } + + // set gaplessness of the Music track + App.audioMixer.musicTrack.let { track -> + track.doGaplessPlayback = (it.diskJockeyingMode == "continuous") + if (track.doGaplessPlayback) { + track.pullNextTrack = { + track.currentTrack = MusicService.currentPlaylist!!.queueNext() + } + } + } } onSuccess() @@ -313,7 +325,9 @@ object MusicService : TransactionListener() { if (err != null) throw err!! } - override fun onSuccess(state: TransactionState) { onSuccess() } + override fun onSuccess(state: TransactionState) { + onSuccess() + } override fun onFailure(e: Throwable, state: TransactionState) { e.printStackTrace() } diff --git a/src/net/torvald/terrarum/TerrarumMusicPlaylist.kt b/src/net/torvald/terrarum/TerrarumMusicPlaylist.kt index 16e411724..75214bce1 100644 --- a/src/net/torvald/terrarum/TerrarumMusicPlaylist.kt +++ b/src/net/torvald/terrarum/TerrarumMusicPlaylist.kt @@ -26,7 +26,7 @@ class TerrarumMusicPlaylist( ): Disposable { private val internalIndices = ArrayList() - private var currentIndexCursor = musicList.size + private var currentIndexCursor = musicList.size - 1 init { reset() @@ -36,7 +36,7 @@ class TerrarumMusicPlaylist( internalIndices.clear() refillInternalIndices() refillInternalIndices() - currentIndexCursor = musicList.size + currentIndexCursor = musicList.size - 1 } private fun checkRefill() { @@ -50,6 +50,11 @@ class TerrarumMusicPlaylist( return musicList[internalIndices[currentIndexCursor]] } + /** + * For Gapless playback, this function is called by track's pullNextTrack callback (defined in [MusicService.createTransactionPlaylistChange]) + * + * For intermittent playback, this function is called by the transaction defined in [MusicService.update] + */ fun queueNext(): MusicContainer { checkRefill() currentIndexCursor += 1 @@ -81,16 +86,12 @@ class TerrarumMusicPlaylist( fun queueNthSong(n: Int): MusicContainer { checkRefill() internalIndices.add(currentIndexCursor, n) + currentIndexCursor -= 1 return musicList[internalIndices[currentIndexCursor]] } private fun refillInternalIndices() { - if (diskJockeyingMode == "continuous") { - internalIndices.add(0) // playlist is a one long track for the gapless playback - } - else { - internalIndices.addAll(musicList.indices.toMutableList().also { if (shuffled) it.shuffle() }) - } + internalIndices.addAll(musicList.indices.toMutableList().also { if (shuffled) it.shuffle() }) } diff --git a/src/net/torvald/terrarum/audio/AudioMixer.kt b/src/net/torvald/terrarum/audio/AudioMixer.kt index c30acb28a..a701c1b98 100644 --- a/src/net/torvald/terrarum/audio/AudioMixer.kt +++ b/src/net/torvald/terrarum/audio/AudioMixer.kt @@ -250,7 +250,7 @@ class AudioMixer : Disposable { // initialise audio paths // listOf(musicTrack, ambientTrack1, ambientTrack2, ambientTrack3, ambientTrack4, guiTrack).forEach { - it.filters[0] = Gain(1f) + it.filters[0] = PreGain(1f) } guiTracks.forEach { @@ -285,11 +285,11 @@ class AudioMixer : Disposable { } convolveBusOpen.filters[1] = Convolv("basegame", "audio/convolution/EchoThief - PurgatoryChasm.bin", decibelsToFullscale(-6.0).toFloat()) - convolveBusOpen.filters[2] = Gain(decibelsToFullscale(17.0).toFloat()) // don't make it too loud; it'll sound like a shit + convolveBusOpen.filters[2] = PreGain(decibelsToFullscale(17.0).toFloat()) // don't make it too loud; it'll sound like a shit convolveBusOpen.volume = 0.5 // will be controlled by the other updater which surveys the world convolveBusCave.filters[1] = Convolv("basegame", "audio/convolution/EchoThief - WaterplacePark-trimmed.bin", decibelsToFullscale(-3.0).toFloat()) - convolveBusCave.filters[2] = Gain(decibelsToFullscale(16.0).toFloat()) + convolveBusCave.filters[2] = PreGain(decibelsToFullscale(16.0).toFloat()) convolveBusCave.volume = 0.5 // will be controlled by the other updater which surveys the world fadeBus.addSidechainInput(sumBus, 1.0 / 3.0) @@ -392,12 +392,12 @@ class AudioMixer : Disposable { // the real updates (Gdx.audio as? Lwjgl3Audio)?.update() masterTrack.volume = masterVolume - musicTrack.getFilter().gain = musicVolume.toFloat() * 0.5f + musicTrack.getFilter().gain = musicVolume.toFloat() * 0.5f ambientTracks.forEach { - it.getFilter().gain = ambientVolume.toFloat() + it.getFilter().gain = ambientVolume.toFloat() } sfxSumBus.volume = sfxVolume - guiTrack.getFilter().gain = guiVolume.toFloat() + guiTrack.getFilter().gain = guiVolume.toFloat() // process fades diff --git a/src/net/torvald/terrarum/audio/dsp/Gain.kt b/src/net/torvald/terrarum/audio/dsp/PreGain.kt similarity index 91% rename from src/net/torvald/terrarum/audio/dsp/Gain.kt rename to src/net/torvald/terrarum/audio/dsp/PreGain.kt index 1dc659506..769f1ad4e 100644 --- a/src/net/torvald/terrarum/audio/dsp/Gain.kt +++ b/src/net/torvald/terrarum/audio/dsp/PreGain.kt @@ -9,7 +9,7 @@ import kotlin.math.roundToInt /** * Created by minjaesong on 2023-11-25. */ -class Gain(var gain: Float): TerrarumAudioFilter() { +class PreGain(var gain: Float): TerrarumAudioFilter() { override fun thru(inbuf: List, outbuf: List) { for (i in 0 until App.audioBufferSize) { outbuf[0][i] = inbuf[0][i] * gain @@ -25,7 +25,7 @@ class Gain(var gain: Float): TerrarumAudioFilter() { override val debugViewHeight = 16 override fun copyParamsFrom(other: TerrarumAudioFilter) { - if (other is Gain) { + if (other is PreGain) { this.gain = other.gain } } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureAlloyingFurnace.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureAlloyingFurnace.kt index e67b9262f..9fb1cb1fd 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureAlloyingFurnace.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureAlloyingFurnace.kt @@ -9,7 +9,7 @@ import net.torvald.spriteanimation.SheetSpriteAnimation import net.torvald.terrarum.* import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.audio.audiobank.MusicContainer -import net.torvald.terrarum.audio.dsp.Gain +import net.torvald.terrarum.audio.dsp.PreGain import net.torvald.terrarum.audio.dsp.NullFilter import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.gameactors.AVKey @@ -361,7 +361,7 @@ class FixtureAlloyingFurnace : FixtureBase { getTrackByAudio(static).let { if (it == null || (temperature > 0f && !it.isPlaying && !it.playRequested.get())) { startAudio(static) { - it.filters[filterIndex] = Gain(0f) + it.filters[filterIndex] = PreGain(0f) } } else if (it != null && it.isPlaying && temperature <= 0f) { @@ -371,10 +371,10 @@ class FixtureAlloyingFurnace : FixtureBase { } if (it != null) { - if (it.filters[filterIndex] !is Gain) // just in case... - it.filters[filterIndex] = Gain(0f) + if (it.filters[filterIndex] !is PreGain) // just in case... + it.filters[filterIndex] = PreGain(0f) - (it.filters[filterIndex] as Gain).gain = (it.maxVolume * temperature * volRand.get()).toFloat() + (it.filters[filterIndex] as PreGain).gain = (it.maxVolume * temperature * volRand.get()).toFloat() } } diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureFurnaceAndAnvil.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureFurnaceAndAnvil.kt index fe840129b..364a44689 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureFurnaceAndAnvil.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureFurnaceAndAnvil.kt @@ -4,7 +4,7 @@ import net.torvald.gdx.graphics.Cvec import net.torvald.spriteanimation.SheetSpriteAnimation import net.torvald.terrarum.* import net.torvald.terrarum.audio.audiobank.MusicContainer -import net.torvald.terrarum.audio.dsp.Gain +import net.torvald.terrarum.audio.dsp.PreGain import net.torvald.terrarum.audio.dsp.NullFilter import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.gameactors.AVKey @@ -112,7 +112,7 @@ class FixtureFurnaceAndAnvil : FixtureBase, CraftingStation { if (audioStatus == 0) { startAudio(static) { - it.filters[filterIndex] = Gain(0f) + it.filters[filterIndex] = PreGain(0f) audioStatus = 1 } } @@ -124,10 +124,10 @@ class FixtureFurnaceAndAnvil : FixtureBase, CraftingStation { if (it != null) { if (it.processor.streamBuf != null || it.playRequested.get()) { - if (it.filters[filterIndex] !is Gain) // just in case... - it.filters[filterIndex] = Gain(0f) + if (it.filters[filterIndex] !is PreGain) // just in case... + it.filters[filterIndex] = PreGain(0f) - (it.filters[filterIndex] as Gain).gain = 0.4f * volRand.get() + (it.filters[filterIndex] as PreGain).gain = 0.4f * volRand.get() } else { audioStatus = 0 diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureSmelterBasic.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureSmelterBasic.kt index 3c99141c8..d58689922 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureSmelterBasic.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureSmelterBasic.kt @@ -9,7 +9,7 @@ import net.torvald.spriteanimation.SheetSpriteAnimation import net.torvald.terrarum.* import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED import net.torvald.terrarum.audio.audiobank.MusicContainer -import net.torvald.terrarum.audio.dsp.Gain +import net.torvald.terrarum.audio.dsp.PreGain import net.torvald.terrarum.audio.dsp.NullFilter import net.torvald.terrarum.blockproperties.Block import net.torvald.terrarum.gameactors.AVKey @@ -348,7 +348,7 @@ class FixtureSmelterBasic : FixtureBase { getTrackByAudio(static).let { if (it == null || (temperature > 0f && !it.isPlaying && !it.playRequested.get())) { startAudio(static) { - it.filters[filterIndex] = Gain(0f) + it.filters[filterIndex] = PreGain(0f) } } else if (it != null && it.isPlaying && temperature <= 0f) { @@ -358,10 +358,10 @@ class FixtureSmelterBasic : FixtureBase { } if (it != null) { - if (it.filters[filterIndex] !is Gain) // just in case... - it.filters[filterIndex] = Gain(0f) + if (it.filters[filterIndex] !is PreGain) // just in case... + it.filters[filterIndex] = PreGain(0f) - (it.filters[filterIndex] as Gain).gain = (it.maxVolume * temperature * volRand.get()).toFloat() + (it.filters[filterIndex] as PreGain).gain = (it.maxVolume * temperature * volRand.get()).toFloat() } } diff --git a/src/net/torvald/terrarum/transaction/Transaction.kt b/src/net/torvald/terrarum/transaction/Transaction.kt index c8dd659ab..584119dbe 100644 --- a/src/net/torvald/terrarum/transaction/Transaction.kt +++ b/src/net/torvald/terrarum/transaction/Transaction.kt @@ -58,6 +58,7 @@ abstract class TransactionListener { catch (e: Throwable) { // if failed, notify the failure System.err.println("Transaction failure: generic") + e.printStackTrace() transaction.onFailure(e, state) } finally { @@ -67,7 +68,7 @@ abstract class TransactionListener { } else { System.err.println("Transaction failure: locked") - transaction.onFailure(LockedException(this, currentLock), state) + transaction.onFailure(LockedException(transaction, this, currentLock), state) } }.start() } @@ -76,8 +77,8 @@ abstract class TransactionListener { protected abstract fun commitTransaction(state: TransactionState) } -class LockedException(listener: TransactionListener, lockedBy: Transaction) : - Exception("Transaction is rejected because the class '${listener.javaClass.canonicalName}' is locked by '${lockedBy.javaClass.canonicalName}'") +class LockedException(offendingTransaction: Transaction, listener: TransactionListener, lockedBy: Transaction) : + Exception("Transaction '$offendingTransaction' is rejected because the class '$listener' is locked by '$lockedBy'") @JvmInline value class TransactionState(val valueTable: HashMap) { operator fun get(key: String) = valueTable[key] diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index 70dc5813a..cb87dd22d 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -665,6 +665,7 @@ class BasicDebugInfoWindow : UICanvas() { else it }, //"C:${track.currentTrack?.codec ?: ""}", + "GL:${if (track.doGaplessPlayback) "Y" else "N"}", "R:${track.currentTrack?.samplingRate ?: ""}", ).forEachIndexed { i, s -> // gauge background @@ -680,6 +681,14 @@ class BasicDebugInfoWindow : UICanvas() { Toolkit.fillArea(batch, x.toFloat(), faderY - (i + 1) * 16f + 14f, STRIP_W * perc, 2f) } + // fill the back if the track is in gapless mode + if (i == 1 && track.doGaplessPlayback) { + batch.color = COL_PROGRESS_GRAD2 + Toolkit.fillArea(batch, x.toFloat(), faderY - (i + 1) * 16f, STRIP_W.toFloat(), 14f) + batch.color = COL_PROGRESS_GRAD + Toolkit.fillArea(batch, x.toFloat(), faderY - (i + 1) * 16f + 14f, STRIP_W.toFloat(), 2f) + } + batch.color = FILTER_NAME_ACTIVE App.fontSmallNumbers.draw(batch, s, x + 3f, faderY - (i + 1) * 16f + 1f) }