package net.torvald.terrarum.modulebasegame 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.MusicContainer import net.torvald.terrarum.gameworld.WorldTime.Companion.DAY_LENGTH class TerrarumMusicAndAmbientStreamer : MusicStreamer() { private val STATE_INTERMISSION = 0 private val STATE_FIREPLAY = 1 private val STATE_PLAYING = 2 init { } private val ambients: HashMap> = HashMap(Terrarum.audioCodex.audio.filter { it.key.startsWith("ambient.") }.map { it.key to it.value.mapNotNull { fileHandle -> try { MusicContainer( fileHandle.nameWithoutExtension().replace('_', ' ').split(" ").map { it.capitalize() }.joinToString(" "), fileHandle.file(), looping = true, ) } catch (e: GdxRuntimeException) { e.printStackTrace() null } }.toHashSet() }.toMap()) // private val musicStartHooks = ArrayList<(MusicContainer) -> Unit>() // private val musicStopHooks = ArrayList<(MusicContainer) -> Unit>() init { // TODO queue and play the default playlist // TerrarumMusicPlaylist.fromDirectory(App.defaultMusicDir, true, "intermittent") } /*fun addMusicStartHook(f: (MusicContainer) -> Unit) { musicStartHooks.add(f) } fun addMusicStopHook(f: (MusicContainer) -> Unit) { musicStopHooks.add(f) }*/ init { ambients.forEach { (k, v) -> printdbg(this, "Ambients: $k -> $v") v.forEach { App.disposables.add(it) } } } protected var ambState = 0 protected var ambFired = false fun getRandomMusicInterval() = MusicService.getRandomMusicInterval() // call MusicService to fade out // pauses playlist update // called by MusicPlayerControl /*fun stopMusicPlayback() { }*/ // resumes playlist update // called by MusicPlayerControl /*fun resumeMusicPlayback() { }*/ private fun stopAmbient() { // if (::currentAmbientTrack.isInitialized) // App.audioMixer.ambientTrack.nextTrack = currentAmbientTrack } private fun startAmbient1(song: MusicContainer) { App.audioMixer.startAmb1(song) printdbg(this, "startAmbient1 Now playing: $song") ambState = STATE_PLAYING } private fun startAmbient2(song: MusicContainer) { App.audioMixer.startAmb2(song) printdbg(this, "startAmbient2 Now playing: $song") ambState = STATE_PLAYING } private fun queueAmbientForce1(song: MusicContainer) { App.audioMixer.ambientTrack1.let { it.nextTrack = song it.stop() } printdbg(this, "startAmbient1 Now playing: $song") ambState = STATE_PLAYING } private fun queueAmbientForce2(song: MusicContainer) { App.audioMixer.ambientTrack2.let { it.nextTrack = song it.stop() } printdbg(this, "startAmbient2 Now playing: $song") ambState = STATE_PLAYING } var firstTime = true override fun update(ingame: IngameInstance, delta: Float) { val timeNow = System.currentTimeMillis() // start the song queueing if there is one to play if (firstTime) { firstTime = false if (ambients.isNotEmpty()) ambState = STATE_INTERMISSION } 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 val isSunUp = (solarElevDeg >= 0) val seasonName = when (season) { in 0f..2f -> "autumn" in 2f..3f -> "summer" in 3f..5f -> "autumn" else -> "winter" } when (ambState) { STATE_FIREPLAY -> { if (!ambFired) { ambFired = true // ambient track 1: diurnal/nocturnal // ambient track 2: crepuscular/matutinal val track1 = if (isSunUp) ambients["ambient.season.diurnal_$seasonName"]!!.random() // mad respect to Klankbeeld else ambients["ambient.season.nocturnal"]!!.random() // as it turns out ambient recordings of a wild place AT NIGHT is quite rare val track2 = if (isAM) ambients["ambient.season.matutinal"]!!.random() else ambients["ambient.season.crepuscular"]!!.random() startAmbient1(track1) startAmbient2(track2) } } STATE_PLAYING -> { // mix ambient tracks // queue up nocturnal if (!isSunUp && oldWorldSolarElev >= 0) queueAmbientForce1(ambients["ambient.season.nocturnal"]!!.random()) // as it turns out ambient recordings of a wild place AT NIGHT is quite rare // queue up diurnal else if (isSunUp && oldWorldSolarElev < 0) queueAmbientForce1(ambients["ambient.season.diurnal_$seasonName"]!!.random()) // mad respect to Klankbeeld // queue up crepuscular if (!isAM && oldWorldTime < DAY_LENGTH / 2) queueAmbientForce2(ambients["ambient.season.crepuscular"]!!.random()) else if (isAM && oldWorldTime >= DAY_LENGTH / 2) queueAmbientForce2(ambients["ambient.season.matutinal"]!!.random()) // play around the fader val track2vol = if (isAM) when (solarElevDeg) { in TRACK2_DAWN_ELEV_UP_MIN..TRACK2_DAWN_ELEV_UP_MAX -> FastMath.interpolateLinear( (solarElevDeg - TRACK2_DAWN_ELEV_UP_MIN) / (TRACK2_DAWN_ELEV_UP_MAX - TRACK2_DAWN_ELEV_UP_MIN), 1.0, 0.0 ) in TRACK2_DAWN_ELEV_DN_MAX..TRACK2_DAWN_ELEV_DN_MIN -> FastMath.interpolateLinear( (solarElevDeg - TRACK2_DAWN_ELEV_DN_MIN) / (TRACK2_DAWN_ELEV_DN_MAX - TRACK2_DAWN_ELEV_DN_MIN), 1.0, 0.0 ) in TRACK2_DAWN_ELEV_DN_MIN..TRACK2_DAWN_ELEV_UP_MIN -> 1.0 else -> 0.0 } else when (solarElevDeg) { in TRACK2_DUSK_ELEV_UP_MIN..TRACK2_DUSK_ELEV_UP_MAX -> FastMath.interpolateLinear( (solarElevDeg - TRACK2_DUSK_ELEV_UP_MIN) / (TRACK2_DUSK_ELEV_UP_MAX - TRACK2_DUSK_ELEV_UP_MIN), 1.0, 0.0 ) in TRACK2_DUSK_ELEV_DN_MAX..TRACK2_DUSK_ELEV_DN_MIN -> FastMath.interpolateLinear( (solarElevDeg - TRACK2_DUSK_ELEV_DN_MIN) / (TRACK2_DUSK_ELEV_DN_MAX - TRACK2_DUSK_ELEV_DN_MIN), 1.0, 0.0 ) in TRACK2_DUSK_ELEV_DN_MIN..TRACK2_DUSK_ELEV_UP_MIN -> 1.0 else -> 0.0 } val track1vol = 1.0 - track2vol App.audioMixer.ambientTrack1.volume = track1vol App.audioMixer.ambientTrack2.volume = track2vol } STATE_INTERMISSION -> { ambState = STATE_FIREPLAY } } oldWorldSolarElev = solarElevDeg oldWorldTime = ingame.world.worldTime.todaySeconds } private var oldWorldSolarElev = Terrarum.ingame?.world?.worldTime?.solarElevationDeg ?: 0.0 private var oldWorldTime = Terrarum.ingame?.world?.worldTime?.todaySeconds ?: 0 private val TRACK2_DUSK_ELEV_UP_MAX = 15.0 private val TRACK2_DUSK_ELEV_UP_MIN = 0.1 private val TRACK2_DUSK_ELEV_DN_MIN = -0.1 private val TRACK2_DUSK_ELEV_DN_MAX = -15.0 private val TRACK2_DAWN_ELEV_UP_MAX = 20.0 private val TRACK2_DAWN_ELEV_UP_MIN = 5.0 private val TRACK2_DAWN_ELEV_DN_MIN = 5.0 private val TRACK2_DAWN_ELEV_DN_MAX = -10.0 override fun dispose() { stopAmbient() } }