mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
more transaction-based music disk jockeying wip
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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,10 +82,8 @@ object MusicService : TransactionListener() {
|
||||
}
|
||||
|
||||
fun onMusicFinishing(audio: AudioBank) {
|
||||
synchronized(this) {
|
||||
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,7 +138,6 @@ object MusicService : TransactionListener() {
|
||||
|
||||
|
||||
fun enterScene(id: String) {
|
||||
synchronized(this) {
|
||||
/*val playlist = when (id) {
|
||||
"title" -> getTitlePlaylist()
|
||||
"ingame" -> getIngameDefaultPlaylist()
|
||||
@@ -150,13 +151,10 @@ object MusicService : TransactionListener() {
|
||||
|
||||
stopPlaylistPlayback { }
|
||||
}
|
||||
}
|
||||
|
||||
fun leaveScene() {
|
||||
synchronized(this) {
|
||||
stopPlaylistPlayback {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the given playlist to this object if the transaction successes. If the given playlist is same as the
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -192,7 +192,6 @@ class TerrarumAudioMixerTrack(
|
||||
}
|
||||
|
||||
fireSongFinishHook()
|
||||
// fireSoundFinishHook()
|
||||
|
||||
trackingTarget = null
|
||||
processor.streamBuf = null
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
//////////////
|
||||
|
||||
@@ -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<MusicContainer> = 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
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
if (musicIsPlaying)
|
||||
MusicService.enterIntermission()
|
||||
}
|
||||
catch (_: Throwable) {}
|
||||
catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopDiscPlayback() {
|
||||
|
||||
@@ -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<Transaction?> = AtomicReference(null)
|
||||
val transactionLockingClass: AtomicReference<Transaction?> = 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
|
||||
|
||||
Reference in New Issue
Block a user