From 90f7e8232560e582f33b66a725d6d807facd6eeb Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 6 Jul 2024 20:58:23 +0900 Subject: [PATCH] more transaction-based music disk jockeying wip --- .../musicplayer/gui/MusicPlayerControl.kt | 10 ++-- src/net/torvald/terrarum/MusicService.kt | 46 ++++++++----------- src/net/torvald/terrarum/MusicStreamer.kt | 8 ++-- src/net/torvald/terrarum/audio/AudioMixer.kt | 23 ++++++---- .../terrarum/audio/TerrarumAudioMixerTrack.kt | 1 - .../terrarum/modulebasegame/BuildingMaker.kt | 2 +- .../terrarum/modulebasegame/TerrarumIngame.kt | 2 +- ....kt => TerrarumMusicAndAmbientStreamer.kt} | 37 +-------------- .../gameactors/FixtureJukebox.kt | 1 - .../gameactors/FixtureMusicalTurntable.kt | 9 ++-- .../terrarum/transaction/Transaction.kt | 11 +++-- 11 files changed, 59 insertions(+), 91 deletions(-) rename src/net/torvald/terrarum/modulebasegame/{TerrarumMusicStreamer.kt => TerrarumMusicAndAmbientStreamer.kt} (89%) diff --git a/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt b/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt index ba87f1821..5a7a4a054 100644 --- a/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt +++ b/MusicPlayer/src/net/torvald/terrarum/musicplayer/gui/MusicPlayerControl.kt @@ -16,6 +16,7 @@ import net.torvald.terrarum.gameworld.fmod import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.gameactors.PlaysMusic import net.torvald.terrarum.ui.BasicDebugInfoWindow +import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.toIntAndFrac import net.torvald.terrarum.ui.MouseLatch import net.torvald.terrarum.ui.Toolkit import net.torvald.terrarum.ui.UICanvas @@ -191,7 +192,6 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() { private var mouseOnList: Int? = null override fun updateImpl(delta: Float) { - val transactionLocked = MusicService.transactionLocked val currentPlaylist = getCurrentPlaylist() // process transition request @@ -322,7 +322,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() { else null - // make button work + // make buttons work if (mouseUp) mouseLatch.latch { if (mouseOnButton != null) { when (mouseOnButton) { @@ -495,7 +495,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() { val playlist = loadNewAlbum(albumsList[index]) MusicService.putNewPlaylist(playlist) { resetPlaylistScroll(App.audioMixer.musicTrack.nextTrack as? MusicContainer) - App.audioMixer.startMusic(playlist.getCurrent()) + MusicService.resumePlaylistPlayback({}, {}) } } } @@ -723,7 +723,9 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() { } batch.color = Color.WHITE - Toolkit.drawTextCentered(batch, App.fontSmallNumbers, "State: ${MusicService.currentPlaybackState.get()}", Toolkit.drawWidth, 0, _posY.toInt() + height + 18) + 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) // end of debug codes diff --git a/src/net/torvald/terrarum/MusicService.kt b/src/net/torvald/terrarum/MusicService.kt index a0a42dd51..9ebcec61b 100644 --- a/src/net/torvald/terrarum/MusicService.kt +++ b/src/net/torvald/terrarum/MusicService.kt @@ -1,5 +1,6 @@ package net.torvald.terrarum +import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.audio.AudioBank import net.torvald.terrarum.audio.AudioMixer.Companion.DEFAULT_FADEOUT_LEN import net.torvald.terrarum.transaction.Transaction @@ -39,18 +40,18 @@ object MusicService : TransactionListener() { private const val STATE_PLAYING = 2 val currentPlaybackState = AtomicInteger(STATE_INTERMISSION) - private var waitAkku = 0f - private var waitTime = 10f + var waitAkku = 0f; private set + var waitTime = 10f; private set private fun enterSTATE_INTERMISSION(waitFor: Float) { currentPlaybackState.set(STATE_INTERMISSION) waitTime = waitFor waitAkku = 0f + playTransactionOngoing = false } private fun enterSTATE_FIREPLAY() { val state = currentPlaybackState.get() - if (state == STATE_FIREPLAY) throw IllegalStateException("Cannot change state FIREPLAY -> FIREPLAY") if (state == STATE_PLAYING) throw IllegalStateException("Cannot change state PLAYING -> FIREPLAY") waitAkku = 0f @@ -81,9 +82,7 @@ object MusicService : TransactionListener() { } fun onMusicFinishing(audio: AudioBank) { - synchronized(this) { - enterIntermissionAndWaitForPlaylist() - } + enterIntermissionAndWaitForPlaylist() } private var playTransactionOngoing = false @@ -120,6 +119,9 @@ object MusicService : TransactionListener() { } ) } + else { + println("PLAYing is deferred: playTransaction is ongoing") + } } STATE_PLAYING -> { // onMusicFinishing() will be called when the music finishes; it's on the setOnCompletionListener @@ -136,26 +138,22 @@ object MusicService : TransactionListener() { fun enterScene(id: String) { - synchronized(this) { - /*val playlist = when (id) { - "title" -> getTitlePlaylist() - "ingame" -> getIngameDefaultPlaylist() - else -> getIngameDefaultPlaylist() - } - - putNewPlaylist(playlist) { - // after the fadeout, we'll... - enterSTATE_FIREPLAY() - }*/ - - stopPlaylistPlayback { } + /*val playlist = when (id) { + "title" -> getTitlePlaylist() + "ingame" -> getIngameDefaultPlaylist() + else -> getIngameDefaultPlaylist() } + + putNewPlaylist(playlist) { + // after the fadeout, we'll... + enterSTATE_FIREPLAY() + }*/ + + stopPlaylistPlayback { } } fun leaveScene() { - synchronized(this) { - stopPlaylistPlayback {} - } + stopPlaylistPlayback {} } /** @@ -363,10 +361,8 @@ object MusicService : TransactionListener() { override fun start(state: TransactionState) { var fadedOut = false var err: Throwable? = null - println("createTransactionPausePlaylistForMusicalFixture start") // request fadeout App.audioMixer.requestFadeOut(App.audioMixer.musicTrack, DEFAULT_FADEOUT_LEN / 2.0) { - println("createTransactionPausePlaylistForMusicalFixture fadeout end") try { // callback: let the caller actually take care of playing the audio action() @@ -383,11 +379,9 @@ object MusicService : TransactionListener() { if (err != null) throw err!! // enter intermission state - println("createTransactionPausePlaylistForMusicalFixture fadeout waiting end, entering INTERMISSION state") enterSTATE_INTERMISSION(Float.POSITIVE_INFINITY) // wait until the interjected music finishes - println("createTransactionPausePlaylistForMusicalFixture waiting for musicFinished()") waitUntil { musicFinished() } } diff --git a/src/net/torvald/terrarum/MusicStreamer.kt b/src/net/torvald/terrarum/MusicStreamer.kt index 0f5866a97..95e340905 100644 --- a/src/net/torvald/terrarum/MusicStreamer.kt +++ b/src/net/torvald/terrarum/MusicStreamer.kt @@ -6,10 +6,10 @@ open class MusicStreamer { } - protected var musicState = 0 // 0: disabled, 1: playing, 2: waiting - protected var intermissionAkku = 0f - protected var intermissionLength = 1f - protected var musicFired = false +// protected var musicState = 0 // 0: disabled, 1: playing, 2: waiting +// protected var intermissionAkku = 0f +// protected var intermissionLength = 1f +// protected var musicFired = false open fun dispose() { diff --git a/src/net/torvald/terrarum/audio/AudioMixer.kt b/src/net/torvald/terrarum/audio/AudioMixer.kt index 75ef7fc0b..c30acb28a 100644 --- a/src/net/torvald/terrarum/audio/AudioMixer.kt +++ b/src/net/torvald/terrarum/audio/AudioMixer.kt @@ -339,7 +339,6 @@ class AudioMixer : Disposable { map[it] = FadeRequest() } } - private val fadeReqsCol = fadeReqs.entries private var lpAkku = 0.0 private var lpLength = 0.4 @@ -402,7 +401,7 @@ class AudioMixer : Disposable { // process fades - fadeReqsCol.forEach { val track = it.key; val req = it.value + fadeReqs.entries.forEach { val track = it.key; val req = it.value if (req.fadeoutFired) { req.fadeAkku += delta val step = req.fadeAkku / req.fadeLength @@ -484,18 +483,26 @@ class AudioMixer : Disposable { private var ambientStopped = true - fun startMusic(song: AudioBank) { + /** + * Don't call this function from the application (fixture, user-made music player mod, etc.) directly! + * Use transactions from the MusicService. + */ + internal fun startMusic(song: AudioBank) { if (musicTrack.isPlaying) { requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN) } musicTrack.nextTrack = song } - fun stopMusic() { + /** + * Don't call this function from the application (fixture, user-made music player mod, etc.) directly! + * Use transactions from the MusicService. + */ + internal fun stopMusic() { requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN) } - fun startAmb(song: AudioBank) { + internal fun startAmb(song: AudioBank) { val ambientTrack = if (!ambientTrack1.streamPlaying.get()) ambientTrack1 else if (!ambientTrack2.streamPlaying.get()) @@ -512,7 +519,7 @@ class AudioMixer : Disposable { // fade will be processed by the update() } - fun startAmb1(song: AudioBank) { + internal fun startAmb1(song: AudioBank) { if (ambientTrack1.isPlaying == true) { requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN) } @@ -520,7 +527,7 @@ class AudioMixer : Disposable { // fade will be processed by the update() } - fun startAmb2(song: AudioBank) { + internal fun startAmb2(song: AudioBank) { if (ambientTrack2.isPlaying == true) { requestFadeOut(musicTrack, DEFAULT_FADEOUT_LEN) } @@ -584,7 +591,7 @@ class AudioMixer : Disposable { } } - fun reset() { + internal fun reset() { ambientStopped = true dynamicTracks.forEach { it.stop() } guiTracks.forEach { it.stop() } diff --git a/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt b/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt index 5b52686f9..eb200721a 100644 --- a/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt +++ b/src/net/torvald/terrarum/audio/TerrarumAudioMixerTrack.kt @@ -192,7 +192,6 @@ class TerrarumAudioMixerTrack( } fireSongFinishHook() - // fireSoundFinishHook() trackingTarget = null processor.streamBuf = null diff --git a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt index e7a0aada2..962070521 100644 --- a/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt +++ b/src/net/torvald/terrarum/modulebasegame/BuildingMaker.kt @@ -62,7 +62,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) { lateinit var gameWorld: GameWorld - override val musicStreamer = TerrarumMusicStreamer() + override val musicStreamer = TerrarumMusicAndAmbientStreamer() init { gameUpdateGovernor = ConsistentUpdateRate diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt index 7dd58a447..ecb8cd5a5 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumIngame.kt @@ -262,7 +262,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) { override var gameFullyLoaded = false internal set - override val musicStreamer = TerrarumMusicStreamer() + override val musicStreamer = TerrarumMusicAndAmbientStreamer() ////////////// diff --git a/src/net/torvald/terrarum/modulebasegame/TerrarumMusicStreamer.kt b/src/net/torvald/terrarum/modulebasegame/TerrarumMusicAndAmbientStreamer.kt similarity index 89% rename from src/net/torvald/terrarum/modulebasegame/TerrarumMusicStreamer.kt rename to src/net/torvald/terrarum/modulebasegame/TerrarumMusicAndAmbientStreamer.kt index 023719d77..3fca7018c 100644 --- a/src/net/torvald/terrarum/modulebasegame/TerrarumMusicStreamer.kt +++ b/src/net/torvald/terrarum/modulebasegame/TerrarumMusicAndAmbientStreamer.kt @@ -4,14 +4,11 @@ import com.badlogic.gdx.utils.GdxRuntimeException import com.jme3.math.FastMath import net.torvald.terrarum.* import net.torvald.terrarum.App.printdbg -import net.torvald.terrarum.audio.AudioBank -import net.torvald.terrarum.audio.AudioMixer import net.torvald.terrarum.audio.audiobank.MusicContainer import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH -import java.io.File -class TerrarumMusicStreamer : MusicStreamer() { +class TerrarumMusicAndAmbientStreamer : MusicStreamer() { private val STATE_INIT = 0 private val STATE_FIREPLAY = 1 private val STATE_PLAYING = 2 @@ -19,7 +16,6 @@ class TerrarumMusicStreamer : MusicStreamer() { init { - musicState = STATE_INTERMISSION } private var playlist: List = emptyList() @@ -198,40 +194,9 @@ class TerrarumMusicStreamer : MusicStreamer() { // start the song queueing if there is one to play if (firstTime) { firstTime = false - if (playlist.isNotEmpty()) musicState = STATE_INTERMISSION if (ambients.isNotEmpty()) ambState = STATE_INTERMISSION } - when (musicState) { - STATE_FIREPLAY -> { - if (!musicFired) { - MusicService.resumePlaylistPlayback( - // onSuccess: () -> Unit - { - musicFired = true - musicState = STATE_PLAYING - }, - // onFailure: (Throwable) -> Unit - { - musicFired = false - musicState = STATE_INTERMISSION - }, - ) - } - } - STATE_PLAYING -> { - // stopMusic() will be called when the music finishes; it's on the setOnCompletionListener - } - STATE_INTERMISSION -> { - intermissionAkku += delta - - if (intermissionAkku >= intermissionLength && playlist.isNotEmpty()) { - intermissionAkku = 0f - musicState = STATE_FIREPLAY - } - } - } - val season = ingame.world.worldTime.ecologicalSeason val isAM = (ingame.world.worldTime.todaySeconds < DAY_LENGTH / 2) // 0 until DAY_LENGTH (86400) val solarElevDeg = ingame.world.worldTime.solarElevationDeg diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt index 70404d54c..8949cf19f 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureJukebox.kt @@ -19,7 +19,6 @@ import net.torvald.terrarum.gameactors.Hitbox import net.torvald.terrarum.gameactors.Lightbox import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.langpack.Lang -import net.torvald.terrarum.modulebasegame.TerrarumMusicStreamer import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase import net.torvald.terrarum.modulebasegame.gameitems.ItemFileRef import net.torvald.terrarum.modulebasegame.gameitems.MusicDiscHelper diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMusicalTurntable.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMusicalTurntable.kt index 1626753e6..f009ba61a 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMusicalTurntable.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMusicalTurntable.kt @@ -9,7 +9,6 @@ import net.torvald.terrarum.gameactors.AVKey import net.torvald.terrarum.gameitems.GameItem import net.torvald.terrarum.gameitems.ItemID import net.torvald.terrarum.langpack.Lang -import net.torvald.terrarum.modulebasegame.TerrarumMusicStreamer import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase import net.torvald.terrarum.modulebasegame.gameitems.ItemFileRef import net.torvald.terrarum.modulebasegame.gameitems.MusicDiscHelper @@ -125,7 +124,6 @@ class FixtureMusicalTurntable : Electric, PlaysMusic { MusicService.playMusicalFixture( /* action: () -> Unit */ { - App.printdbg(this, "call startAudio(${musicNowPlaying?.name})") startAudio(musicNowPlaying!!) { loadEffector(it) } }, /* musicFinished: () -> Boolean */ { @@ -151,9 +149,12 @@ class FixtureMusicalTurntable : Electric, PlaysMusic { fun stopGracefully() { stopDiscPlayback() try { - MusicService.enterIntermission() + if (musicIsPlaying) + MusicService.enterIntermission() + } + catch (e: Throwable) { + e.printStackTrace() } - catch (_: Throwable) {} } private fun stopDiscPlayback() { diff --git a/src/net/torvald/terrarum/transaction/Transaction.kt b/src/net/torvald/terrarum/transaction/Transaction.kt index f2674b23a..aac59c09e 100644 --- a/src/net/torvald/terrarum/transaction/Transaction.kt +++ b/src/net/torvald/terrarum/transaction/Transaction.kt @@ -30,7 +30,7 @@ interface Transaction { abstract class TransactionListener { /** `null` if not locked, a class that acquired the lock if locked */ - private val transactionLockingClass: AtomicReference = AtomicReference(null) + val transactionLockingClass: AtomicReference = AtomicReference(null) val transactionLocked: Boolean; get() = (transactionLockingClass.get() != null) @@ -43,9 +43,10 @@ abstract class TransactionListener { */ fun runTransaction(transaction: Transaction, onFinally: () -> Unit = {}) { printdbg(this, "Accepting transaction $transaction") - Thread { synchronized(this) { + Thread { val state = getCurrentStatusForTransaction() - if (!transactionLocked) { + val currentLock = transactionLockingClass.get() + if (currentLock == null) { transactionLockingClass.set(transaction) try { transaction.start(state) @@ -66,9 +67,9 @@ abstract class TransactionListener { } else { System.err.println("Transaction failure: locked") - transaction.onFailure(LockedException(this, transactionLockingClass.get()), state) + transaction.onFailure(LockedException(this, currentLock), state) } - } }.start() + }.start() } protected abstract fun getCurrentStatusForTransaction(): TransactionState