mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 12:21:52 +09:00
somewhat working?
This commit is contained in:
@@ -107,12 +107,6 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
//return App.audioMixer.dynamicTracks.any { it.isPlaying && it.trackingTarget is PlaysMusic }
|
||||
}*/
|
||||
|
||||
/** Returns the playlist name from the MusicGovernor. Getting the value from the MusicGovernor
|
||||
* is recommended as an ingame interaction may cancel the playback from the playlist from the MusicPlayer
|
||||
* (e.g. interacting with a jukebox) */
|
||||
private val internalPlaylistName: String
|
||||
get() = ingame.musicStreamer.playlistName
|
||||
|
||||
private fun registerPlaylist(path: String, fileToName: JsonValue?, shuffled: Boolean, diskJockeyingMode: String): TerrarumMusicPlaylist {
|
||||
fun String.isNum(): Boolean {
|
||||
try {
|
||||
@@ -140,7 +134,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
}
|
||||
}
|
||||
|
||||
ingame.musicStreamer.addMusicStartHook { music ->
|
||||
/*ingame.musicStreamer.addMusicStartHook { music ->
|
||||
setMusicName(music.name)
|
||||
if (mode <= MODE_PLAYING)
|
||||
transitionRequest = MODE_PLAYING
|
||||
@@ -150,7 +144,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
setIntermission()
|
||||
if (mode <= MODE_PLAYING)
|
||||
transitionRequest = MODE_IDLE
|
||||
}
|
||||
}*/
|
||||
|
||||
setPlaylistDisplayVars(playlist)
|
||||
|
||||
@@ -369,7 +363,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
}
|
||||
|
||||
2 -> { // stop
|
||||
if (mode < MODE_SHOW_LIST) { // disable stop button entirely on MODE_SHOW_LIST
|
||||
/*if (mode < MODE_SHOW_LIST) { // disable stop button entirely on MODE_SHOW_LIST
|
||||
// when the button is STOP
|
||||
if (App.audioMixer.musicTrack.isPlaying) {
|
||||
// FIXME the olde way -- must be replaced with one that utilises MusicService
|
||||
@@ -397,11 +391,10 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
stopRequested = false
|
||||
},
|
||||
/* onFailure: (Throwable) -> Unit */ {
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
3 -> { // next
|
||||
@@ -479,7 +472,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
if (index < list.size) {
|
||||
// if selected album is not the same album currently playing, queue that album immediately
|
||||
// (navigating into the selected album involves too much complication :p)
|
||||
if (ingame.musicStreamer.playlistSource != albumsList[index].canonicalPath) {
|
||||
if (MusicService.currentPlaylist?.source != albumsList[index].canonicalPath) {
|
||||
// FIXME the olde way -- must be replaced with one that utilises MusicService
|
||||
// fade out
|
||||
/*App.audioMixer.requestFadeOut(App.audioMixer.musicTrack, AudioMixer.DEFAULT_FADEOUT_LEN / 3f) {
|
||||
@@ -515,7 +508,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
private var stopRequested = false
|
||||
|
||||
private fun resetAlbumlistScroll() {
|
||||
val currentlyPlaying = albumsList.indexOfFirst { it.canonicalPath.replace('\\', '/') == ingame.musicStreamer.playlistSource }
|
||||
val currentlyPlaying = albumsList.indexOfFirst { it.canonicalPath.replace('\\', '/') == MusicService.currentPlaylist?.source }
|
||||
if (currentlyPlaying >= 0) {
|
||||
albumlistScroll = (currentlyPlaying / PLAYLIST_LINES) * PLAYLIST_LINES
|
||||
}
|
||||
@@ -933,7 +926,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
|
||||
// print the album name
|
||||
batch.color = Color(1f, 1f, 1f, alpha * 0.75f)
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, internalPlaylistName, width, x.roundToInt(), 3 + (y + PLAYLIST_LINE_HEIGHT * PLAYLIST_LINES * scale).roundToInt())
|
||||
Toolkit.drawTextCentered(batch, App.fontGame, MusicService.currentPlaylist?.name ?: "(null)", width, x.roundToInt(), 3 + (y + PLAYLIST_LINE_HEIGHT * PLAYLIST_LINES * scale).roundToInt())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -974,7 +967,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
val pnum = i + albumlistScroll
|
||||
|
||||
val currentlyPlaying = if (pnum in albumsList.indices) {
|
||||
val m1 = ingame.musicStreamer.playlistSource
|
||||
val m1 = MusicService.currentPlaylist?.source
|
||||
val m2 = albumsList[pnum].canonicalPath.replace('\\', '/')
|
||||
(m1 == m2)
|
||||
}
|
||||
@@ -1343,7 +1336,7 @@ class MusicPlayerControl(private val ingame: TerrarumIngame) : UICanvas() {
|
||||
track.doGaplessPlayback = (albumProp.diskJockeyingMode == "continuous")
|
||||
if (track.doGaplessPlayback) {
|
||||
track.pullNextTrack = {
|
||||
track.currentTrack = MusicService.currentPlaylist!!.peekNext()
|
||||
track.currentTrack = MusicService.currentPlaylist!!.queueNext()
|
||||
setMusicName(track.currentTrack?.name ?: "")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ 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.audio.audiobank.MusicContainer
|
||||
import net.torvald.terrarum.transaction.Transaction
|
||||
import net.torvald.terrarum.transaction.TransactionListener
|
||||
import net.torvald.terrarum.transaction.TransactionState
|
||||
@@ -69,12 +70,14 @@ object MusicService : TransactionListener() {
|
||||
fun getRandomMusicInterval() = 20f + Math.random().toFloat() * 4f // longer gap (20s to 24s)
|
||||
|
||||
private fun enterIntermissionAndWaitForPlaylist() {
|
||||
val time = when (currentPlaylist?.diskJockeyingMode ?: "intermittent") {
|
||||
val djmode = currentPlaylist?.diskJockeyingMode ?: "intermittent"
|
||||
val time = when (djmode) {
|
||||
"intermittent" -> getRandomMusicInterval()
|
||||
"continuous" -> 0f
|
||||
else -> getRandomMusicInterval()
|
||||
}
|
||||
enterSTATE_INTERMISSION(time)
|
||||
if (djmode == "continuous") enterSTATE_FIREPLAY()
|
||||
}
|
||||
|
||||
fun enterIntermission() {
|
||||
@@ -82,6 +85,7 @@ object MusicService : TransactionListener() {
|
||||
}
|
||||
|
||||
fun onMusicFinishing(audio: AudioBank) {
|
||||
printdbg(this, "onMusicFinishing ${audio.name}")
|
||||
enterIntermissionAndWaitForPlaylist()
|
||||
}
|
||||
|
||||
@@ -96,21 +100,27 @@ object MusicService : TransactionListener() {
|
||||
/* onSuccess: () -> Unit */
|
||||
{
|
||||
runTransaction(object : Transaction {
|
||||
private lateinit var nextMusic: MusicContainer
|
||||
|
||||
override fun start(state: TransactionState) {
|
||||
App.audioMixer.startMusic((state["currentPlaylist"] as TerrarumMusicPlaylist).getCurrent())
|
||||
nextMusic = (state["currentPlaylist"] as TerrarumMusicPlaylist).queueNext()
|
||||
App.audioMixer.startMusic(nextMusic)
|
||||
}
|
||||
|
||||
override fun onSuccess(state: TransactionState) {
|
||||
printdbg(this, "FIREPLAY started music (${nextMusic.name})")
|
||||
enterSTATE_PLAYING()
|
||||
}
|
||||
|
||||
override fun onFailure(e: Throwable, state: TransactionState) {
|
||||
printdbg(this, "FIREPLAY resume OK but startMusic failed, entering intermission")
|
||||
enterSTATE_INTERMISSION(getRandomMusicInterval()) // will try again after a random interval
|
||||
}
|
||||
})
|
||||
},
|
||||
/* onFailure: (Throwable) -> Unit */
|
||||
{
|
||||
printdbg(this, "FIREPLAY resume failed, entering intermission")
|
||||
enterSTATE_INTERMISSION(getRandomMusicInterval()) // will try again after a random interval
|
||||
},
|
||||
// onFinally: () -> Unit
|
||||
@@ -120,7 +130,7 @@ object MusicService : TransactionListener() {
|
||||
)
|
||||
}
|
||||
else {
|
||||
println("PLAYing is deferred: playTransaction is ongoing")
|
||||
printdbg(this, "FIREPLAY no-op: playTransaction is ongoing")
|
||||
}
|
||||
}
|
||||
STATE_PLAYING -> {
|
||||
@@ -168,11 +178,9 @@ object MusicService : TransactionListener() {
|
||||
* The old playlist will be disposed of if and only if the transaction was successful.
|
||||
*
|
||||
* @param playlist An instance of a [TerrarumMusicPlaylist] to be changed into
|
||||
* @param onSuccess What to do after the transaction. Default behaviour is: `App.audioMixer.startMusic(playlist.getCurrent())`
|
||||
* @param onSuccess What to do after the transaction
|
||||
*/
|
||||
private fun createTransactionPlaylistChange(playlist: TerrarumMusicPlaylist, onSuccess: () -> Unit = {
|
||||
App.audioMixer.startMusic(playlist.getCurrent())
|
||||
}): Transaction {
|
||||
private fun createTransactionPlaylistChange(playlist: TerrarumMusicPlaylist, onSuccess: () -> Unit): Transaction {
|
||||
return object : Transaction {
|
||||
var oldPlaylist: TerrarumMusicPlaylist? = null
|
||||
|
||||
@@ -413,7 +421,7 @@ object MusicService : TransactionListener() {
|
||||
if (onSuccess != null)
|
||||
runTransaction(createTransactionPlaylistChange(playlist, onSuccess))
|
||||
else
|
||||
runTransaction(createTransactionPlaylistChange(playlist))
|
||||
runTransaction(createTransactionPlaylistChange(playlist, {}))
|
||||
}
|
||||
fun putNewPlaylist(playlist: TerrarumMusicPlaylist, onSuccess: () -> Unit, onFinally: () -> Unit) {
|
||||
runTransaction(createTransactionPlaylistChange(playlist, onSuccess), onFinally)
|
||||
|
||||
@@ -40,7 +40,7 @@ class TerrarumMusicPlaylist(
|
||||
}
|
||||
|
||||
private fun checkRefill() {
|
||||
if (internalIndices.size < currentIndexCursor + 1)
|
||||
if (currentIndexCursor >= internalIndices.size - 2)
|
||||
refillInternalIndices()
|
||||
}
|
||||
|
||||
@@ -50,19 +50,14 @@ class TerrarumMusicPlaylist(
|
||||
return musicList[internalIndices[currentIndexCursor]]
|
||||
}
|
||||
|
||||
fun getNext(): MusicContainer {
|
||||
fun queueNext(): MusicContainer {
|
||||
checkRefill()
|
||||
currentIndexCursor += 1
|
||||
|
||||
return musicList[internalIndices[currentIndexCursor]]
|
||||
}
|
||||
|
||||
fun peekNext(): MusicContainer {
|
||||
checkRefill()
|
||||
return musicList[internalIndices[currentIndexCursor + 1]]
|
||||
}
|
||||
|
||||
fun getPrev(): MusicContainer {
|
||||
fun queuePrev(): MusicContainer {
|
||||
if (currentIndexCursor == 0) {
|
||||
if (shuffled) {
|
||||
musicList.indices.toMutableList().also { if (shuffled) it.shuffle() }.reversed().forEach {
|
||||
@@ -83,12 +78,21 @@ class TerrarumMusicPlaylist(
|
||||
return musicList[internalIndices[currentIndexCursor]]
|
||||
}
|
||||
|
||||
|
||||
private fun refillInternalIndices() {
|
||||
internalIndices.addAll(musicList.indices.toMutableList().also { if (shuffled) it.shuffle() })
|
||||
fun queueNthSong(n: Int): MusicContainer {
|
||||
checkRefill()
|
||||
internalIndices.add(currentIndexCursor, n)
|
||||
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() })
|
||||
}
|
||||
}
|
||||
|
||||
inline fun getNthSong(n: Int) = musicList[n]
|
||||
|
||||
override fun dispose() {
|
||||
musicList.forEach {
|
||||
|
||||
@@ -9,82 +9,14 @@ import net.torvald.terrarum.audio.audiobank.MusicContainer
|
||||
import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH
|
||||
|
||||
class TerrarumMusicAndAmbientStreamer : MusicStreamer() {
|
||||
private val STATE_INIT = 0
|
||||
private val STATE_INTERMISSION = 0
|
||||
private val STATE_FIREPLAY = 1
|
||||
private val STATE_PLAYING = 2
|
||||
private val STATE_INTERMISSION = 3
|
||||
|
||||
|
||||
init {
|
||||
}
|
||||
|
||||
private var playlist: List<MusicContainer> = emptyList()
|
||||
var playlistName = ""; private set
|
||||
/** canonicalPath with path separators converted to forward slash */
|
||||
var playlistSource = "" ; private set
|
||||
private var musicBin: ArrayList<MusicContainer> = ArrayList()
|
||||
private var shuffled = true
|
||||
private var diskJockeyingMode = "intermittent" // intermittent, continuous
|
||||
|
||||
|
||||
|
||||
private fun restockMusicBin() {
|
||||
musicBin = ArrayList(if (shuffled) playlist.shuffled() else playlist.slice(playlist.indices))
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a song to the head of the internal playlist (`musicBin`)
|
||||
*/
|
||||
fun xxxqueueMusicToPlayNext(music: MusicContainer) {
|
||||
musicBin.add(0, music)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshifts an internal playlist (`musicBin`). The `music` argument must be the song that exists on the `songs`.
|
||||
*/
|
||||
fun xxxunshiftPlaylist(music: MusicContainer) {
|
||||
val indexAtMusicBin = playlist.indexOf(music)
|
||||
if (indexAtMusicBin < 0) throw IllegalArgumentException("The music does not exist on the internal songs list ($music)")
|
||||
|
||||
// rewrite musicBin
|
||||
val newMusicBin = if (shuffled) playlist.shuffled().toTypedArray().also {
|
||||
// if shuffled,
|
||||
// 1. create a shuffled version of songlist
|
||||
// 2. swap two songs such that the songs[indexAtMusicBin] comes first
|
||||
val swapTo = it.indexOf(playlist[indexAtMusicBin])
|
||||
val tmp = it[swapTo]
|
||||
it[swapTo] = it[0]
|
||||
it[0] = tmp
|
||||
}
|
||||
else Array(playlist.size - indexAtMusicBin) { offset ->
|
||||
val k = offset + indexAtMusicBin
|
||||
playlist[k]
|
||||
}
|
||||
|
||||
musicBin = ArrayList(newMusicBin.toList())
|
||||
}
|
||||
|
||||
fun xxxqueueIndexFromPlaylist(indexAtMusicBin: Int) {
|
||||
if (indexAtMusicBin !in playlist.indices) throw IndexOutOfBoundsException("The index is outside of the internal songs list ($indexAtMusicBin/${playlist.size})")
|
||||
|
||||
// rewrite musicBin
|
||||
val newMusicBin = if (shuffled) playlist.shuffled().toTypedArray().also {
|
||||
// if shuffled,
|
||||
// 1. create a shuffled version of songlist
|
||||
// 2. swap two songs such that the songs[indexAtMusicBin] comes first
|
||||
val swapTo = it.indexOf(playlist[indexAtMusicBin])
|
||||
val tmp = it[swapTo]
|
||||
it[swapTo] = it[0]
|
||||
it[0] = tmp
|
||||
}
|
||||
else Array(playlist.size - indexAtMusicBin) { offset ->
|
||||
val k = offset + indexAtMusicBin
|
||||
playlist[k]
|
||||
}
|
||||
|
||||
musicBin = ArrayList(newMusicBin.toList())
|
||||
}
|
||||
|
||||
private val ambients: HashMap<String, HashSet<MusicContainer>> =
|
||||
HashMap(Terrarum.audioCodex.audio.filter { it.key.startsWith("ambient.") }.map { it.key to it.value.mapNotNull { fileHandle ->
|
||||
try {
|
||||
@@ -100,8 +32,8 @@ class TerrarumMusicAndAmbientStreamer : MusicStreamer() {
|
||||
}
|
||||
}.toHashSet() }.toMap())
|
||||
|
||||
private val musicStartHooks = ArrayList<(MusicContainer) -> Unit>()
|
||||
private val musicStopHooks = ArrayList<(MusicContainer) -> Unit>()
|
||||
// private val musicStartHooks = ArrayList<(MusicContainer) -> Unit>()
|
||||
// private val musicStopHooks = ArrayList<(MusicContainer) -> Unit>()
|
||||
|
||||
init {
|
||||
// TODO queue and play the default playlist
|
||||
@@ -109,18 +41,15 @@ class TerrarumMusicAndAmbientStreamer : MusicStreamer() {
|
||||
}
|
||||
|
||||
|
||||
fun addMusicStartHook(f: (MusicContainer) -> Unit) {
|
||||
/*fun addMusicStartHook(f: (MusicContainer) -> Unit) {
|
||||
musicStartHooks.add(f)
|
||||
}
|
||||
|
||||
fun addMusicStopHook(f: (MusicContainer) -> Unit) {
|
||||
musicStopHooks.add(f)
|
||||
}
|
||||
}*/
|
||||
|
||||
init {
|
||||
playlist.forEach {
|
||||
App.disposables.add(it)
|
||||
}
|
||||
ambients.forEach { (k, v) ->
|
||||
printdbg(this, "Ambients: $k -> $v")
|
||||
|
||||
@@ -131,9 +60,6 @@ class TerrarumMusicAndAmbientStreamer : MusicStreamer() {
|
||||
}
|
||||
|
||||
|
||||
private var warningPrinted = false
|
||||
|
||||
|
||||
|
||||
protected var ambState = 0
|
||||
protected var ambFired = false
|
||||
@@ -143,15 +69,15 @@ class TerrarumMusicAndAmbientStreamer : MusicStreamer() {
|
||||
// call MusicService to fade out
|
||||
// pauses playlist update
|
||||
// called by MusicPlayerControl
|
||||
fun stopMusicPlayback() {
|
||||
/*fun stopMusicPlayback() {
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
// resumes playlist update
|
||||
// called by MusicPlayerControl
|
||||
fun resumeMusicPlayback() {
|
||||
/*fun resumeMusicPlayback() {
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
private fun stopAmbient() {
|
||||
// if (::currentAmbientTrack.isInitialized)
|
||||
|
||||
@@ -76,8 +76,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(listener: TransactionListener, lockedBy: Transaction) :
|
||||
Exception("Transaction is rejected because the class '${listener.javaClass.canonicalName}' is locked by '${lockedBy.javaClass.canonicalName}'")
|
||||
|
||||
@JvmInline value class TransactionState(val valueTable: HashMap<String, Any?>) {
|
||||
operator fun get(key: String) = valueTable[key]
|
||||
|
||||
Reference in New Issue
Block a user