convolver crossfeed; filter debug code moved to the classes

This commit is contained in:
minjaesong
2023-12-21 17:00:23 +09:00
parent 64ef0343b9
commit fefdf44e3e
15 changed files with 299 additions and 182 deletions

View File

@@ -184,11 +184,11 @@ object AudioMixer: Disposable {
it.addSidechainInput(sfxSumBus, 1.0)
}
convolveBusOpen.filters[1] = Convolv(ModMgr.getFile("basegame", "audio/convolution/EchoThief - PurgatoryChasm.bin"))
convolveBusOpen.filters[1] = Convolv(ModMgr.getFile("basegame", "audio/convolution/EchoThief - PurgatoryChasm.bin"), decibelsToFullscale(-6.0).toFloat())
convolveBusOpen.filters[2] = Gain(decibelsToFullscale(17.0).toFloat()) // don't make it too loud; it'll sound like a shit
convolveBusOpen.volume = 0.5 // will be controlled by the other updater which surveys the world
convolveBusCave.filters[1] = Convolv(ModMgr.getFile("basegame", "audio/convolution/EchoThief - WaterplacePark-trimmed.bin"))
convolveBusCave.filters[1] = Convolv(ModMgr.getFile("basegame", "audio/convolution/EchoThief - WaterplacePark-trimmed.bin"), decibelsToFullscale(-3.0).toFloat())
convolveBusCave.filters[2] = Gain(decibelsToFullscale(16.0).toFloat())
convolveBusCave.volume = 0.5 // will be controlled by the other updater which surveys the world

View File

