mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
lowpass in/out on opening menu
This commit is contained in:
@@ -3,9 +3,15 @@ package net.torvald.terrarum.audio
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.lwjgl3.audio.Lwjgl3Audio
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.App
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATED
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATEF
|
||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||
import net.torvald.terrarum.tryDispose
|
||||
import kotlin.math.log
|
||||
import kotlin.math.log10
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* Any audio reference fed into this manager will get lost; you must manually store and dispose of them on your own.
|
||||
@@ -28,24 +34,36 @@ object AudioMixer: Disposable {
|
||||
get() = (App.getConfigDouble("sfxvolume") * App.getConfigDouble("mastervolume"))
|
||||
|
||||
|
||||
private val tracks = Array(10) { TerrarumAudioMixerTrack("Audio Track #${it+1}") }
|
||||
val tracks = Array(10) { TerrarumAudioMixerTrack(
|
||||
if (it == 0) "BGM Track"
|
||||
else if (it == 1) "AMB Track"
|
||||
else "Audio Track #${it+1}"
|
||||
) }
|
||||
|
||||
private val masterTrack = TerrarumAudioMixerTrack("Master", true).also { master ->
|
||||
val masterTrack = TerrarumAudioMixerTrack("Master", true).also { master ->
|
||||
tracks.forEach { master.addSidechainInput(it, 1.0) }
|
||||
master.filters[0] = Lowpass(48000, TerrarumAudioMixerTrack.SAMPLING_RATE)
|
||||
}
|
||||
|
||||
private val musicTrack: TerrarumAudioMixerTrack
|
||||
val musicTrack: TerrarumAudioMixerTrack
|
||||
get() = tracks[0]
|
||||
private val ambientTrack: TerrarumAudioMixerTrack
|
||||
val ambientTrack: TerrarumAudioMixerTrack
|
||||
get() = tracks[1]
|
||||
|
||||
init {
|
||||
musicTrack.filters[0] = Lowpass(48000f, TerrarumAudioMixerTrack.SAMPLING_RATE)
|
||||
ambientTrack.filters[0] = Lowpass(48000f, TerrarumAudioMixerTrack.SAMPLING_RATE)
|
||||
}
|
||||
|
||||
private var fadeAkku = 0.0
|
||||
private var fadeLength = DEFAULT_FADEOUT_LEN
|
||||
|
||||
private var fadeoutFired = false
|
||||
private var fadeinFired = false
|
||||
|
||||
private var lpAkku = 0.0
|
||||
private var lpLength = 0.4
|
||||
private var lpOutFired = false
|
||||
private var lpInFired = false
|
||||
|
||||
// TODO make sidechaining work
|
||||
// TODO master volume controls the master track
|
||||
// TODO fadein/out controls the master track
|
||||
@@ -58,34 +76,51 @@ object AudioMixer: Disposable {
|
||||
fadeAkku += delta
|
||||
musicTrack.volume = (musicVolume * (1.0 - (fadeAkku / fadeLength))).coerceIn(0.0, 1.0)
|
||||
|
||||
// printdbg(this, "Fadeout fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
||||
|
||||
if (fadeAkku >= fadeLength) {
|
||||
fadeoutFired = false
|
||||
musicTrack.volume = 0.0
|
||||
// currentMusic?.gdxMusic?.pause()
|
||||
musicTrack.currentTrack = null
|
||||
|
||||
// printdbg(this, "Fadeout end")
|
||||
}
|
||||
}
|
||||
// process fadein request
|
||||
else if (fadeinFired) {
|
||||
fadeAkku += delta
|
||||
musicTrack.volume = (musicVolume * (fadeAkku / fadeLength)).coerceIn(0.0, 1.0)
|
||||
|
||||
// printdbg(this, "Fadein fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
||||
|
||||
if (musicTrack.isPlaying == false) {
|
||||
musicTrack.play()
|
||||
// printdbg(this, "Fadein starting music ${currentMusic?.name}")
|
||||
}
|
||||
|
||||
if (fadeAkku >= fadeLength) {
|
||||
musicTrack.volume = musicVolume
|
||||
fadeinFired = false
|
||||
}
|
||||
}
|
||||
|
||||
// printdbg(this, "Fadein end")
|
||||
|
||||
if (lpOutFired) {
|
||||
lpAkku += delta
|
||||
val x = (lpAkku / lpLength).coerceIn(0.0, 1.0)
|
||||
val q = 400.0
|
||||
val step = (q.pow(x) - 1) / (q - 1) // https://www.desmos.com/calculator/sttaq2qhzm
|
||||
val cutoff = FastMath.interpolateLinear(step, SAMPLING_RATED / 100.0, SAMPLING_RATED)
|
||||
(musicTrack.filters[0] as Lowpass).setCutoff(cutoff)
|
||||
|
||||
if (lpAkku >= lpLength) {
|
||||
lpOutFired = false
|
||||
(musicTrack.filters[0] as Lowpass).setCutoff(SAMPLING_RATEF)
|
||||
}
|
||||
}
|
||||
else if (lpInFired) {
|
||||
lpAkku += delta
|
||||
val x = (lpAkku / lpLength).coerceIn(0.0, 1.0)
|
||||
val q = 400.0
|
||||
val step = log((q-1) * x + 1.0, q) // https://www.desmos.com/calculator/sttaq2qhzm
|
||||
val cutoff = FastMath.interpolateLinear(step, SAMPLING_RATED, SAMPLING_RATED / 100.0)
|
||||
(musicTrack.filters[0] as Lowpass).setCutoff(cutoff)
|
||||
|
||||
if (lpAkku >= lpLength) {
|
||||
(musicTrack.filters[0] as Lowpass).setCutoff(SAMPLING_RATEF / 100.0)
|
||||
lpInFired = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,6 +161,23 @@ object AudioMixer: Disposable {
|
||||
}
|
||||
|
||||
|
||||
fun requestLowpassOut(length: Double) {
|
||||
if (!lpOutFired) {
|
||||
lpLength = length.coerceAtLeast(1.0/1024.0)
|
||||
lpAkku = 0.0
|
||||
lpOutFired = true
|
||||
}
|
||||
}
|
||||
|
||||
fun requestLowpassIn(length: Double) {
|
||||
if (!lpInFired) {
|
||||
lpLength = length.coerceAtLeast(1.0/1024.0)
|
||||
lpAkku = 0.0
|
||||
lpInFired = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun dispose() {
|
||||
tracks.forEach { it.tryDispose() }
|
||||
masterTrack.tryDispose()
|
||||
|
||||
@@ -9,6 +9,10 @@ import kotlin.math.absoluteValue
|
||||
* Created by minjaesong on 2023-11-17.
|
||||
*/
|
||||
class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: TerrarumAudioMixerTrack): Runnable {
|
||||
|
||||
val BACK_BUF_COUNT = 2
|
||||
|
||||
|
||||
@Volatile private var running = true
|
||||
@Volatile private var paused = false
|
||||
private val pauseLock = java.lang.Object()
|
||||
@@ -163,7 +167,7 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
|
||||
if (samplesL0 != null && samplesL1 != null && samplesR0 != null && samplesR1 != null) {
|
||||
|
||||
// spin until queue is sufficiently empty
|
||||
while (track.pcmQueue.size >= 4 && running) {
|
||||
while (track.pcmQueue.size >= BACK_BUF_COUNT && running) {
|
||||
Thread.sleep(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,15 +24,27 @@ object NullFilter: TerrarumAudioFilter() {
|
||||
}
|
||||
|
||||
|
||||
class Lowpass(cutoff: Int, rate: Int): TerrarumAudioFilter() {
|
||||
class Lowpass(cutoff: Float, val rate: Int): TerrarumAudioFilter() {
|
||||
|
||||
val alpha: Float
|
||||
private var alpha: Float = 0f
|
||||
init {
|
||||
val RC: Float = 1f / (cutoff.toFloat() * FastMath.TWO_PI)
|
||||
setCutoff(cutoff)
|
||||
}
|
||||
|
||||
fun setCutoff(cutoff: Float) {
|
||||
// println("LP Cutoff: $cutoff")
|
||||
val RC: Float = 1f / (cutoff * FastMath.TWO_PI)
|
||||
val dt: Float = 1f / rate
|
||||
alpha = dt / (RC + dt)
|
||||
}
|
||||
|
||||
fun setCutoff(cutoff: Double) {
|
||||
// println("LP Cutoff: $cutoff")
|
||||
val RC: Double = 1.0 / (cutoff * Math.PI * 2.0)
|
||||
val dt: Double = 1.0 / rate
|
||||
alpha = (dt / (RC + dt)).toFloat()
|
||||
}
|
||||
|
||||
override fun thru(inbuf0: List<FloatArray>, inbuf1: List<FloatArray>, outbuf0: List<FloatArray>, outbuf1: List<FloatArray>) {
|
||||
for (ch in outbuf1.indices) {
|
||||
val out = outbuf1[ch]
|
||||
|
||||
@@ -16,6 +16,8 @@ class TerrarumAudioMixerTrack(val name: String, val isMaster: Boolean = false):
|
||||
|
||||
companion object {
|
||||
const val SAMPLING_RATE = 48000
|
||||
const val SAMPLING_RATEF = 48000f
|
||||
const val SAMPLING_RATED = 48000.0
|
||||
}
|
||||
|
||||
val hash = getHashStr()
|
||||
@@ -123,7 +125,7 @@ class TerrarumAudioMixerTrack(val name: String, val isMaster: Boolean = false):
|
||||
|
||||
// 1st ring of the hell: the THREADING HELL //
|
||||
|
||||
val BUFFER_SIZE = 16384
|
||||
val BUFFER_SIZE = 6000
|
||||
|
||||
internal var processor = MixerTrackProcessor(BUFFER_SIZE, SAMPLING_RATE, this)
|
||||
private val processorThread = Thread(processor).also {
|
||||
|
||||
@@ -7,6 +7,9 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.Lowpass
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.blockproperties.Block
|
||||
import net.torvald.terrarum.blockproperties.BlockPropUtil
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
@@ -299,6 +302,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
override fun show() {
|
||||
Gdx.input.inputProcessor = BuildingMakerController(this)
|
||||
(AudioMixer.musicTrack.filters[0] as Lowpass).setCutoff(TerrarumAudioMixerTrack.SAMPLING_RATEF)
|
||||
super.show()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ import net.torvald.terrarum.Terrarum.getPlayerSaveFiledesc
|
||||
import net.torvald.terrarum.Terrarum.getWorldSaveFiledesc
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.Lowpass
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.blockproperties.BlockPropUtil
|
||||
import net.torvald.terrarum.blockstats.MinimapComposer
|
||||
import net.torvald.terrarum.blockstats.TileSurvey
|
||||
@@ -288,6 +291,8 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
IngameRenderer.setRenderedWorld(world)
|
||||
blockMarkingActor.isVisible = true
|
||||
|
||||
(AudioMixer.musicTrack.filters[0] as Lowpass).setCutoff(TerrarumAudioMixerTrack.SAMPLING_RATEF)
|
||||
|
||||
super.show() // this function sets gameInitialised = true
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ import net.torvald.terrarum.App.printdbgerr
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.Lowpass
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.clut.Skybox
|
||||
import net.torvald.terrarum.console.CommandDict
|
||||
import net.torvald.terrarum.gameactors.*
|
||||
@@ -293,6 +296,9 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
UILoadGovernor.reset()
|
||||
|
||||
|
||||
(AudioMixer.musicTrack.filters[0] as Lowpass).setCutoff(TerrarumAudioMixerTrack.SAMPLING_RATEF)
|
||||
|
||||
|
||||
loadThingsWhileIntroIsVisible()
|
||||
printdbg(this, "show() exit")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,11 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.App.*
|
||||
import net.torvald.terrarum.audio.AudioMixer
|
||||
import net.torvald.terrarum.audio.Lowpass
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATE
|
||||
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATEF
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
@@ -15,6 +20,7 @@ import net.torvald.terrarum.ui.UIHandler
|
||||
import net.torvald.terrarum.ui.UIItemHorizontalFadeSlide
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import net.torvald.unicode.*
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-10-21.
|
||||
@@ -358,6 +364,8 @@ class UIInventoryFull(
|
||||
transitionPanel.uis.forEach { it.opacity = FastMath.pow(opacity, 0.5f) }
|
||||
INGAME.pause()
|
||||
INGAME.setTooltipMessage(null)
|
||||
|
||||
AudioMixer.requestLowpassIn(0.4)
|
||||
}
|
||||
|
||||
override fun doClosing(delta: Float) {
|
||||
@@ -366,6 +374,7 @@ class UIInventoryFull(
|
||||
INGAME.resume()
|
||||
INGAME.setTooltipMessage(null)
|
||||
|
||||
AudioMixer.requestLowpassOut(0.4)
|
||||
}
|
||||
|
||||
override fun endOpening(delta: Float) {
|
||||
|
||||
Reference in New Issue
Block a user