(defpackage cold (:export fftw-convolve fft-kernel))
(in-package cold)
;;;;LENGTH is hardcoded to 4096.

(ffi:clines "
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>

#include <fftw3.h>

#define         LENGTH  4096
")

(ffi:clines "
double a[LENGTH];
double k[LENGTH];
fftw_plan k_pin;
fftw_complex *ck;
")

(defparameter *length* (ffi:c-inline () () :int "@(return)=LENGTH;"))

(ffi:c-inline () () nil "
ck = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * LENGTH);
")

(defun fft-kernel () "
"
(ffi:c-inline () () nil "
k_pin  = fftw_plan_dft_r2c_1d(LENGTH, k, ck, FFTW_ESTIMATE);
fftw_execute(k_pin);
fftw_destroy_plan(k_pin);
"))

(defun gen-kernel (function) "
"
(let ((x 0) (f 0.0d0))
 (declare (:int x) (:double f))
 (dotimes (s *length*)
 (setf f (* 1.0d0 (funcall function)))
 (ffi:c-inline (x f) (:int :double ) nil "
k[#0] = #1; ")
  (incf x)))
(fft-kernel))

;;;;INITIALIZE KERNEL TO SOMETHING DUMB
(gen-kernel (lambda () (* 1.0d0 (1- (random 3)))))

(defun kernth (n)
(ffi:c-inline (n) (:int) :double "
@(return)=k[#0];
"))

(defun set-kernth (n f)
(ffi:c-inline (n f) (:int :double) :double "
k[#0]=#1;
@(return)=(k[#0]);
"))

(defun anth (n)
(ffi:c-inline (n) (:int) :double "
@(return)=a[#0];
"))

(defun set-anth (n f)
(ffi:c-inline (n f) (:int :double) :double "
a[#0]=#1;
@(return)=(a[#0]);
"))


(defun fftw-convolve () "
(fftw-convolve)
"
(ffi:c-inline ()
              ()
              nil"
fftw_complex *ca;
fftw_plan a_pin;
fftw_plan a_pout;

int idx;


ca = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * LENGTH);

a_pin  = fftw_plan_dft_r2c_1d(LENGTH, a, ca, FFTW_ESTIMATE);
fftw_execute(a_pin);
fftw_destroy_plan(a_pin);

for (idx=0; idx<LENGTH;++idx) {
       ca[idx] = ((complex double *)ck)[idx] * ((complex double *)ca)[idx];
}

a_pout = fftw_plan_dft_c2r_1d(LENGTH, ca, a, FFTW_ESTIMATE);

fftw_execute(a_pout);

fftw_destroy_plan(a_pout);
fftw_free(ca);
"))