dynamic track first commit

This commit is contained in:
minjaesong
2023-12-02 16:41:37 +09:00
parent 9a3ab64383
commit 6da28b943a
5 changed files with 141 additions and 7 deletions

View File

@@ -951,6 +951,23 @@ fun distBetweenActors(a: ActorWithBody, b: ActorWithBody): Double {
val dist = min(min(bpos.distanceSquared(apos1), bpos.distanceSquared(apos2)), bpos.distanceSquared(apos3)) val dist = min(min(bpos.distanceSquared(apos1), bpos.distanceSquared(apos2)), bpos.distanceSquared(apos3))
return dist.sqrt() return dist.sqrt()
} }
/**
* @return positive if the otherActor is on the right side of the player, negative if on the left
*/
fun relativeXposition(thisActor: ActorWithBody, otherActor: ActorWithBody): Double {
val ww = INGAME.world.width * TILE_SIZED
val thisPos = thisActor.centrePosVector
val pos1 = otherActor.centrePosVector
val pos2 = Vector2(pos1.x + ww, pos1.y)
val pos3 = Vector2(pos1.x - ww, pos1.y)
val posToUse = listOf(
pos1 to thisPos.distanceSquared(pos1),
pos2 to thisPos.distanceSquared(pos2),
pos3 to thisPos.distanceSquared(pos3),
).sortedBy { it.second }.first().first
return posToUse.x - thisPos.x
}
fun distBetween(a: ActorWithBody, bpos: Vector2): Double { fun distBetween(a: ActorWithBody, bpos: Vector2): Double {
val ww = INGAME.world.width * TILE_SIZED val ww = INGAME.world.width * TILE_SIZED
val apos1 = a.centrePosVector val apos1 = a.centrePosVector

View File

@@ -95,6 +95,26 @@ object AudioMixer: Disposable {
var processing = true var processing = true
var actorNowPlaying = Terrarum.ingame?.actorNowPlaying; private set
/**
* Return oldest dynamic track, even if the track is currently playing
*/
fun getFreeTrackNoMatterWhat(): TerrarumAudioMixerTrack {
return dynamicTracks.minBy { it.playStartedTime }
}
/**
* Return oldest dynamic track that is not playing
*/
fun getFreeTrack(): TerrarumAudioMixerTrack? {
val oldestTrack = dynamicTracks.minBy { it.playStartedTime }
return if (oldestTrack.isPlaying)
null
else
oldestTrack
}
private val processingExecutor = ThreadExecutor() private val processingExecutor = ThreadExecutor()
// private lateinit var processingSubthreads: List<Thread> // private lateinit var processingSubthreads: List<Thread>
val processingThread = Thread { val processingThread = Thread {
@@ -117,6 +137,8 @@ object AudioMixer: Disposable {
}*/ }*/
while (processing) { while (processing) {
actorNowPlaying = Terrarum.ingame?.actorNowPlaying
for (tracks in parallelProcessingSchedule) { for (tracks in parallelProcessingSchedule) {
if (!processing) break if (!processing) break

View File

@@ -2,10 +2,13 @@ package net.torvald.terrarum.audio
import com.badlogic.gdx.utils.Queue import com.badlogic.gdx.utils.Queue
import net.torvald.reflection.forceInvoke import net.torvald.reflection.forceInvoke
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.audio.dsp.BinoPan
import net.torvald.terrarum.audio.dsp.NullFilter import net.torvald.terrarum.audio.dsp.NullFilter
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.relativeXposition
import net.torvald.terrarum.sqr import net.torvald.terrarum.sqr
import kotlin.math.absoluteValue import kotlin.math.*
import kotlin.math.sqrt
/** /**
* Created by minjaesong on 2023-11-17. * Created by minjaesong on 2023-11-17.
@@ -35,6 +38,8 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
private var breakBomb = false private var breakBomb = false
private val distFalloff = 2048.0
private fun printdbg(msg: Any) { private fun printdbg(msg: Any) {
if (true) println("[AudioAdapter ${track.name}] $msg") if (true) println("[AudioAdapter ${track.name}] $msg")
} }
@@ -67,15 +72,30 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
if (breakBomb) break*/ // uncomment to multithread if (breakBomb) break*/ // uncomment to multithread
// Your code here // Your code here
// update panning and shits
if (track.trackType == TrackType.DYNAMIC_SOURCE && track.isPlaying) {
if (AudioMixer.actorNowPlaying != null) {
if (track.trackingTarget == null || track.trackingTarget == AudioMixer.actorNowPlaying) {
track.volume = track.maxVolume
(track.filters[0] as BinoPan).pan = 0f
}
else {
val relativeXpos = relativeXposition(AudioMixer.actorNowPlaying!!, track.trackingTarget!!)
track.volume = track.maxVolume * (1.0 - relativeXpos.absoluteValue.pow(0.5) / distFalloff)
(track.filters[0] as BinoPan).pan = ((2*asin(relativeXpos / distFalloff)) / Math.PI).toFloat()
}
}
}
// fetch deviceBufferSize amount of sample from the disk // fetch deviceBufferSize amount of sample from the disk
if (track.trackType != TrackType.MASTER && track.trackType != TrackType.BUS && track.streamPlaying) { if (track.trackType != TrackType.MASTER && track.trackType != TrackType.BUS && track.streamPlaying) {
streamBuf.fetchBytes { streamBuf.fetchBytes {
val bytesRead = track.currentTrack?.gdxMusic?.forceInvoke<Int>("read", arrayOf(it)) val bytesRead = track.currentTrack?.gdxMusic?.forceInvoke<Int>("read", arrayOf(it))
if (bytesRead == null || bytesRead <= 0) { // some class (namely Mp3) may return 0 instead of negative value if (bytesRead == null || bytesRead <= 0) { // some class (namely Mp3) may return 0 instead of negative value
// printdbg("Finished reading audio stream") // printdbg("Finished reading audio stream")
track.currentTrack?.gdxMusic?.forceInvoke<Int>("reset", arrayOf()) track.stop()
track.streamPlaying = false
track.fireSongFinishHook()
} }
} }

View File

@@ -1,12 +1,15 @@
package net.torvald.terrarum.audio package net.torvald.terrarum.audio
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.audio.Sound
import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio import com.badlogic.gdx.backends.lwjgl3.audio.OpenALLwjgl3Audio
import com.badlogic.gdx.utils.Disposable import com.badlogic.gdx.utils.Disposable
import com.badlogic.gdx.utils.Queue import com.badlogic.gdx.utils.Queue
import net.torvald.reflection.forceInvoke
import net.torvald.terrarum.App import net.torvald.terrarum.App
import net.torvald.terrarum.audio.dsp.NullFilter import net.torvald.terrarum.audio.dsp.NullFilter
import net.torvald.terrarum.audio.dsp.TerrarumAudioFilter import net.torvald.terrarum.audio.dsp.TerrarumAudioFilter
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.getHashStr import net.torvald.terrarum.getHashStr
import net.torvald.terrarum.hashStrMap import net.torvald.terrarum.hashStrMap
import net.torvald.terrarum.modulebasegame.MusicContainer import net.torvald.terrarum.modulebasegame.MusicContainer
@@ -36,6 +39,8 @@ class TerrarumAudioMixerTrack(val name: String, val trackType: TrackType, privat
var currentTrack: MusicContainer? = null var currentTrack: MusicContainer? = null
var nextTrack: MusicContainer? = null var nextTrack: MusicContainer? = null
var currentSound: Sound? = null // DYNAMIC_SOURCE only
var volume: TrackVolume = 1.0 var volume: TrackVolume = 1.0
get() = field get() = field
set(value) { set(value) {
@@ -46,14 +51,16 @@ class TerrarumAudioMixerTrack(val name: String, val trackType: TrackType, privat
val maxVolume: Double val maxVolume: Double
get() = maxVolumeFun() get() = maxVolumeFun()
var pan = 0.0
var dBfs: Double var dBfs: Double
get() = fullscaleToDecibels(volume) get() = fullscaleToDecibels(volume)
set(value) { volume = decibelsToFullscale(value) } set(value) { volume = decibelsToFullscale(value) }
val filters: Array<TerrarumAudioFilter> = Array(4) { NullFilter } val filters: Array<TerrarumAudioFilter> = Array(4) { NullFilter }
var trackingTarget: ActorWithBody? = null
var playStartedTime = 0L; private set
inline fun <reified T> getFilter() = filters.filterIsInstance<T>().first()!! inline fun <reified T> getFilter() = filters.filterIsInstance<T>().first()!!
internal val sidechainInputs = ArrayList<Pair<TerrarumAudioMixerTrack, TrackVolume>?>() internal val sidechainInputs = ArrayList<Pair<TerrarumAudioMixerTrack, TrackVolume>?>()
@@ -110,6 +117,7 @@ class TerrarumAudioMixerTrack(val name: String, val trackType: TrackType, privat
internal var streamPlaying = false internal var streamPlaying = false
fun play() { fun play() {
playStartedTime = System.nanoTime()
streamPlaying = true streamPlaying = true
// currentTrack?.gdxMusic?.play() // currentTrack?.gdxMusic?.play()
} }
@@ -129,6 +137,14 @@ class TerrarumAudioMixerTrack(val name: String, val trackType: TrackType, privat
override fun equals(other: Any?) = this.hash == (other as TerrarumAudioMixerTrack).hash override fun equals(other: Any?) = this.hash == (other as TerrarumAudioMixerTrack).hash
fun stop() {
currentTrack?.gdxMusic?.forceInvoke<Int>("reset", arrayOf())
streamPlaying = false
playStartedTime = 0L
fireSongFinishHook()
// fireSoundFinishHook()
}
fun fireSongFinishHook() { fun fireSongFinishHook() {
currentTrack?.songFinishedHook?.invoke(currentTrack!!.gdxMusic) currentTrack?.songFinishedHook?.invoke(currentTrack!!.gdxMusic)
} }

View File

@@ -1,9 +1,14 @@
package net.torvald.terrarum.gameactors package net.torvald.terrarum.gameactors
import com.badlogic.gdx.audio.Music
import com.badlogic.gdx.audio.Sound
import net.torvald.random.HQRNG import net.torvald.random.HQRNG
import net.torvald.terrarum.INGAME import net.torvald.terrarum.INGAME
import net.torvald.terrarum.ReferencingRanges import net.torvald.terrarum.ReferencingRanges
import net.torvald.terrarum.Terrarum import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.audio.AudioMixer
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.modulebasegame.MusicContainer
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.savegame.toBigEndian import net.torvald.terrarum.savegame.toBigEndian
@@ -88,6 +93,60 @@ abstract class Actor : Comparable<Actor>, Runnable {
*/ */
abstract @Event fun onActorValueChange(key: String, value: Any?) abstract @Event fun onActorValueChange(key: String, value: Any?)
// @Transient val soundTracks = HashMap<Sound, TerrarumAudioMixerTrack>()
@Transient val musicTracks = HashMap<MusicContainer, TerrarumAudioMixerTrack>()
/*open fun startAudio(sound: Sound) {
getTrackByAudio(sound)?.let {
it.trackingTarget = if (this is ActorWithBody) this else null
it.currentSound = sound
it.play()
}
}*/
private fun getTrackByAudio(music: MusicContainer): TerrarumAudioMixerTrack? {
// get existing track
var track = musicTracks[music]
// if there is no existing track, try to get one
if (track == null) {
track = if (this == Terrarum.ingame?.actorNowPlaying)
AudioMixer.getFreeTrackNoMatterWhat()
else
AudioMixer.getFreeTrack()
// if the request was successful, put it into the hashmap
if (track != null) {
musicTracks[music] = track
}
}
return track
}
open fun startAudio(music: MusicContainer) {
getTrackByAudio(music)?.let {
it.trackingTarget = if (this is ActorWithBody) this else null
it.currentTrack = music
it.play()
}
}
/*open fun stopAudio(sound: Sound) {
}*/
open fun stopAudio(music: MusicContainer) {
musicTracks[music]?.stop()
}
/*open fun onAudioInterrupt(sound: Sound) {
}*/
open @Event fun onAudioInterrupt(music: MusicContainer) {
music.songFinishedHook(music.gdxMusic)
}
abstract fun dispose() abstract fun dispose()
@Transient val localHash = HQRNG().nextInt() @Transient val localHash = HQRNG().nextInt()