diff --git a/src/net/torvald/terrarum/audio/FFT.kt b/src/net/torvald/terrarum/audio/FFT.kt index f1ca165cf..6ced155c3 100644 --- a/src/net/torvald/terrarum/audio/FFT.kt +++ b/src/net/torvald/terrarum/audio/FFT.kt @@ -12,6 +12,7 @@ private val IM0 = 1 private val RE1 = -1 private val IM1 = 0 +private val mulBuf = FloatArray(2) @JvmInline value class ComplexArray(val reim: FloatArray) { @@ -21,12 +22,7 @@ private val IM1 = 0 get() = reim.size / 2 operator fun times(other: ComplexArray): ComplexArray { - val l = size -// val re = FloatArray(l) { res[2*it+RE] * other.res[it] - ims[it] * other.ims[it] } -// val im = FloatArray(l) { res[it] * other.ims[it] + ims[it] * other.res[it] } -// return ComplexArray(re, im) - - val out = FloatArray(l * 2) { + val out = FloatArray(size * 2) { if (it % 2 == 0) reim[it+RE0] * other.reim[it+RE0] - reim[it+IM0] * other.reim[it+IM0] else @@ -37,6 +33,32 @@ private val IM1 = 0 return ComplexArray(out) } + fun mult(other: ComplexArray, out: ComplexArray) { + for (it in 0 until size * 2) { + out.reim[it] = + if (it % 2 == 0) + reim[it+RE0] * other.reim[it+RE0] - reim[it+IM0] * other.reim[it+IM0] + else + reim[it+RE1] *other.reim[it+IM1] + reim[it+IM1] * other.reim[it+RE1] + + } + } + + // this is actually slower that having a separate array for mult results + /*fun inlineMult(other: ComplexArray) { + for (it in 0 until size * 2) { + mulBuf[it % 2] = if (it % 2 == 0) + reim[it+RE0] * other.reim[it+RE0] - reim[it+IM0] * other.reim[it+IM0] + else + reim[it+RE1] *other.reim[it+IM1] + reim[it+IM1] * other.reim[it+RE1] + + if (it % 2 == 1) { + reim[it+RE1] = mulBuf[0] + reim[it+IM1] = mulBuf[1] + } + } + }*/ + fun getReal(): FloatArray { return FloatArray(size) { reim[it * 2] } } @@ -120,6 +142,10 @@ object FFT: Disposable { return ComplexArray(signal) } + fun fft(signal0: ComplexArray) { + ffts[signal0.size]!!.complexForward(signal0.reim) + } + // org.apache.commons.math3.transform.FastFouriesTransformer.java:404 fun ifftAndGetReal(signal0: ComplexArray): FloatArray { // val re = FloatArray(signal0.size) { signal0.reim[it * 2] } diff --git a/src/net/torvald/terrarum/audio/dsp/Convolv.kt b/src/net/torvald/terrarum/audio/dsp/Convolv.kt index 46f994cb1..a85618561 100644 --- a/src/net/torvald/terrarum/audio/dsp/Convolv.kt +++ b/src/net/torvald/terrarum/audio/dsp/Convolv.kt @@ -109,6 +109,10 @@ class Convolv(ir: File, val gain: Float = 1f / 256f): TerrarumAudioFilter() { } private val realtime = (BLOCKSIZE / TerrarumAudioMixerTrack.SAMPLING_RATEF * 1000000000L) + private val fftIn = ComplexArray(FloatArray(fftLen * 2)) + private val fftMult = ComplexArray(FloatArray(fftLen * 2)) + private val fftOut = FloatArray(fftLen) + /** * https://thewolfsound.com/fast-convolution-fft-based-overlap-add-overlap-save-partitioned/ */ @@ -119,10 +123,16 @@ class Convolv(ir: File, val gain: Float = 1f / 256f): TerrarumAudioFilter() { for (ch in outbuf.indices) { push(inbuf[ch].applyGain(gain), this.inbuf[ch]) - val inputFFT = FFT.fft(this.inbuf[ch]) - val Y = inputFFT * convFFT[ch] - val y = FFT.ifftAndGetReal(Y) - System.arraycopy(y, fftLen - BLOCKSIZE, outbuf[ch], 0, BLOCKSIZE) + + for (i in 0 until fftLen) { + fftIn.reim[i * 2] = this.inbuf[ch][i] + fftIn.reim[i * 2 + 1] = 0f + } + + FFT.fft(fftIn) + fftIn.mult(convFFT[ch], fftMult) + FFT.ifftAndGetReal(fftMult, fftOut) + System.arraycopy(fftOut, fftLen - BLOCKSIZE, outbuf[ch], 0, BLOCKSIZE) }