Skip to content

unit FftC32

em.utils/FftC32.em
package em.utils

from em.lang import Math

module FftC32

    type Complex: class
        re: int16
        im: int16
        function get(): uint32
        function set(w: uint32)
    end

    config fftSize: uint16 = 128
    config shift: uint8 = 1

    function exec(buf: Complex[])

private:

    config N_WAVE: uint16
    config N_WAVE_LOG2: uint8

    config SINE_WAVE: int16[]

    function fixMul(a: int16, b: int16): int16

end

def em$construct()
    N_WAVE = fftSize
    N_WAVE_LOG2 = Math.log2(N_WAVE)
    auto numHalf = N_WAVE / 2
    auto numQtr = N_WAVE / 4
    SINE_WAVE.length = N_WAVE - numQtr
    auto rng = Math.PI / 2
    for auto i = 0; i < SINE_WAVE.length; i++
        if i <= numQtr
            auto sx = Math.sin((rng / numQtr) * i)
            SINE_WAVE[i] = Math.round(sx * 32767) >> shift
        elif i < numHalf
            SINE_WAVE[i] = SINE_WAVE[numHalf - i]
        else
            SINE_WAVE[i] = -(SINE_WAVE[i - numHalf])
        end
    end
end

def exec(buf)
    auto mr = 0
    for auto m = 1; m < fftSize; m++
        auto l = fftSize
        for ;;
            l >>= 1
            continue if mr + l > fftSize - 1
            break
        end
        mr = (mr & (l - 1)) + l
        continue if mr <= m
        auto t = buf[m].get()
        buf[m].set(buf[mr].get())
        buf[mr].set(t)
    end
    auto stage = 1
    auto sineStep = N_WAVE_LOG2 - 1
    while stage < fftSize
        auto twiddleStep = stage << 1
        for auto grp = 0; grp < stage; grp++
            auto idx = grp << sineStep
            auto wr = SINE_WAVE[idx + N_WAVE / 4]
            auto wi = -SINE_WAVE[idx]
            for auto i = grp; i < fftSize; i += twiddleStep
                auto j = i + stage
                auto fci = &buf[i]
                auto fcj = &buf[j]
                auto tr = fixMul(wr, fcj.re) - fixMul(wi, fcj.im)
                auto ti = fixMul(wr, fcj.im) + fixMul(wi, fcj.re)
                auto qr = fci.re >> shift
                auto qi = fci.im >> shift
                fcj.re = qr - tr
                fcj.im = qi - ti
                fci.re = qr + tr
                fci.im = qi + ti
            end
        end
        sineStep -= 1
        stage = twiddleStep
    end
end


def fixMul(a, b)
    auto c = (<int32>a * <int32>b) >> 14
    b = <int16>(<uint32>c & 0x01)
    a = <int16>((c >> 1) + b)
    return a
end

def Complex.get()
    return *(<uint32*>this)
end

def Complex.set(w)
    *(<uint32*>this) = w
end