mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-17 00:56:07 +09:00
i don't know if it's even working lol
This commit is contained in:
@@ -260,6 +260,7 @@ class AudioMixer : Disposable {
|
|||||||
|
|
||||||
masterTrack.filters[0] = SoftClp
|
masterTrack.filters[0] = SoftClp
|
||||||
masterTrack.filters[1] = Buffer
|
masterTrack.filters[1] = Buffer
|
||||||
|
// masterTrack.filters[1] = Comp(-24f, 5f, 0.5f)
|
||||||
masterTrack.filters[2] = Vecto(1.4142f)
|
masterTrack.filters[2] = Vecto(1.4142f)
|
||||||
masterTrack.filters[3] = Spectro()
|
masterTrack.filters[3] = Spectro()
|
||||||
|
|
||||||
|
|||||||
134
src/net/torvald/terrarum/audio/dsp/Comp.kt
Normal file
134
src/net/torvald/terrarum/audio/dsp/Comp.kt
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
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.decibelsToFullscale
|
||||||
|
import net.torvald.terrarum.audio.fullscaleToDecibels
|
||||||
|
import net.torvald.terrarum.ui.BasicDebugInfoWindow.Companion.COL_METER_GRAD2_YELLOW
|
||||||
|
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 kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2024-12-24.
|
||||||
|
*/
|
||||||
|
class Comp(
|
||||||
|
val thresholdDB: Float,
|
||||||
|
val ratio: Float,
|
||||||
|
/** Knee is defined as the multiplier of the threshold. For example: if threshold is -12dB and kneeRatio is 0.5, the knee will be -24dB to -6dB */
|
||||||
|
val kneeRaio: Float
|
||||||
|
): TerrarumAudioFilter(), DspCompressor {
|
||||||
|
|
||||||
|
private val thresholdLinear = decibelsToFullscale(thresholdDB.toDouble())
|
||||||
|
private val kneeLinear = thresholdLinear * kneeRaio//decibelsToFullscale(kneeDB.toDouble())
|
||||||
|
private val makeupGain = (1.0 - 1.0 / ratio) * (-thresholdDB)
|
||||||
|
private val makeupGainLinear = decibelsToFullscale(makeupGain)
|
||||||
|
|
||||||
|
private var internalGainKnob = 1.0
|
||||||
|
private var internalGainKnobWithoutGain = 1.0
|
||||||
|
private var outputGainKnob = 1.0
|
||||||
|
private var outputGainKnobWithoutGain = 1.0 // used for debug view only
|
||||||
|
private val gainKnobWeight = 0.93 // outputGainKnob is updated per sample (48000 times per second)
|
||||||
|
|
||||||
|
|
||||||
|
private fun calcGainMinusM(sampleL: Float, sampleR: Float, thresholdLinear: Double, ratio: Float, kneeLinear: Double): Double {
|
||||||
|
// https://www.desmos.com/calculator/p3wufeoioi
|
||||||
|
|
||||||
|
val x = maxOf(sampleL.absoluteValue, sampleR.absoluteValue).toDouble()
|
||||||
|
val t = thresholdLinear
|
||||||
|
val k = kneeLinear
|
||||||
|
val r = ratio.toDouble()
|
||||||
|
// val M = (r-1) / r
|
||||||
|
|
||||||
|
val rx = r*x
|
||||||
|
val rt = r*t
|
||||||
|
val rtt = r*t*t
|
||||||
|
val kk = k*k
|
||||||
|
val kkr = k*k*r
|
||||||
|
val krt = k*r*t
|
||||||
|
val kr = k*r
|
||||||
|
val kt = k*t
|
||||||
|
val kx = k*x
|
||||||
|
val tt = t*t
|
||||||
|
val tx = t*x
|
||||||
|
val xx = x*x
|
||||||
|
val halfk = k/2
|
||||||
|
|
||||||
|
val fx = 1.0
|
||||||
|
val gx = (rx-r+t-x)/(rt-r)
|
||||||
|
val K = (kkr-kk+4*krt-8*kr+4*kt+4*rtt-4*tt)/(8*krt-8*kr)
|
||||||
|
val hx = ((r-1)*(kx-2*tx+xx))/(2*krt-2*kr)+K
|
||||||
|
|
||||||
|
|
||||||
|
return if (x < t-halfk)
|
||||||
|
fx
|
||||||
|
else if (1 > x && x > t+halfk)
|
||||||
|
gx
|
||||||
|
else if (t-halfk <= x && x <= t+halfk)
|
||||||
|
hx
|
||||||
|
else
|
||||||
|
(1/r)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override val downForce = arrayOf(1.0f, 1.0f)
|
||||||
|
|
||||||
|
private var maxReduction = 1.0
|
||||||
|
|
||||||
|
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
|
||||||
|
downForce.fill(1.0f)
|
||||||
|
maxReduction = 10000.0
|
||||||
|
|
||||||
|
val outL = outbuf[0]
|
||||||
|
val innL = inbuf[0]
|
||||||
|
val outR = outbuf[1]
|
||||||
|
val innR = inbuf[1]
|
||||||
|
|
||||||
|
for (i in innL.indices) {
|
||||||
|
// do the compression
|
||||||
|
val sampleL = innL[i]
|
||||||
|
val sampleR = innR[i]
|
||||||
|
|
||||||
|
internalGainKnobWithoutGain = calcGainMinusM(sampleL, sampleR, thresholdLinear, ratio, kneeLinear)
|
||||||
|
internalGainKnob = internalGainKnobWithoutGain * makeupGainLinear
|
||||||
|
outputGainKnobWithoutGain = FastMath.interpolateLinear(gainKnobWeight, internalGainKnobWithoutGain, outputGainKnobWithoutGain)
|
||||||
|
outputGainKnob = FastMath.interpolateLinear(gainKnobWeight, internalGainKnob, outputGainKnob)
|
||||||
|
|
||||||
|
outL[i] = (sampleL * internalGainKnob).toFloat()
|
||||||
|
outR[i] = (sampleR * internalGainKnob).toFloat()
|
||||||
|
|
||||||
|
// calculate the downforce
|
||||||
|
maxReduction = minOf(maxReduction, outputGainKnobWithoutGain)
|
||||||
|
|
||||||
|
downForce[0] = maxReduction.toFloat()
|
||||||
|
downForce[1] = maxReduction.toFloat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
|
||||||
|
val reductionDB = fullscaleToDecibels(maxReduction)
|
||||||
|
val perc = (reductionDB / (-0.5*makeupGain)).toFloat().coerceIn(0f, 1f)
|
||||||
|
batch.color = COL_METER_GRAD2_YELLOW
|
||||||
|
Toolkit.fillArea(batch, x.toFloat() + STRIP_W, y.toFloat(), -STRIP_W * perc, 14f)
|
||||||
|
batch.color = COL_METER_GRAD_YELLOW
|
||||||
|
Toolkit.fillArea(batch, x.toFloat() + STRIP_W, y+14f, -STRIP_W * perc, 2f)
|
||||||
|
|
||||||
|
batch.color = FILTER_NAME_ACTIVE
|
||||||
|
App.fontSmallNumbers.draw(batch, "C:${reductionDB.absoluteValue.times(100).roundToInt().div(100f)}", x+3f, y+1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val debugViewHeight: Int = 16
|
||||||
|
|
||||||
|
override fun copyParamsFrom(other: TerrarumAudioFilter) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Double.unNaN(d: Double): Double {
|
||||||
|
return if (this.isNaN()) d else this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
64
src/net/torvald/terrarum/audio/dsp/MultibandComp.kt
Normal file
64
src/net/torvald/terrarum/audio/dsp/MultibandComp.kt
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package net.torvald.terrarum.audio.dsp
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import net.torvald.terrarum.App
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2024-12-22.
|
||||||
|
*/
|
||||||
|
class MultibandComp: TerrarumAudioFilter() {
|
||||||
|
|
||||||
|
private val ratio = 2f
|
||||||
|
|
||||||
|
private val bands = listOf(
|
||||||
|
160f, 1100f, 7500f
|
||||||
|
)
|
||||||
|
|
||||||
|
private val bandFilters = bands.mapIndexed { index: Int, band: Float ->
|
||||||
|
if (index == 0)
|
||||||
|
Lowpass(band)
|
||||||
|
else
|
||||||
|
Bandpass(bands[index-1], band)
|
||||||
|
} + Highpass(bands.last())
|
||||||
|
|
||||||
|
private var midbufLen = App.audioBufferSize
|
||||||
|
private var midbufs = bandFilters.map {
|
||||||
|
listOf(FloatArray(midbufLen), FloatArray(midbufLen))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resizeMidbufs(newLen: Int) {
|
||||||
|
midbufLen = newLen
|
||||||
|
midbufs = bandFilters.map {
|
||||||
|
listOf(FloatArray(midbufLen), FloatArray(midbufLen))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val statelessComp = Comp(-24f, ratio, 6f)
|
||||||
|
|
||||||
|
override fun thru(inbuf: List<FloatArray>, outbuf: List<FloatArray>) {
|
||||||
|
(bandFilters zip midbufs).forEach { (filter, buf) ->
|
||||||
|
// pass thru the band filters
|
||||||
|
filter.thru(inbuf, buf)
|
||||||
|
|
||||||
|
// apply the comp fun
|
||||||
|
for (ch in outbuf.indices) {
|
||||||
|
for (sample in 0 until midbufLen) {
|
||||||
|
statelessComp.thru(buf, buf)
|
||||||
|
|
||||||
|
// and add up the results to the outbuf
|
||||||
|
outbuf[ch][sample] += buf[ch][sample]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun drawDebugView(batch: SpriteBatch, x: Int, y: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override val debugViewHeight: Int = 16
|
||||||
|
|
||||||
|
override fun copyParamsFrom(other: TerrarumAudioFilter) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user