lowpass in/out on opening menu

This commit is contained in:
minjaesong
2023-11-18 14:17:54 +09:00
parent 62c7b36a46
commit dc2f58d754
8 changed files with 115 additions and 21 deletions

View File

@@ -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()

View File

@@ -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)
}

View File

@@ -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]

View File

@@ -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 {

View File

@@ -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()
}

View File

@@ -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
}

View File

@@ -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")
}

View File

@@ -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) {