more audio pathing

This commit is contained in:
minjaesong
2023-11-26 01:59:11 +09:00
parent 4d85d91478
commit cc4fac7dca
9 changed files with 81 additions and 57 deletions

Binary file not shown.

View File

@@ -44,13 +44,16 @@ object AudioMixer: Disposable {
get() = App.getConfigDouble("guivolume")
val tracks = Array(5) { TerrarumAudioMixerTrack(
if (it == 0) "BGM"
else if (it == 1) "AMB"
else if (it == 2) "SFX"
val tracks = Array(8) { TerrarumAudioMixerTrack(
if (it == 0) "Music"
else if (it == 1) "Ambient"
else if (it == 2) "Player"
else if (it == 3) "GUI"
else if (it == 4) "BUS1"
else "Trk${it+1}", isBus = (it == 4), maxVolumeFun = {
else if (it == 4) "\u00F0 \u00E4 \u00F0" // summation
else if (it == 5) "\u00D9Open\u00D9" // convolution1
else if (it == 6) "\u00D9Cave\u00D9" // convolution2
else if (it == 7) "\u00F0 \u00DA \u00F0" // fade
else "Trk${it+1}", isBus = (it >= 4), maxVolumeFun = {
when (it) {
0 -> { musicVolume }
1 -> { ambientVolume }
@@ -61,7 +64,7 @@ object AudioMixer: Disposable {
}
) }
val masterTrack = TerrarumAudioMixerTrack("Master", true) { masterVolume }
val masterTrack = TerrarumAudioMixerTrack("\u00DBMASTER", true) { masterVolume }
val musicTrack: TerrarumAudioMixerTrack
get() = tracks[0]
@@ -72,8 +75,14 @@ object AudioMixer: Disposable {
val guiTrack: TerrarumAudioMixerTrack
get() = tracks[3]
val fadeBus: TerrarumAudioMixerTrack
val sumBus: TerrarumAudioMixerTrack
get() = tracks[4]
val convolveBusOpen: TerrarumAudioMixerTrack
get() = tracks[5]
val convolveBusCave: TerrarumAudioMixerTrack
get() = tracks[6]
val fadeBus: TerrarumAudioMixerTrack
get() = tracks[7]
var processing = true
@@ -102,19 +111,37 @@ object AudioMixer: Disposable {
init {
// musicTrack.filters[0] = BinoPan((Math.random() * 2.0 - 1.0).toFloat())
// musicTrack.filters[1] = Reverb(36f, 0.92f, 1200f)
// initialise audio paths //
// musicTrack.filters[1] = BinoPan(0f)
// musicTrack.filters[2] = Reverb(36f, 0.92f, 1200f)
listOf(musicTrack, ambientTrack, sfxMixTrack, guiTrack).forEach {
it.filters[0] = Gain(1f)
}
masterTrack.filters[0] = SoftClp
masterTrack.filters[1] = Buffer
masterTrack.filters[2] = Scope()
fadeBus.addSidechainInput(musicTrack, 1.0)
fadeBus.addSidechainInput(ambientTrack, 1.0)
fadeBus.addSidechainInput(sfxMixTrack, 1.0)
fadeBus.filters[0] = Convolv(ModMgr.getFile("basegame", "audio/convolution/EchoThief - CedarCreekWinery.bin"))
fadeBus.filters[1] = Gain(10f)
fadeBus.filters[3] = Lowpass(SAMPLING_RATE / 2f)
listOf(sumBus, convolveBusOpen, convolveBusCave).forEach {
it.addSidechainInput(musicTrack, 1.0)
it.addSidechainInput(ambientTrack, 1.0)
it.addSidechainInput(sfxMixTrack, 1.0)
}
convolveBusOpen.filters[0] = Convolv(ModMgr.getFile("basegame", "audio/convolution/EchoThief - Cranbrook Art Museum.bin"))
convolveBusOpen.filters[1] = Gain(decibelsToFullscale(21.0).toFloat())
convolveBusOpen.volume = 0.5
convolveBusCave.filters[0] = Convolv(ModMgr.getFile("basegame", "audio/convolution/EchoThief - CedarCreekWinery.bin"))
convolveBusCave.filters[1] = Gain(decibelsToFullscale(18.0).toFloat())
convolveBusCave.volume = 0.5
fadeBus.addSidechainInput(sumBus, 1.0 / 3.0)
fadeBus.addSidechainInput(convolveBusOpen, 2.0 / 3.0)
fadeBus.addSidechainInput(convolveBusCave, 2.0 / 3.0)
fadeBus.filters[0] = Lowpass(SAMPLING_RATE / 2f)
masterTrack.addSidechainInput(fadeBus, 1.0)
masterTrack.addSidechainInput(guiTrack, 1.0)
@@ -152,7 +179,7 @@ object AudioMixer: Disposable {
fun update(delta: Float) {
// test the panning
/*(musicTrack.filters[0] as? BinoPan)?.let {
/*musicTrack.getFilter<BinoPan>().let {
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
it.pan = (it.pan + 0.001f).coerceIn(-1f, 1f)
}
@@ -166,10 +193,10 @@ object AudioMixer: Disposable {
// the real updates
(Gdx.audio as? Lwjgl3Audio)?.update()
masterTrack.volume = masterVolume
musicTrack.volume = musicVolume
ambientTrack.volume = ambientVolume
sfxMixTrack.volume = sfxVolume
guiTrack.volume = guiVolume
musicTrack.getFilter<Gain>().gain = musicVolume.toFloat()
ambientTrack.getFilter<Gain>().gain = ambientVolume.toFloat()
sfxMixTrack.getFilter<Gain>().gain = sfxVolume.toFloat()
guiTrack.getFilter<Gain>().gain = guiVolume.toFloat()
// process fades

View File

@@ -81,54 +81,48 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
}
}
var samplesL0: FloatArray? = null
var samplesR0: FloatArray? = null
var samplesL1: FloatArray? = null
var samplesR1: FloatArray? = null
var samplesL1: FloatArray
var samplesR1: FloatArray
var bufEmpty = false
// get samples and apply the fader
if (track.isMaster || track.isBus) {
// combine all the inputs
samplesL0 = FloatArray(bufferSize / 4)
samplesR0 = FloatArray(bufferSize / 4)
samplesL1 = FloatArray(bufferSize / 4)
samplesR1 = FloatArray(bufferSize / 4)
val sidechains = track.sidechainInputs.filterNotNull()
// add all up
sidechains.forEach { (side, mix) ->
for (i in samplesL0!!.indices) {
samplesL1!![i] += side.processor.fout1[0][i] * (mix * track.volume).toFloat()
samplesR1!![i] += side.processor.fout1[1][i] * (mix * track.volume).toFloat()
for (i in samplesL1.indices) {
samplesL1[i] += side.processor.fout1[0][i] * (mix * track.volume).toFloat()
samplesR1[i] += side.processor.fout1[1][i] * (mix * track.volume).toFloat()
}
}
}
// source channel: skip processing if there's no active input
// else if (track.getSidechains().any { it != null && !it.isBus && !it.isMaster && !it.streamPlaying } && !track.streamPlaying) {
else if (!track.streamPlaying) {
samplesL0 = null
samplesR0 = null
samplesL1 = null
samplesR1 = null
samplesL1 = emptyBuf
samplesR1 = emptyBuf
bufEmpty = true
}
else {
samplesL0 = streamBuf.getL0(track.volume)
samplesR0 = streamBuf.getR0(track.volume)
samplesL1 = streamBuf.getL1(track.volume)
samplesR1 = streamBuf.getR1(track.volume)
}
if (samplesL0 != null /*&& samplesL1 != null && samplesR0 != null && samplesR1 != null*/) {
if (!bufEmpty) {
// run the input through the stack of filters
val filterStack = track.filters.filter { !it.bypass && it !is NullFilter }
if (filterStack.isEmpty()) {
fout1 = listOf(samplesL1!!, samplesR1!!)
fout1 = listOf(samplesL1, samplesR1)
}
else {
var fin1 = listOf(samplesL1!!, samplesR1!!)
var fin1 = listOf(samplesL1, samplesR1)
fout1 = listOf(FloatArray(bufferSize / 4), FloatArray(bufferSize / 4))
filterStack.forEachIndexed { index, it ->
@@ -162,6 +156,7 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
}
}
else {
fout1 = listOf(samplesL1, samplesR1) // keep pass the so that long-delay filters can empty out its buffer
maxSigLevel.fill(0.0)
maxRMS.fill(0.0)
hasClipping.fill(false)
@@ -173,16 +168,14 @@ class MixerTrackProcessor(val bufferSize: Int, val rate: Int, val track: Terraru
this.pause()
}
else {
if (samplesL0 != null /*&& samplesL1 != null && samplesR0 != null && samplesR1 != null*/) {
// spin until queue is sufficiently empty
/*while (track.pcmQueue.size >= BACK_BUF_COUNT && running) { // uncomment to multithread
Thread.sleep(1)
}*/
// spin until queue is sufficiently empty
/*while (track.pcmQueue.size >= BACK_BUF_COUNT && running) { // uncomment to multithread
Thread.sleep(1)
}*/
// printdbg("PUSHE; Queue size: ${track.pcmQueue.size}")
track.pcmQueue.addLast(fout1)
}
// printdbg("PUSHE; Queue size: ${track.pcmQueue.size}")
track.pcmQueue.addLast(fout1)
// spin
// Thread.sleep(((1000*bufferSize) / 8L / rate).coerceAtLeast(1L)) // uncomment to multithread

View File

@@ -4,7 +4,6 @@ import com.jme3.math.FastMath
import com.jme3.math.FastMath.sin
import net.torvald.terrarum.audio.AudioMixer.SPEED_OF_SOUND
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.BUFFER_SIZE
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATED
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.SAMPLING_RATEF
import net.torvald.terrarum.roundToFloat
import java.io.File
@@ -58,8 +57,8 @@ object SoftClp : TerrarumAudioFilter() {
}
class Scope : TerrarumAudioFilter() {
val backbufL = Array((4096f / BUFFER_SIZE * 4).roundToInt()) { FloatArray(BUFFER_SIZE / 4) }
val backbufR = Array((4096f / BUFFER_SIZE * 4).roundToInt()) { FloatArray(BUFFER_SIZE / 4) }
val backbufL = Array((4096f / BUFFER_SIZE * 4).roundToInt().coerceAtLeast(1)) { FloatArray(BUFFER_SIZE / 4) }
val backbufR = Array((4096f / BUFFER_SIZE * 4).roundToInt().coerceAtLeast(1)) { FloatArray(BUFFER_SIZE / 4) }
private val sqrt2p = 0.7071067811865475
@@ -445,11 +444,11 @@ object MStoXY: TerrarumAudioFilter() {
}
}
class Gain(val gain: Float): TerrarumAudioFilter() {
class Gain(var gain: Float): TerrarumAudioFilter() {
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
for (i in 0 until BUFFER_SIZE / 4) {
outbuf[0][i] = inbuf[1][i] * gain
outbuf[1][i] = inbuf[0][i] * gain
outbuf[0][i] = inbuf[0][i] * gain
outbuf[1][i] = inbuf[1][i] * gain
}
}
}

View File

@@ -20,7 +20,7 @@ class TerrarumAudioMixerTrack(val name: String, val isMaster: Boolean = false, v
const val SAMPLING_RATE = 48000
const val SAMPLING_RATEF = 48000f
const val SAMPLING_RATED = 48000.0
const val BUFFER_SIZE = 8192 // n ms -> 384 * n
const val BUFFER_SIZE = 16384 // n ms -> 384 * n
}
val hash = getHashStr()

View File

@@ -377,7 +377,7 @@ class BasicDebugInfoWindow : UICanvas() {
private val meterTroughHeight = meterGradCountMinusOne * meterGradSize + 5
private val meterHeight = meterTroughHeight - 4
private val stripW = 56
private val stripW = 54
private val halfStripW = stripW / 2
private val stripGap = 1
private val stripFilterHeight = 16
@@ -454,7 +454,7 @@ class BasicDebugInfoWindow : UICanvas() {
// name text
batch.color = FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, track.name, x + 3f, y + stripH - 13f)
App.fontSmallNumbers.draw(batch, track.name, x + 1f + (stripW - track.name.length * 7) / 2, y + stripH - 13f)
// filterbank back
@@ -484,6 +484,8 @@ class BasicDebugInfoWindow : UICanvas() {
val mixDb = fullscaleToDecibels(mix)
val perc = ((mixDb + 24.0).coerceAtLeast(0.0) / 24.0).toFloat()
// gauge background
batch.color = COL_METER_TROUGH
Toolkit.fillArea(batch, x.toFloat(), faderY - (i+1)*16f, stripW.toFloat(), 14f)
batch.color = COL_SENDS_GRAD2
Toolkit.fillArea(batch, x.toFloat(), faderY - (i+1)*16f, stripW * perc, 14f)
batch.color = COL_SENDS_GRAD