factoring a bunch of math outside the SawOscillatorDevice class

This commit is contained in:
りき萌 2023-05-01 18:49:33 +02:00
parent 578005f41f
commit 9dbf5000a7
3 changed files with 46 additions and 32 deletions

View file

@ -0,0 +1,17 @@
package net.liquidev.dawd3.audio.devices.oscillator
import kotlin.math.abs
/** Utility for computing the derivative of a phase without artifacting. */
class PhaseDerivative {
private var previousPhase = 0f
private var previousDeltaPhase = 0f
fun stepNextDerivative(phase: Float): Float {
val deltaPhase = phase - previousPhase
val smoothDeltaPhase = if (abs(deltaPhase) > 0.999) previousDeltaPhase else deltaPhase
previousPhase = phase
previousDeltaPhase = deltaPhase
return smoothDeltaPhase
}
}

View file

@ -3,7 +3,6 @@ package net.liquidev.dawd3.audio.devices.oscillator
import net.liquidev.dawd3.Mod
import net.liquidev.dawd3.audio.device.*
import net.minecraft.util.Identifier
import kotlin.math.abs
class SawOscillatorDevice : Device<NoControls> {
companion object : DeviceDescriptor {
@ -16,12 +15,10 @@ class SawOscillatorDevice : Device<NoControls> {
const val oversampling = 4
}
private val phase = InputPort()
private val output = OutputPort(bufferCount = 1)
private var previousPhase = 0f
private var previousDeltaPhase = 0f
private val phaseDerivative = PhaseDerivative()
override fun process(sampleCount: Int, controls: NoControls) {
val phaseBuffer = phase.getConnectedOutputBuffer(0, sampleCount)
@ -29,23 +26,8 @@ class SawOscillatorDevice : Device<NoControls> {
val outputBuffer = output.buffers[0].getOrReallocate(sampleCount)
for (i in 0 until sampleCount) {
val phase = phaseBuffer[i]
val deltaPhase = phase - previousPhase
// Smooth out the delta phase at spikes, as then our PolyBLEP dt is no longer accurate.
val smoothDeltaPhase = if (abs(deltaPhase) > 0.999) previousDeltaPhase else deltaPhase
previousPhase = phase
previousDeltaPhase = deltaPhase
var accumulator = 0f
for (sample in 0 until oversampling) {
val t = sample.toFloat() / oversampling.toFloat()
accumulator += saw(
phase + smoothDeltaPhase * t,
smoothDeltaPhase
)
}
outputBuffer[i] = accumulator / oversampling
val deltaPhase = phaseDerivative.stepNextDerivative(phase)
outputBuffer[i] = oversample(phase, deltaPhase, oversampling, ::saw)
}
}
@ -58,17 +40,6 @@ class SawOscillatorDevice : Device<NoControls> {
}
}
private fun polyBLEP(t: Float, dt: Float) =
if (t < dt) {
val tt = t / dt
tt + tt - tt * tt - 1f
} else if (t > 1f - dt) {
val tt = (t - 1f) / dt
tt * tt + tt + tt + 1f
} else {
0f
}
override fun visitInputPorts(visit: (InputPortName, InputPort) -> Unit) {
visit(phasePort, phase)
}

View file

@ -0,0 +1,26 @@
package net.liquidev.dawd3.audio.devices.oscillator
inline fun oversample(
phase: Float,
deltaPhase: Float,
sampleCount: Int,
oscillator: (Float, Float) -> Float,
): Float {
var accumulator = 0f
for (sample in 0 until sampleCount) {
val t = sample.toFloat() / sampleCount.toFloat()
accumulator += oscillator(phase + deltaPhase * t, deltaPhase)
}
return accumulator / sampleCount.toFloat()
}
fun polyBLEP(t: Float, dt: Float) =
if (t < dt) {
val tt = t / dt
tt + tt - tt * tt - 1f
} else if (t > 1f - dt) {
val tt = (t - 1f) / dt
tt * tt + tt + tt + 1f
} else {
0f
}