
(require :asdf)

(pushnew #P"/usr/local/asdf-install/site-systems/" asdf:*central-registry*)

(defpackage #:approx-ft-about
  (:use "COMMON-LISP"))
(in-package #:approx-ft-about)

(defun make-image-from-params ( params buf ww hh )
  (labels ((clip (vv)
	     (declare (type fixnum vv))
	     (cond
	       ((minusp vv) 0)
	       ((< 255 vv) 255)
	       (t vv)))
	   (calc (ii jj params &optional (sum 0.5d0))
	     (declare (type double-float ii jj)
		      (type list params)
		      (optimize (speed 3)))
	     (cond
	       ((null params) (clip (round (* sum 255.0d0))))
	       (t (let ((pp (first params)))
		    (let ((amp (first pp))
			  (freq (second pp))
			  (angle (third pp))
			  (off (fourth pp)))
		      (declare (type double-float amp freq angle off))
		      (let ((cos (coerce (cos angle) 'double-float))
			    (sin (coerce (sin angle) 'double-float)))
			(declare (type double-float cos sin))
			(let ((xx (+ (* cos ii) (* sin jj))))
			  (declare (type double-float xx))
			  (let ((raw (coerce (cos (* 2.0d0 pi
						     (+ (* xx freq) off)))
					     'double-float)))
			    (declare (type double-float raw))
			    (calc ii jj
				  (rest params)
				  (+ (* amp raw) sum)))))))))))
    (loop :for jj :from 0 :below hh
       :do (loop :with fj = (- (/ jj hh 0.5d0) 1.0d0)
	      :for ii :from 0 :below ww
	      :do (loop :with fi = (- (/ ii ww 0.5d0) 1.0d0)
		     :for kk :from 0 :below 1
		     :do (setf (aref buf (+ (* jj ww) ii))
			       (calc fi fj params)))))
    buf))

(defun make-image ( amp freq angle off buf ww hh )
  (declare (type double-float amp freq angle off))
  (make-image-from-params (list (list amp freq angle off)) buf ww hh))

(defun make-angle-cycler (initial step buf ww hh
			  &key (amp 0.5d0)
			       (freq 3.0d0)
			       (off 0.0d0))
  (let ((angle (coerce initial 'double-float)))
    (lambda ()
      (values
         (make-image amp freq angle off buf ww hh)
	 (incf angle step)))))

(defun make-offset-cycler (initial step buf ww hh
			  &key (amp 0.5d0)
			       (freq 3.0d0)
			       (angle 0.0d0))
  (let ((off (coerce initial 'double-float)))
    (lambda ()
      (values
         (make-image amp freq angle off buf ww hh)
	 (incf off step)))))

(defun make-frequency-cycler (scale step buf ww hh
			      &key (amp 0.5d0)
			           (angle 0.0d0)
			           (off 0.0d0))
  (let ((freq-angle 0.0d0))
    (lambda ()
      (values
         (make-image amp (* (cos freq-angle) scale) angle off buf ww hh)
	 (incf freq-angle step)))))

(defun make-amplitude-cycler (scale step buf ww hh
			      &key (freq 0.5d0)
			           (angle 0.0d0)
			           (off 0.0d0))
  (let ((amp-angle 0.0d0))
    (lambda ()
      (values
         (make-image (* (cos amp-angle) scale)
		     freq angle off buf ww hh)
	 (incf amp-angle step)))))

(defun make-list-cycler (params buf ww hh)
  (let ((cur (1- (length params))))
    (lambda ()
      (let ((pp (nthcdr cur params)))
	(when (plusp cur)
	  (decf cur))
	(make-image-from-params pp buf ww hh)))))

(defun fixed-to-float ( ff )
  (/ (- ff 32768) 1024.0))

(defparameter +param-count+ 4)
(defparameter +scale+ 0.02d0)
(defparameter +wave-scale+ 1.5d0)

(defun load-gene ( pathname )
  (let ((raw (with-open-file (in pathname)
	       (read in)))
	(scale (make-array +param-count+
			   :initial-contents (list +scale+
						   +wave-scale+
						   pi
						   +wave-scale+))))
    (loop :for ii :from 0 :below (length raw) :by +param-count+
       :collecting (loop :for jj :from 0 :below +param-count+
		      :collecting (* (fixed-to-float (aref raw (+ ii jj)))
				     (aref scale jj))))))

(defparameter +waves+ (load-gene "gene.lisp"))