@@ -1,10 +1,20 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.audio.AudioMixer
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.audio.decibelsToFullscale
import net.torvald.terrarum.ui.BasicDebugInfoWindow
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.toIntAndFrac
import net.torvald.terrarum.ui.Toolkit
import kotlin.math.absoluteValue
import kotlin.math.roundToInt
/**
* The input audio must be monaural
@@ -62,4 +72,22 @@ class BinoPan(var pan: Float, var earDist: Float = 0.18f): TerrarumAudioFilter()
push(inbuf[0], delayLine)
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
val w = pan * 0.5f * STRIP_W
batch.color = COL_METER_GRAD2
Toolkit.fillArea(batch, x + STRIP_W / 2f, y.toFloat(), w, 14f)
batch.color = COL_METER_GRAD
Toolkit.fillArea(batch, x + STRIP_W / 2f, y+14f, w, 2f)
batch.color = FILTER_NAME_ACTIVE
val panLabel = if (pan == 0f) "<C>"
else if (pan < 0) "L${pan.absoluteValue.times(100).toIntAndFrac(3,1)}"
else "R${pan.absoluteValue.times(100).toIntAndFrac(3,1)}"
App.fontSmallNumbers.draw(batch, panLabel, x+3f, y+1f)
App.fontSmallNumbers.draw(batch, "AS:${AudioMixer.SPEED_OF_SOUND.roundToInt()}", x+3f, y+17f)
}
override val debugViewHeight = 32
}

View File

@@ -1,7 +1,14 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.audio.linToLogPerc
import net.torvald.terrarum.roundToFloat
import net.torvald.terrarum.ui.BasicDebugInfoWindow
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.toIntAndFrac
import net.torvald.terrarum.ui.Toolkit
class Bitcrush(var steps: Int, var inputGain: Float = 1f): TerrarumAudioFilter() {
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
@@ -14,4 +21,19 @@ class Bitcrush(var steps: Int, var inputGain: Float = 1f): TerrarumAudioFilter()
}
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
val perc = linToLogPerc(steps.toDouble(), 2.0, 65536.0).toFloat()
batch.color = BasicDebugInfoWindow.COL_METER_GRAD2
Toolkit.fillArea(batch, x.toFloat(), y.toFloat(), BasicDebugInfoWindow.STRIP_W * perc, 14f)
batch.color = BasicDebugInfoWindow.COL_METER_GRAD
Toolkit.fillArea(batch, x.toFloat(), y+14f, BasicDebugInfoWindow.STRIP_W * perc, 2f)
val bits = FastMath.log(steps.toFloat(), 2f).toIntAndFrac(1,2)
batch.color = BasicDebugInfoWindow.FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, "B:$bits", x+3f, y+1f)
}
override val debugViewHeight = 16
}

View File

@@ -1,5 +1,10 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.App
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.AUDIO_BUFFER_SIZE
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
object Buffer : TerrarumAudioFilter() {
init {
bypass = true
@@ -8,4 +13,11 @@ object Buffer : TerrarumAudioFilter() {
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
bypass = true
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
batch.color = FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, "Bs:${AUDIO_BUFFER_SIZE}", x+3f, y+1f)
}
override val debugViewHeight = 16
}

View File

@@ -1,17 +1,34 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.App.setDebugTime
import net.torvald.terrarum.audio.*
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack.Companion.AUDIO_BUFFER_SIZE
import net.torvald.terrarum.ui.BasicDebugInfoWindow
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2_RED
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2_YELLOW
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD_RED
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD_YELLOW
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W
import net.torvald.terrarum.ui.Toolkit
import java.io.File
import kotlin.math.roundToInt
class Convolv(ir: File, val gain: Float = 1f / 512f): TerrarumAudioFilter() {
/**
* @param ir Binary file containing MONO IR
* @param crossfeed The amount of channel crossfeeding to simulate the stereo ID
*/
class Convolv(ir: File, val crossfeed: Float, gain: Float = 1f / 256f): TerrarumAudioFilter() {
private val gain: Float = gain / (1f + crossfeed)
val fftLen: Int
private val convFFT: Array<ComplexArray>
// private val inbuf: Array<ComplexArray>
private val sumbuf: ComplexArray
private val sumbuf: Array<ComplexArray>
private val BLOCKSIZE = TerrarumAudioMixerTrack.AUDIO_BUFFER_SIZE
@@ -31,8 +48,7 @@ class Convolv(ir: File, val gain: Float = 1f / 512f): TerrarumAudioFilter() {
println("IR '${ir.path}' Sample Count = $sampleCount; FFT Length = $fftLen")
val conv = Array(2) { FloatArray(fftLen) }
// inbuf = Array(2) { ComplexArray(FloatArray(fftLen * 2)) }
sumbuf = ComplexArray(FloatArray(fftLen * 2))
sumbuf = Array(2) { ComplexArray(FloatArray(fftLen * 2)) }
ir.inputStream().let {
for (i in 0 until sampleCount) {
@@ -93,8 +109,8 @@ class Convolv(ir: File, val gain: Float = 1f / 512f): TerrarumAudioFilter() {
pushSum(gain, inbuf[0], inbuf[1], sumbuf)
convolve(sumbuf, convFFT[0], fftOutL)
convolve(sumbuf, convFFT[1], fftOutR)
convolve(sumbuf[0], convFFT[0], fftOutL)
convolve(sumbuf[1], convFFT[1], fftOutR)
for (i in 0 until BLOCKSIZE) {
outbuf[0][i] = fftOutL[fftLen - BLOCKSIZE + i]
@@ -109,7 +125,7 @@ class Convolv(ir: File, val gain: Float = 1f / 512f): TerrarumAudioFilter() {
}
fun push(gain: Float, samples: FloatArray, buf: ComplexArray) {
private fun push(gain: Float, samples: FloatArray, buf: ComplexArray) {
// shift numbers
System.arraycopy(buf.reim, samples.size * 2, buf.reim, 0, buf.reim.size - samples.size * 2)
// fill in the shifted area
@@ -120,15 +136,42 @@ class Convolv(ir: File, val gain: Float = 1f / 512f): TerrarumAudioFilter() {
}
}
fun pushSum(gain: Float, sampleL: FloatArray, sampleR: FloatArray, buf: ComplexArray) {
private fun pushSum(gain: Float, sampleL: FloatArray, sampleR: FloatArray, sumbuf: Array<ComplexArray>) {
// shift numbers
System.arraycopy(buf.reim, sampleL.size * 2, buf.reim, 0, buf.reim.size - sampleL.size * 2)
System.arraycopy(sumbuf[0].reim, sampleL.size * 2, sumbuf[0].reim, 0, sumbuf[0].reim.size - sampleL.size * 2)
System.arraycopy(sumbuf[1].reim, sampleL.size * 2, sumbuf[1].reim, 0, sumbuf[1].reim.size - sampleL.size * 2)
// fill in the shifted area
val baseI = buf.reim.size - sampleL.size * 2
val baseI = sumbuf[0].reim.size - sampleL.size * 2
for (index in sampleL.indices) {
buf.reim[baseI + index * 2 + 0] = (sampleL[index] + sampleR[index]) * gain
buf.reim[baseI + index * 2 + 1] = 0f
sumbuf[0].reim[baseI + index * 2 + 0] = (sampleL[index] * 1.000000f + sampleR[index] * crossfeed) * gain
sumbuf[0].reim[baseI + index * 2 + 1] = 0f
sumbuf[1].reim[baseI + index * 2 + 0] = (sampleL[index] * crossfeed + sampleR[index] * 1.000000f) * gain
sumbuf[1].reim[baseI + index * 2 + 1] = 0f
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
// processing speed bar
val w = processingSpeed
val perc = w.coerceAtMost(2f) / 2f
batch.color = if (w > 1.5f) COL_METER_GRAD2 else if (w > 1f) COL_METER_GRAD2_YELLOW else COL_METER_GRAD2_RED
Toolkit.fillArea(batch, x.toFloat(), y.toFloat(), STRIP_W * perc, 14f)
batch.color = if (w > 1.5f) COL_METER_GRAD else if (w > 1f) COL_METER_GRAD_YELLOW else COL_METER_GRAD_RED
Toolkit.fillArea(batch, x.toFloat(), y+14f, STRIP_W * perc, 2f)
// filter length bar
val g = FastMath.intLog2(AUDIO_BUFFER_SIZE)
val perc2 = (FastMath.intLog2(fftLen).minus(g).toFloat() / (16f - g)).coerceIn(0f, 1f)
batch.color = COL_METER_GRAD2
Toolkit.fillArea(batch, x.toFloat(), y + 16f, STRIP_W * perc2, 14f)
batch.color = COL_METER_GRAD
Toolkit.fillArea(batch, x.toFloat(), y + 16f+14f, STRIP_W * perc2, 2f)
// texts
batch.color = FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, "P:${processingSpeed.times(100).roundToInt().div(100f)}x", x+3f, y+1f)
App.fontSmallNumbers.draw(batch, "L:${fftLen}", x+3f, y+17f)
}
override val debugViewHeight = 32
}

View File

@@ -1,6 +1,11 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.App
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.audio.fullscaleToDecibels
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
import kotlin.math.roundToInt
class Gain(var gain: Float): TerrarumAudioFilter() {
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
@@ -9,4 +14,11 @@ class Gain(var gain: Float): TerrarumAudioFilter() {
outbuf[1][i] = inbuf[1][i] * gain
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
batch.color = FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, "G:${fullscaleToDecibels(gain.toDouble()).times(100).roundToInt().div(100f)}", x+3f, y+1f)
}
override val debugViewHeight = 16
}

View File

@@ -1,7 +1,15 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.audio.linToLogPerc
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W
import net.torvald.terrarum.ui.Toolkit
class Highpass(cutoff0: Float): TerrarumAudioFilter() {
@@ -47,4 +55,17 @@ class Highpass(cutoff0: Float): TerrarumAudioFilter() {
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
val perc = 1f - linToLogPerc(cutoff, 2.0, 24000.0).toFloat()
batch.color = COL_METER_GRAD2
Toolkit.fillArea(batch, x.toFloat() + STRIP_W, y.toFloat(), -STRIP_W * perc, 14f)
batch.color = COL_METER_GRAD
Toolkit.fillArea(batch, x.toFloat() + STRIP_W, y+14f, -STRIP_W * perc, 2f)
batch.color = FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, "F:${cutoff.toInt()}", x+3f, y+1f)
}
override val debugViewHeight = 16
}

View File

@@ -1,7 +1,15 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.terrarum.App
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.audio.linToLogPerc
import net.torvald.terrarum.ui.BasicDebugInfoWindow
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.FILTER_NAME_ACTIVE
import net.torvald.terrarum.ui.Toolkit
class Lowpass(cutoff0: Float): TerrarumAudioFilter() {
@@ -47,4 +55,16 @@ class Lowpass(cutoff0: Float): TerrarumAudioFilter() {
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
val perc = linToLogPerc(cutoff, 24.0, 24000.0).toFloat()
batch.color = COL_METER_GRAD2
Toolkit.fillArea(batch, x.toFloat(), y.toFloat(), BasicDebugInfoWindow.STRIP_W * perc, 14f)
batch.color = COL_METER_GRAD
Toolkit.fillArea(batch, x.toFloat(), y+14f, BasicDebugInfoWindow.STRIP_W * perc, 2f)
batch.color = FILTER_NAME_ACTIVE
App.fontSmallNumbers.draw(batch, "F:${cutoff.toInt()}", x+3f, y+1f)
}
override val debugViewHeight = 16
}

View File

@@ -1,9 +1,16 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
object NullFilter : TerrarumAudioFilter() {
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
outbuf.forEachIndexed { index, outTrack ->
System.arraycopy(inbuf[index], 0, outTrack, 0, outTrack.size)
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
}
override val debugViewHeight = 0
}

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.jme3.math.FastMath
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import kotlin.math.roundToInt
@@ -46,4 +47,9 @@ class Reverb(val delayMS: Float = 36f, var feedback: Float = 0.92f, var lowpass:
}
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
}
override val debugViewHeight = 0
}

View File

@@ -1,6 +1,10 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.STRIP_W
import net.torvald.terrarum.ui.Toolkit
import kotlin.math.roundToInt
class Scope : TerrarumAudioFilter() {
@@ -37,4 +41,26 @@ class Scope : TerrarumAudioFilter() {
System.arraycopy(inbuf[index], 0, outTrack, 0, outTrack.size)
}
}
private val halfStripW = STRIP_W / 2
private val scopePlotCol = Color(0x61b3df_33)
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
batch.color = scopePlotCol
val xxs = backbufR
val yys = backbufL
for (t in xxs.lastIndex downTo 0) {
val xs = xxs[t]
val ys = yys[t]
for (i in xs.indices.reversed()) {
val px = xs[i] * halfStripW + halfStripW
val py = ys[i] * halfStripW + halfStripW
Toolkit.fillArea(batch, x + px, y + py, 1f, 1f)
}
}
}
override val debugViewHeight = STRIP_W
}

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import kotlin.math.absoluteValue
import kotlin.math.tanh
@@ -25,4 +26,9 @@ object SoftClp : TerrarumAudioFilter() {
}
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
}
override val debugViewHeight = 0
}

View File

@@ -1,5 +1,7 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
abstract class TerrarumAudioFilter {
var bypass = false
protected abstract fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>)
@@ -11,6 +13,8 @@ abstract class TerrarumAudioFilter {
}
else thru(inbuf, outbuf)
}
abstract fun drawDebugView(batch: SpriteBatch, x: Int, y: Int)
abstract val debugViewHeight: Int
}
fun FloatArray.applyGain(gain: Float = 1f) = this.map { it * gain }.toFloatArray()

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.audio.dsp
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
object XYtoMS: TerrarumAudioFilter() {
@@ -13,6 +14,11 @@ object XYtoMS: TerrarumAudioFilter() {
outbuf[1][i] = S
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
}
override val debugViewHeight = 0
}
object MStoXY: TerrarumAudioFilter() {
@@ -26,4 +32,9 @@ object MStoXY: TerrarumAudioFilter() {
outbuf[1][i] = Y
}
}
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
}
override val debugViewHeight = 0
}