summary refs log tree commit diff stats
path: root/src/main/kotlin/space/autistic/radio/fmsim
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2025-03-08 11:32:33 -0300
committerSoniEx2 <endermoneymod@gmail.com>2025-03-08 11:32:33 -0300
commitfee7157d84c3ce887a540be82dc7a7d2e0c8e368 (patch)
treec3e119fd761bdcfe6c500bda755ed571a5dd6c4c /src/main/kotlin/space/autistic/radio/fmsim
parentc97871470f0f3f224a95177ec84b3156b66f3ac4 (diff)
Move things around default
Diffstat (limited to 'src/main/kotlin/space/autistic/radio/fmsim')
-rw-r--r--src/main/kotlin/space/autistic/radio/fmsim/FmFullConstants.kt114
-rw-r--r--src/main/kotlin/space/autistic/radio/fmsim/FmFullDemodulator.kt158
-rw-r--r--src/main/kotlin/space/autistic/radio/fmsim/FmFullMixer.kt4
-rw-r--r--src/main/kotlin/space/autistic/radio/fmsim/FmFullModulator.kt171
4 files changed, 0 insertions, 447 deletions
diff --git a/src/main/kotlin/space/autistic/radio/fmsim/FmFullConstants.kt b/src/main/kotlin/space/autistic/radio/fmsim/FmFullConstants.kt
deleted file mode 100644
index 6b92328..0000000
--- a/src/main/kotlin/space/autistic/radio/fmsim/FmFullConstants.kt
+++ /dev/null
@@ -1,114 +0,0 @@
-package space.autistic.radio.fmsim
-
-import kotlin.math.PI
-import kotlin.math.cos
-import kotlin.math.sin
-
-object FmFullConstants {
-    // tau = 75us, fh = 20396.25Hz
-    const val FM_PREEMPAHSIS_B0_48K = 6.7639647f
-    const val FM_PREEMPHASIS_B1_48K = -4.975628f
-
-    /* const val FM_PREEMPHASIS_A0_48K = 1f */
-    const val FM_PREEMPHASIS_A1_48K = 0.78833646f
-
-    const val FM_DEEMPAHSIS_B0_48K = 1f / FM_PREEMPAHSIS_B0_48K
-    const val FM_DEEMPHASIS_B1_48K = FM_PREEMPHASIS_A1_48K / FM_PREEMPAHSIS_B0_48K
-
-    /* const val FM_DEEMPHASIS_A0_48K = 1f */
-    const val FM_DEEMPHASIS_A1_48K = FM_PREEMPHASIS_B1_48K / FM_PREEMPAHSIS_B0_48K
-
-    val FIR_LPF_48K_15K_3K1 = floatArrayOf(
-        -0.0010006913216784596f,
-        0.001505308784544468f,
-        -2.625857350794219e-18f,
-        -0.002777613466605544f,
-        0.0030173989944159985f,
-        0.002290070755407214f,
-        -0.008225799538195133f,
-        0.004239063244313002f,
-        0.010359899140894413f,
-        -0.017650796100497246f,
-        1.510757873119297e-17f,
-        0.029305754229426384f,
-        -0.02889496460556984f,
-        -0.020366130396723747f,
-        0.07103750854730606f,
-        -0.03811456635594368f,
-        -0.10945471376180649f,
-        0.29212409257888794f,
-        0.6252123713493347f,
-        0.29212409257888794f,
-        -0.10945471376180649f,
-        -0.03811456635594368f,
-        0.07103750854730606f,
-        -0.020366130396723747f,
-        -0.02889496460556984f,
-        0.029305754229426384f,
-        1.510757873119297e-17f,
-        -0.017650796100497246f,
-        0.010359899140894413f,
-        0.004239063244313002f,
-        -0.008225799538195133f,
-        0.002290070755407214f,
-        0.0030173989944159985f,
-        -0.002777613466605544f,
-        -2.625857350794219e-18f,
-        0.001505308784544468f,
-        -0.0010006913216784596f,
-    )
-
-    // chosen such that we can easily do 38kHz mixing in frequency (1500*38k/300k = shift of 95 bins, where 1500 comes
-    // from the 4/25 ratio 48k/300k i.e. 240*25/4)
-    // (the theoretical optimum, as per above, would be around 180)
-    // (we could have fudged the carrier frequency a bit but we chose not to)
-    // NOTE: latency = (data block size / 48000) seconds (84 -> 1.75 ms)
-    const val FFT_SIZE_LPF_48K_15K_3K1 = 2 * 120
-    const val FFT_OVERLAP_LPF_48K_15K_3K1 = 36
-    const val FFT_DATA_BLOCK_SIZE_LPF_48K_15K_3K1 = FFT_SIZE_LPF_48K_15K_3K1 - FFT_OVERLAP_LPF_48K_15K_3K1
-
-    init {
-        assert(FFT_OVERLAP_LPF_48K_15K_3K1 >= FIR_LPF_48K_15K_3K1.size - 1)
-    }
-
-    const val DECIMATION_48K_300K = 4
-    const val INTERPOLATION_48K_300K = 25
-
-    const val FFT_SIZE_48K_300K = FFT_SIZE_LPF_48K_15K_3K1 * INTERPOLATION_48K_300K / DECIMATION_48K_300K
-    const val FFT_OVERLAP_48K_300K = FFT_OVERLAP_LPF_48K_15K_3K1 * INTERPOLATION_48K_300K / DECIMATION_48K_300K
-    const val FFT_DATA_BLOCK_SIZE_48K_300K = FFT_SIZE_48K_300K - FFT_OVERLAP_48K_300K
-
-    // how many bins to shift for 38kHz mixing
-    // assuming FFT_SIZE_LPF_48K_15K_3K1 *bins* (complex)
-    // 19 / 150 is the ratio between 38k/300k
-    const val FREQUENCY_MIXING_BINS_38K =
-        FFT_SIZE_LPF_48K_15K_3K1 * INTERPOLATION_48K_300K / DECIMATION_48K_300K * 19 / 150
-
-    // a single cycle of a 19kHz signal takes (1/19k)/(1/300k) or 300k/19k samples.
-    // since that number isn't exact, buffer an entire 19 cycles.
-    const val BUFFER_SIZE_19K_300K = 300
-
-    // using cosine is nicer
-    val BUFFER_19K_300K = FloatArray(BUFFER_SIZE_19K_300K) {
-        0.1f * cos(2 * PI * 19000.0 * it.toDouble() / 300000.0).toFloat()
-    }
-
-    // we want a carrier deviation of +-75kHz, at a sampling rate of 300kHz
-    const val CORRECTION_FACTOR = (75000.0 / (300000.0 / (2.0 * PI))).toFloat()
-    const val INVERSE_CORRECTION_FACTOR = 1 / CORRECTION_FACTOR
-
-    // these are used for "low/high" mixing
-    const val CBUFFER_SIZE_100K_300K = 3
-
-    val CBUFFER_100K_300K = FloatArray(2 * CBUFFER_SIZE_100K_300K) {
-        val index = it / 2
-        if (it and 1 == 0) {
-            1f * sin(2 * PI * 100000.0 * index.toDouble() / 300000.0).toFloat()
-        } else {
-            1f * cos(2 * PI * 100000.0 * index.toDouble() / 300000.0).toFloat()
-        }
-    }
-
-    const val STEREO = true
-    const val MONO = false
-}
\ No newline at end of file
diff --git a/src/main/kotlin/space/autistic/radio/fmsim/FmFullDemodulator.kt b/src/main/kotlin/space/autistic/radio/fmsim/FmFullDemodulator.kt
deleted file mode 100644
index de44e69..0000000
--- a/src/main/kotlin/space/autistic/radio/fmsim/FmFullDemodulator.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-package space.autistic.radio.fmsim
-
-import org.joml.Vector2f
-import org.jtransforms.fft.FloatFFT_1D
-import space.autistic.radio.complex.I
-import space.autistic.radio.complex.cmul
-import space.autistic.radio.complex.conjugate
-import space.autistic.radio.dsp.Biquad1stOrder
-import java.nio.FloatBuffer
-import java.util.function.BiConsumer
-
-class FmFullDemodulator {
-    private val inputBuffer = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_48K_300K)
-    private val fft300kBuf = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_48K_300K)
-    private val fft48kBuf = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-    private val outputBuffer = FloatBuffer.allocate(2 * FmFullConstants.FFT_DATA_BLOCK_SIZE_LPF_48K_15K_3K1)
-
-    init {
-        inputBuffer.position(2 * FmFullConstants.FFT_OVERLAP_48K_300K)
-    }
-
-    // yep.
-    private val boxcarI = Biquad1stOrder(1f, 1f, 0f)
-    private val boxcarQ = Biquad1stOrder(1f, 1f, 0f)
-    private val delayI = Biquad1stOrder(0f, 1f, 0f)
-    private val delayQ = Biquad1stOrder(0f, 1f, 0f)
-
-    private val deemphasisLeft = Biquad1stOrder(
-        FmFullConstants.FM_DEEMPAHSIS_B0_48K,
-        FmFullConstants.FM_DEEMPHASIS_B1_48K,
-        FmFullConstants.FM_DEEMPHASIS_A1_48K
-    )
-    private val deemphasisRight = Biquad1stOrder(
-        FmFullConstants.FM_DEEMPAHSIS_B0_48K,
-        FmFullConstants.FM_DEEMPHASIS_B1_48K,
-        FmFullConstants.FM_DEEMPHASIS_A1_48K
-    )
-
-    private val lastStereoPilot = Vector2f()
-    private val lastStereoPilotPolarDiscriminator = Vector2f()
-
-    /**
-     * Takes in samples at 300kHz, in I/Q format, and processes them for output.
-     *
-     * Calls consumer with processed samples at 48kHz, stereo.
-     */
-    fun process(input: FloatBuffer, stereo: Boolean, consumer: BiConsumer<Boolean, FloatBuffer>) {
-        while (input.remaining() >= 2) {
-            val z = Vector2f()
-            val w = Vector2f()
-            while (input.remaining() >= 2 && inputBuffer.hasRemaining()) {
-                z.x = boxcarI.process(input.get())
-                z.y = boxcarQ.process(input.get())
-                // quadrature demodulation = FM demodulation
-                // see https://wiki.gnuradio.org/index.php/Quadrature_Demod and such
-                w.x = delayI.process(z.x)
-                w.y = -delayQ.process(z.y)
-                z.cmul(w)
-                inputBuffer.put(org.joml.Math.atan2(z.y, z.x) * FmFullConstants.INVERSE_CORRECTION_FACTOR)
-            }
-            if (!inputBuffer.hasRemaining()) {
-                var stereoPilot = false
-                fft300kBuf.put(0, inputBuffer.array())
-                fft300k.realForward(fft300kBuf.array())
-                for (i in 0 until fft48kBuf.capacity()) {
-                    fft48kBuf.put(i, 0f)
-                }
-                for (i in 2 until (FmFullConstants.FREQUENCY_MIXING_BINS_38K - 2 and 1.inv()) step 2) {
-                    z.x = fft300kBuf.get(i)
-                    z.y = fft300kBuf.get(i + 1)
-                    w.x = fir48kLpf.get(i)
-                    w.y = fir48kLpf.get(i + 1)
-                    z.cmul(w)
-                    fft48kBuf.put(i, z.x)
-                    fft48kBuf.put(i + 1, z.y)
-                }
-                fft48kBuf.put(0, fft300kBuf.get(0) * fir48kLpf.get(0))
-                fft48k.realInverse(fft48kBuf.array(), false)
-                outputBuffer.clear()
-                fft48kBuf.position(FmFullConstants.FFT_OVERLAP_LPF_48K_15K_3K1)
-                for (i in 0 until FmFullConstants.FFT_DATA_BLOCK_SIZE_LPF_48K_15K_3K1) {
-                    val sample = fft48kBuf.get() * (1f / FmFullConstants.FFT_SIZE_48K_300K)
-                    outputBuffer.put(sample)
-                    outputBuffer.put(sample)
-                }
-                outputBuffer.clear()
-                if (stereo) {
-                    z.x = fft300kBuf.get(FmFullConstants.FREQUENCY_MIXING_BINS_38K)
-                    z.y = fft300kBuf.get(FmFullConstants.FREQUENCY_MIXING_BINS_38K + 1)
-                    z.conjugate(w).cmul(lastStereoPilot).conjugate().normalize()
-                    if (lastStereoPilotPolarDiscriminator.distanceSquared(w) < 0.5f && z.lengthSquared() >= FmFullConstants.FFT_SIZE_48K_300K) {
-                        stereoPilot = true
-                    }
-                    lastStereoPilot.set(z)
-                    lastStereoPilotPolarDiscriminator.set(w)
-                    if (stereoPilot) {
-                        // w is our phase offset
-                        // TODO check if this is mathematically sound
-                        z.normalize().cmul(z).cmul(w.conjugate()).conjugate()
-                        // z is our recovered 38kHz carrier, including phase offset
-                        for (i in 0 until fft48kBuf.capacity()) {
-                            fft48kBuf.put(i, 0f)
-                        }
-                        val base = FmFullConstants.FREQUENCY_MIXING_BINS_38K * 2
-                        val sz = Vector2f()
-                        val sw = Vector2f()
-                        for (i in 2 until (FmFullConstants.FREQUENCY_MIXING_BINS_38K - 2 and 1.inv()) step 2) {
-                            sz.x = fft300kBuf.get(base + i)
-                            sz.y = fft300kBuf.get(base + i + 1)
-                            sw.x = fft300kBuf.get(base - i)
-                            sw.y = fft300kBuf.get(base - i + 1)
-                            sz.cmul(z).add(sw.cmul(z).conjugate())
-                            sw.x = fir48kLpf.get(i)
-                            sw.y = fir48kLpf.get(i + 1)
-                            sz.cmul(sw)
-                            fft48kBuf.put(i, sz.x)
-                            fft48kBuf.put(i + 1, sz.y)
-                        }
-                        sz.x = fft300kBuf.get(base)
-                        sz.y = fft300kBuf.get(base + 1)
-                        sz.cmul(z)
-                        fft48kBuf.put(0, sz.x * fir48kLpf.get(0))
-                        fft48k.realInverse(fft48kBuf.array(), false)
-                        outputBuffer.clear()
-                        fft48kBuf.position(FmFullConstants.FFT_OVERLAP_LPF_48K_15K_3K1)
-                        for (i in 0 until FmFullConstants.FFT_DATA_BLOCK_SIZE_LPF_48K_15K_3K1) {
-                            val lmr = fft48kBuf.get() * (1f / FmFullConstants.FFT_SIZE_48K_300K)
-                            val lpr = outputBuffer.get(outputBuffer.position())
-                            outputBuffer.put((lpr + lmr) * 0.5f)
-                            outputBuffer.put((lpr - lmr) * 0.5f)
-                        }
-                        outputBuffer.clear()
-                    }
-                }
-                inputBuffer.position(FmFullConstants.FFT_DATA_BLOCK_SIZE_48K_300K)
-                inputBuffer.compact()
-                for (i in 0 until outputBuffer.capacity() step 2) {
-                    outputBuffer.put(i, deemphasisLeft.process(outputBuffer.get(i)))
-                }
-                for (i in 1 until outputBuffer.capacity() step 2) {
-                    outputBuffer.put(i, deemphasisRight.process(outputBuffer.get(i)))
-                }
-                consumer.accept(stereoPilot, outputBuffer)
-            }
-        }
-    }
-
-    companion object {
-        private val fft300k = FloatFFT_1D(FmFullConstants.FFT_SIZE_48K_300K.toLong())
-        private val fft48k = FloatFFT_1D(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1.toLong())
-        private val fir48kLpf = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-
-        init {
-            fir48kLpf.put(0, FmFullConstants.FIR_LPF_48K_15K_3K1)
-            fft48k.realForward(fir48kLpf.array())
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/space/autistic/radio/fmsim/FmFullMixer.kt b/src/main/kotlin/space/autistic/radio/fmsim/FmFullMixer.kt
deleted file mode 100644
index 654d50f..0000000
--- a/src/main/kotlin/space/autistic/radio/fmsim/FmFullMixer.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package space.autistic.radio.fmsim
-
-class FmFullMixer {
-}
\ No newline at end of file
diff --git a/src/main/kotlin/space/autistic/radio/fmsim/FmFullModulator.kt b/src/main/kotlin/space/autistic/radio/fmsim/FmFullModulator.kt
deleted file mode 100644
index 1f3849e..0000000
--- a/src/main/kotlin/space/autistic/radio/fmsim/FmFullModulator.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-package space.autistic.radio.fmsim
-
-import org.joml.Vector2f
-import space.autistic.radio.complex.cmul
-import space.autistic.radio.complex.conjugate
-import space.autistic.radio.dsp.Biquad1stOrder
-import java.nio.FloatBuffer
-import java.util.function.Consumer
-import org.jtransforms.fft.FloatFFT_1D
-import space.autistic.radio.complex.I
-import kotlin.math.max
-import kotlin.math.min
-import kotlin.math.sqrt
-
-class FmFullModulator {
-    private val leftPlusRight = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-    private val leftMinusRight = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-    private val biquadLeft = Biquad1stOrder(
-        FmFullConstants.FM_PREEMPAHSIS_B0_48K,
-        FmFullConstants.FM_PREEMPHASIS_B1_48K,
-        FmFullConstants.FM_PREEMPHASIS_A1_48K
-    )
-    private val biquadRight = Biquad1stOrder(
-        FmFullConstants.FM_PREEMPAHSIS_B0_48K,
-        FmFullConstants.FM_PREEMPHASIS_B1_48K,
-        FmFullConstants.FM_PREEMPHASIS_A1_48K
-    )
-    private val fft48kBuffer = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-    private val mixingBuffer = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_48K_300K)
-    private val outputBuffer = FloatBuffer.allocate(2 * FmFullConstants.FFT_DATA_BLOCK_SIZE_48K_300K)
-    private val stereoPilot = FloatBuffer.wrap(FmFullConstants.BUFFER_19K_300K)
-
-    private val cycle19k = Vector2f(0f, 1f)
-    private var lastSum = 0f
-
-    init {
-        // pre-pad the buffers
-        leftPlusRight.position(FmFullConstants.FFT_OVERLAP_LPF_48K_15K_3K1)
-        leftMinusRight.position(FmFullConstants.FFT_OVERLAP_LPF_48K_15K_3K1)
-    }
-
-    /**
-     * Takes in samples at 48kHz, interleaved stereo (even when set to MONO), and processes them for output.
-     *
-     * Calls consumer with processed samples at 300kHz in I/Q format.
-     */
-    fun process(input: FloatBuffer, power: Float, stereo: Boolean, consumer: Consumer<FloatBuffer>) {
-        while (input.remaining() >= 2) {
-            while (input.remaining() >= 2 && leftPlusRight.hasRemaining()) {
-                // FIXME AGC (currently clamping/clipping)
-                val left = min(max(biquadLeft.process(input.get()), -1f), 1f)
-                val right = min(max(biquadRight.process(input.get()), -1f), 1f)
-                leftPlusRight.put(left + right)
-                leftMinusRight.put(left - right)
-            }
-            if (!leftPlusRight.hasRemaining()) {
-                // zero the mixing buffer
-                for (i in 0 until mixingBuffer.capacity()) {
-                    mixingBuffer.put(i, 0f)
-                }
-                fft48kBuffer.put(0, leftPlusRight, 0, FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-                fft48k.realForward(fft48kBuffer.array())
-                fft48kBuffer.array().forEachIndexed { index, fl ->
-                    fft48kBuffer.put(
-                        index,
-                        0.4f / FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1 * fl
-                    )
-                }
-                val z = Vector2f()
-                val w = Vector2f()
-                for (i in 2 until (FmFullConstants.FREQUENCY_MIXING_BINS_38K - 2 and 1.inv()) step 2) {
-                    z.x = fft48kBuffer.get(i)
-                    z.y = fft48kBuffer.get(i + 1)
-                    w.x = fir48kLpf.get(i)
-                    w.y = fir48kLpf.get(i + 1)
-                    z.cmul(w)
-                    mixingBuffer.put(i, z.x)
-                    mixingBuffer.put(i + 1, z.y)
-                }
-                mixingBuffer.put(0, fft48kBuffer.get(0) * fir48kLpf.get(0))
-                if (stereo) {
-                    fft48kBuffer.put(0, leftMinusRight, 0, FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-                    fft48k.realForward(fft48kBuffer.array())
-                    fft48kBuffer.array().forEachIndexed { index, fl ->
-                        fft48kBuffer.put(
-                            index,
-                            0.2f / FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1 * fl
-                        )
-                    }
-                    val base = FmFullConstants.FREQUENCY_MIXING_BINS_38K * 2
-                    for (i in 2 until (FmFullConstants.FREQUENCY_MIXING_BINS_38K - 2 and 1.inv()) step 2) {
-                        z.x = fft48kBuffer.get(i)
-                        z.y = fft48kBuffer.get(i + 1)
-                        w.x = fir48kLpf.get(i)
-                        w.y = fir48kLpf.get(i + 1)
-                        z.cmul(w)
-                        mixingBuffer.put(base + i, z.x)
-                        mixingBuffer.put(base + i + 1, z.y)
-                    }
-                    mixingBuffer.put(base, fft48kBuffer.get(0) * fir48kLpf.get(0))
-                    // cycle (phase offset) is frequency-doubled the 19k carrier
-                    // but we need to add a 90deg rotation because ???
-                    // TODO check if this is mathematically sound
-                    val cycle = cycle19k.cmul(cycle19k, Vector2f()).cmul(I)
-                    // bandwidth we care about is about half of 38k, so just, well, half it
-                    for (i in 2 until (FmFullConstants.FREQUENCY_MIXING_BINS_38K - 2 and 1.inv()) step 2) {
-                        z.x = mixingBuffer.get(base + i)
-                        z.y = mixingBuffer.get(base + i + 1)
-                        // we also need the conjugate
-                        z.conjugate(w)
-                        z.cmul(cycle)
-                        w.cmul(cycle)
-                        mixingBuffer.put(base + i, z.x)
-                        mixingBuffer.put(base + i + 1, z.y)
-                        mixingBuffer.put(base - i, mixingBuffer.get(base - i) + w.x)
-                        mixingBuffer.put(base - i + 1, mixingBuffer.get(base - i + 1) + w.y)
-                    }
-                    // handle 38kHz itself
-                    z.x = mixingBuffer.get(base)
-                    z.y = mixingBuffer.get(base + 1)
-                    z.cmul(cycle)
-                    mixingBuffer.put(base, z.x)
-                    mixingBuffer.put(base + 1, z.y)
-                    // add pilot
-                    mixingBuffer.put(
-                        FmFullConstants.FREQUENCY_MIXING_BINS_38K,
-                        75f / FmFullConstants.FFT_SIZE_48K_300K * cycle19k.x
-                    )
-                    mixingBuffer.put(
-                        FmFullConstants.FREQUENCY_MIXING_BINS_38K + 1,
-                        75f / FmFullConstants.FFT_SIZE_48K_300K * cycle19k.y
-                    )
-                    // phase correction factors (due to dropping 225 bins)
-                    cycle19k.cmul(I.conjugate())
-                }
-                // mark data block as processed
-                leftPlusRight.position(FmFullConstants.FFT_DATA_BLOCK_SIZE_LPF_48K_15K_3K1)
-                leftMinusRight.position(FmFullConstants.FFT_DATA_BLOCK_SIZE_LPF_48K_15K_3K1)
-                leftPlusRight.compact()
-                leftMinusRight.compact()
-                fft300k.realInverse(mixingBuffer.array(), false)
-                outputBuffer.clear()
-                var sum = lastSum
-                for (i in FmFullConstants.FFT_OVERLAP_48K_300K until FmFullConstants.FFT_SIZE_48K_300K) {
-                    sum += mixingBuffer.get(i) * FmFullConstants.CORRECTION_FACTOR
-                    outputBuffer.put(org.joml.Math.cos(sum) * power)
-                    outputBuffer.put(org.joml.Math.sin(sum) * power)
-                }
-                lastSum = sum % (2 * Math.PI).toFloat()
-                outputBuffer.clear()
-                consumer.accept(outputBuffer)
-            }
-        }
-        input.compact()
-    }
-
-    fun flush(power: Float, stereo: Boolean, consumer: Consumer<FloatBuffer>) {
-        process(FloatBuffer.allocate(2 * leftPlusRight.remaining()), power, stereo, consumer)
-    }
-
-    companion object {
-        private val fft48k = FloatFFT_1D(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1.toLong())
-        private val fft300k = FloatFFT_1D(FmFullConstants.FFT_SIZE_48K_300K.toLong())
-        private val fir48kLpf = FloatBuffer.allocate(FmFullConstants.FFT_SIZE_LPF_48K_15K_3K1)
-
-        init {
-            fir48kLpf.put(0, FmFullConstants.FIR_LPF_48K_15K_3K1)
-            fft48k.realForward(fir48kLpf.array())
-        }
-    }
-}
\ No newline at end of file