mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 19:44:05 +09:00
audio mixer thingy wip
This commit is contained in:
@@ -2,7 +2,6 @@ package net.torvald.terrarum;
|
|||||||
|
|
||||||
import com.badlogic.gdx.*;
|
import com.badlogic.gdx.*;
|
||||||
import com.badlogic.gdx.audio.AudioDevice;
|
import com.badlogic.gdx.audio.AudioDevice;
|
||||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
|
||||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||||
import com.badlogic.gdx.backends.lwjgl3.TerrarumLwjgl3Application;
|
import com.badlogic.gdx.backends.lwjgl3.TerrarumLwjgl3Application;
|
||||||
import com.badlogic.gdx.controllers.Controllers;
|
import com.badlogic.gdx.controllers.Controllers;
|
||||||
@@ -16,6 +15,7 @@ import com.badlogic.gdx.utils.JsonValue;
|
|||||||
import com.github.strikerx3.jxinput.XInputDevice;
|
import com.github.strikerx3.jxinput.XInputDevice;
|
||||||
import kotlin.text.Charsets;
|
import kotlin.text.Charsets;
|
||||||
import net.torvald.getcpuname.GetCpuName;
|
import net.torvald.getcpuname.GetCpuName;
|
||||||
|
import net.torvald.terrarum.audio.AudioMixer;
|
||||||
import net.torvald.terrarum.controller.GdxControllerAdapter;
|
import net.torvald.terrarum.controller.GdxControllerAdapter;
|
||||||
import net.torvald.terrarum.controller.TerrarumController;
|
import net.torvald.terrarum.controller.TerrarumController;
|
||||||
import net.torvald.terrarum.controller.XinputControllerAdapter;
|
import net.torvald.terrarum.controller.XinputControllerAdapter;
|
||||||
@@ -1188,7 +1188,7 @@ public class App implements ApplicationListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioManager.INSTANCE.getMasterVolume();
|
AudioMixer.INSTANCE.getMasterVolume();
|
||||||
audioManagerThread = new Thread(new AudioManagerRunnable(), "TerrarumAudioManager");
|
audioManagerThread = new Thread(new AudioManagerRunnable(), "TerrarumAudioManager");
|
||||||
audioManagerThread.start();
|
audioManagerThread.start();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package net.torvald.terrarum
|
package net.torvald.terrarum
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx
|
import net.torvald.terrarum.audio.AudioMixer
|
||||||
import net.torvald.terrarum.gamecontroller.InputStrober
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2023-11-08.
|
* Created by minjaesong on 2023-11-08.
|
||||||
@@ -17,7 +16,7 @@ class AudioManagerRunnable : Runnable {
|
|||||||
val T = System.nanoTime()
|
val T = System.nanoTime()
|
||||||
dT = (T - oldT) / 1000000000f
|
dT = (T - oldT) / 1000000000f
|
||||||
oldT = T;
|
oldT = T;
|
||||||
AudioManager.update(dT)
|
AudioMixer.update(dT)
|
||||||
// println("AudioManagerRunnable dT = ${dT * 1000f} ms")
|
// println("AudioManagerRunnable dT = ${dT * 1000f} ms")
|
||||||
Thread.sleep(30L)
|
Thread.sleep(30L)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package net.torvald.terrarum
|
package net.torvald.terrarum.audio
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.backends.lwjgl3.audio.Lwjgl3Audio
|
import com.badlogic.gdx.backends.lwjgl3.audio.Lwjgl3Audio
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App
|
||||||
import net.torvald.terrarum.modulebasegame.MusicContainer
|
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,48 +10,58 @@ import net.torvald.terrarum.modulebasegame.MusicContainer
|
|||||||
*
|
*
|
||||||
* Created by minjaesong on 2023-11-07.
|
* Created by minjaesong on 2023-11-07.
|
||||||
*/
|
*/
|
||||||
object AudioManager {
|
object AudioMixer {
|
||||||
const val DEFAULT_FADEOUT_LEN = 2.4f
|
const val DEFAULT_FADEOUT_LEN = 2.4
|
||||||
|
|
||||||
/** Returns a master volume */
|
/** Returns a master volume */
|
||||||
val masterVolume: Float
|
val masterVolume: Double
|
||||||
get() = App.getConfigDouble("mastervolume").toFloat()
|
get() = App.getConfigDouble("mastervolume")
|
||||||
|
|
||||||
/** Returns a (master volume * bgm volume) */
|
/** Returns a (master volume * bgm volume) */
|
||||||
val musicVolume: Float
|
val musicVolume: Double
|
||||||
get() = (App.getConfigDouble("bgmvolume") * App.getConfigDouble("mastervolume")).toFloat()
|
get() = (App.getConfigDouble("bgmvolume") * App.getConfigDouble("mastervolume"))
|
||||||
|
|
||||||
/** Returns a (master volume * sfx volume */
|
/** Returns a (master volume * sfx volume */
|
||||||
val ambientVolume: Float
|
val ambientVolume: Double
|
||||||
get() = (App.getConfigDouble("sfxvolume") * App.getConfigDouble("mastervolume")).toFloat()
|
get() = (App.getConfigDouble("sfxvolume") * App.getConfigDouble("mastervolume"))
|
||||||
|
|
||||||
|
|
||||||
var currentMusic: MusicContainer? = null
|
private val tracks = Array(10) { TerrarumAudioMixerTracks() }
|
||||||
var currentAmbient: MusicContainer? = null
|
|
||||||
|
|
||||||
private var nextMusic: MusicContainer? = null
|
private val masterTrack = TerrarumAudioMixerTracks().also { master ->
|
||||||
|
tracks.forEach { master.sidechainInputs.add(it to 1.0) }
|
||||||
|
}
|
||||||
|
|
||||||
private var fadeAkku = 0f
|
private val musicTrack: TerrarumAudioMixerTracks
|
||||||
|
get() = tracks[0]
|
||||||
|
private val ambientTrack: TerrarumAudioMixerTracks
|
||||||
|
get() = tracks[1]
|
||||||
|
|
||||||
|
private var fadeAkku = 0.0
|
||||||
private var fadeLength = DEFAULT_FADEOUT_LEN
|
private var fadeLength = DEFAULT_FADEOUT_LEN
|
||||||
|
|
||||||
private var fadeoutFired = false
|
private var fadeoutFired = false
|
||||||
private var fadeinFired = false
|
private var fadeinFired = false
|
||||||
|
|
||||||
|
// TODO make sidechaining work
|
||||||
|
// TODO master volume controls the master track
|
||||||
|
// TODO fadein/out controls the master track
|
||||||
|
|
||||||
fun update(delta: Float) {
|
fun update(delta: Float) {
|
||||||
(Gdx.audio as? Lwjgl3Audio)?.update()
|
(Gdx.audio as? Lwjgl3Audio)?.update()
|
||||||
|
|
||||||
|
|
||||||
if (fadeoutFired) {
|
if (fadeoutFired) {
|
||||||
fadeAkku += delta
|
fadeAkku += delta
|
||||||
currentMusic?.gdxMusic?.volume = (musicVolume * (1f - (fadeAkku / fadeLength))).coerceIn(0f, 1f)
|
musicTrack.volume = (musicVolume * (1.0 - (fadeAkku / fadeLength))).coerceIn(0.0, 1.0)
|
||||||
|
|
||||||
// printdbg(this, "Fadeout fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
// printdbg(this, "Fadeout fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
||||||
|
|
||||||
if (fadeAkku >= fadeLength) {
|
if (fadeAkku >= fadeLength) {
|
||||||
fadeoutFired = false
|
fadeoutFired = false
|
||||||
currentMusic?.gdxMusic?.volume = 0f
|
musicTrack.volume = 0.0
|
||||||
// currentMusic?.gdxMusic?.pause()
|
// currentMusic?.gdxMusic?.pause()
|
||||||
currentMusic = null
|
musicTrack.currentTrack = null
|
||||||
|
|
||||||
// printdbg(this, "Fadeout end")
|
// printdbg(this, "Fadeout end")
|
||||||
}
|
}
|
||||||
@@ -59,17 +69,17 @@ object AudioManager {
|
|||||||
// process fadein request
|
// process fadein request
|
||||||
else if (fadeinFired) {
|
else if (fadeinFired) {
|
||||||
fadeAkku += delta
|
fadeAkku += delta
|
||||||
currentMusic?.gdxMusic?.volume = (musicVolume * (fadeAkku / fadeLength)).coerceIn(0f, 1f)
|
musicTrack.volume = (musicVolume * (fadeAkku / fadeLength)).coerceIn(0.0, 1.0)
|
||||||
|
|
||||||
// printdbg(this, "Fadein fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
// printdbg(this, "Fadein fired - akku: $fadeAkku; volume: ${currentMusic?.gdxMusic?.volume}")
|
||||||
|
|
||||||
if (currentMusic?.gdxMusic?.isPlaying == false) {
|
if (musicTrack.isPlaying == false) {
|
||||||
currentMusic?.gdxMusic?.play()
|
musicTrack.play()
|
||||||
// printdbg(this, "Fadein starting music ${currentMusic?.name}")
|
// printdbg(this, "Fadein starting music ${currentMusic?.name}")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fadeAkku >= fadeLength) {
|
if (fadeAkku >= fadeLength) {
|
||||||
currentMusic?.gdxMusic?.volume = musicVolume
|
musicTrack.volume = musicVolume
|
||||||
fadeinFired = false
|
fadeinFired = false
|
||||||
|
|
||||||
// printdbg(this, "Fadein end")
|
// printdbg(this, "Fadein end")
|
||||||
@@ -77,38 +87,37 @@ object AudioManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (currentMusic?.gdxMusic?.isPlaying != true && nextMusic != null) {
|
if (musicTrack.isPlaying != true && musicTrack.nextTrack != null) {
|
||||||
// printdbg(this, "Playing next music: ${nextMusic!!.name}")
|
// printdbg(this, "Playing next music: ${nextMusic!!.name}")
|
||||||
currentMusic = nextMusic
|
musicTrack.queueNext(null)
|
||||||
nextMusic = null
|
musicTrack.volume = musicVolume
|
||||||
currentMusic!!.gdxMusic.volume = musicVolume
|
musicTrack.play()
|
||||||
currentMusic!!.gdxMusic.play()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startMusic(song: MusicContainer) {
|
fun startMusic(song: MusicContainer) {
|
||||||
if (currentMusic?.gdxMusic?.isPlaying == true) {
|
if (musicTrack.isPlaying == true) {
|
||||||
requestFadeOut(DEFAULT_FADEOUT_LEN)
|
requestFadeOut(DEFAULT_FADEOUT_LEN)
|
||||||
}
|
}
|
||||||
nextMusic = song
|
musicTrack.nextTrack = song
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopMusic() {
|
fun stopMusic() {
|
||||||
requestFadeOut(DEFAULT_FADEOUT_LEN)
|
requestFadeOut(DEFAULT_FADEOUT_LEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestFadeOut(length: Float) {
|
fun requestFadeOut(length: Double) {
|
||||||
if (!fadeoutFired) {
|
if (!fadeoutFired) {
|
||||||
fadeLength = length.coerceAtLeast(1f/1024f)
|
fadeLength = length.coerceAtLeast(1.0/1024.0)
|
||||||
fadeAkku = 0f
|
fadeAkku = 0.0
|
||||||
fadeoutFired = true
|
fadeoutFired = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun requestFadeIn(length: Float) {
|
fun requestFadeIn(length: Double) {
|
||||||
if (!fadeinFired) {
|
if (!fadeinFired) {
|
||||||
fadeLength = length.coerceAtLeast(1f/1024f)
|
fadeLength = length.coerceAtLeast(1.0/1024.0)
|
||||||
fadeAkku = 0f
|
fadeAkku = 0.0
|
||||||
fadeinFired = true
|
fadeinFired = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
12
src/net/torvald/terrarum/audio/TerrarumAudioFilters.kt
Normal file
12
src/net/torvald/terrarum/audio/TerrarumAudioFilters.kt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package net.torvald.terrarum.audio
|
||||||
|
|
||||||
|
interface TerrarumAudioFilters {
|
||||||
|
fun thru(inbufL: FloatArray, inbufR: FloatArray, outbufL: FloatArray, outbufR: FloatArray)
|
||||||
|
}
|
||||||
|
|
||||||
|
object NullFilter: TerrarumAudioFilters {
|
||||||
|
override fun thru(inbufL: FloatArray, inbufR: FloatArray, outbufL: FloatArray, outbufR: FloatArray) {
|
||||||
|
System.arraycopy(inbufL, 0, outbufL, 0, inbufL.size)
|
||||||
|
System.arraycopy(inbufR, 0, outbufR, 0, inbufL.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/net/torvald/terrarum/audio/TerrarumAudioMixerTracks.kt
Normal file
55
src/net/torvald/terrarum/audio/TerrarumAudioMixerTracks.kt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package net.torvald.terrarum.audio
|
||||||
|
|
||||||
|
import net.torvald.terrarum.getHashStr
|
||||||
|
import net.torvald.terrarum.modulebasegame.MusicContainer
|
||||||
|
import net.torvald.terrarum.utils.PasswordBase32
|
||||||
|
import kotlin.math.log10
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
typealias TrackVolume = Double
|
||||||
|
|
||||||
|
class TerrarumAudioMixerTracks {
|
||||||
|
|
||||||
|
val hash = getHashStr()
|
||||||
|
|
||||||
|
var currentTrack: MusicContainer? = null
|
||||||
|
var nextTrack: MusicContainer? = null
|
||||||
|
|
||||||
|
var volume: TrackVolume = 1.0
|
||||||
|
get() = field
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
currentTrack?.gdxMusic?.volume = volume.toFloat()
|
||||||
|
}
|
||||||
|
|
||||||
|
var pan = 0.0
|
||||||
|
|
||||||
|
var dBfs: Double
|
||||||
|
get() = fullscaleToDecibels(volume)
|
||||||
|
set(value) { volume = decibelsToFullscale(value) }
|
||||||
|
|
||||||
|
val filters = arrayListOf<TerrarumAudioFilters>()
|
||||||
|
val sidechainInputs = arrayListOf<Pair<TerrarumAudioMixerTracks, TrackVolume>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* assign nextTrack to currentTrack, then assign nextNext to nextTrack.
|
||||||
|
* Whatever is on the currentTrack will be lost.
|
||||||
|
*/
|
||||||
|
fun queueNext(nextNext: MusicContainer? = null) {
|
||||||
|
currentTrack = nextTrack
|
||||||
|
nextTrack = nextNext
|
||||||
|
}
|
||||||
|
|
||||||
|
fun play() {
|
||||||
|
currentTrack?.gdxMusic?.play()
|
||||||
|
}
|
||||||
|
|
||||||
|
val isPlaying: Boolean?
|
||||||
|
get() = currentTrack?.gdxMusic?.isPlaying
|
||||||
|
|
||||||
|
|
||||||
|
override fun equals(other: Any?) = this.hash == (other as TerrarumAudioMixerTracks).hash
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fullscaleToDecibels(fs: Double) = 10.0 * log10(fs)
|
||||||
|
fun decibelsToFullscale(db: Double) = 10.0.pow(db / 10.0)
|
||||||
@@ -5,6 +5,7 @@ import com.badlogic.gdx.audio.Music
|
|||||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.terrarum.audio.AudioMixer
|
||||||
import net.torvald.unicode.EMDASH
|
import net.torvald.unicode.EMDASH
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun startMusic(song: MusicContainer) {
|
private fun startMusic(song: MusicContainer) {
|
||||||
AudioManager.startMusic(song)
|
AudioMixer.startMusic(song)
|
||||||
printdbg(this, "Now playing: $song")
|
printdbg(this, "Now playing: $song")
|
||||||
INGAME.sendNotification("Now Playing $EMDASH ${song.name}")
|
INGAME.sendNotification("Now Playing $EMDASH ${song.name}")
|
||||||
state = STATE_PLAYING
|
state = STATE_PLAYING
|
||||||
@@ -117,7 +118,7 @@ class TerrarumMusicGovernor : MusicGovernor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
AudioManager.stopMusic() // explicit call for fade-out when the game instance quits
|
AudioMixer.stopMusic() // explicit call for fade-out when the game instance quits
|
||||||
stopMusic()
|
stopMusic()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user