Page 1 of 1

Using FFI array renders dysfunctional

Posted: Sat Nov 12, 2022 12:06 am
by pkhead
I'm making some sort of audio processing thing. I have an array containing the FFT transform. I'm trying to make this array an FFI array instead of a table for potential performance gains.

This is the code that declares the tables, starting from main.lua:26:

Code: Select all

-- using ffi arrays don't work, however using Lua tables does
--local data_l = ffi.new("lua_complex["..(RESOLUTION).."]")
--local data_r = ffi.new("lua_complex["..(RESOLUTION).."]")
local data_l = {}
local data_r = {}
If you switch data_l and data_r to use the FFI array, the output signal becomes garbled. For the past hour, I've struggled to understand why this happens. I've made sure to treat the array as 0-indexed, and it processes the data the same way regardless of if it's an FFI pointer or a table, and yet it only works if it's a table.

I've attached the project zip. (Keep your volume down)

Re: Using FFI array renders dysfunctional

Posted: Sat Nov 12, 2022 9:56 am
by zorg
That's not really an ffi pointer, it's an ffi array of lua_complex structs.
A pointer would be something like you allocating enough memory for RESOLUTION times the size of a lua_complex struct, then doing ffi.new("lua_complex*", memlocation); actually, i'd argue that you should try this, with the memory location being a ByteData, and you doing getFFIPointer on it, passing that to the aforementioned ffi.new call.

I'm not exacly sure though why it's crapping itself; maybe something about the metatype of that complex library it doesn't like when you put it into the array or idk.

I myself did some testing with FFTs though, and i just did it like this:

Code: Select all

local Lr, Rr, Li, Ri = love.data.newByteData(windowSize * ffi.sizeof('double')),
	love.data.newByteData(windowSize * ffi.sizeof('double')),
	love.data.newByteData(windowSize * ffi.sizeof('double')),
	love.data.newByteData(windowSize * ffi.sizeof('double'))
local Lrp, Rrp, Lip, Rip = ffi.cast("double *", Lr:getFFIPointer()),
	ffi.cast("double *", Rr:getFFIPointer()),
	ffi.cast("double *", Li:getFFIPointer()),
	ffi.cast("double *", Ri:getFFIPointer())
in other words, i treated the real and imaginary components of both left and right channels separately, when i was using luafft, which is jank.

After, this is what i did:

Code: Select all

-- used library: https://github.com/soumith/fftw3-ffi

local ffi  = require 'ffi'
local fftw = require 'fftw3'

local N      = 4096*2 -- your RESOLUTION equivalent

local data_i = fftw.alloc_complex(N);
local dptr_i = ffi.new('fftw_complex*', data_i)

local data_o = fftw.alloc_complex(N);
local dptr_o = ffi.new('fftw_complex*', data_o)