;;;;This file is a simple port of the libsndfile regaining example.
;;;;ie sfprocess.c
(defpackage warm (:export transform *left* *right*) )
;;;;BUFFER_LEN = 8192
;;;;CHANNELS = 2
;;;;So the transforms each act upon an 4096 length list.

(in-package warm)

(defvar *left* (list))
(defvar *right* (list))

(defvar *left-transformation* (lambda (list) (nreverse list)))
(defvar *right-transformation* (lambda (list) (nreverse list)))

;;;These middleman callbacks aren't actually so slow.
(defvar pusher*
(ffi:defcallback push-channels nil ((left :float) (right :float))
                (push left *left*)
                (push right *right*)))
(defvar popleft* (ffi:defcallback pop-left :float () (pop *left*)))
(defvar popright* (ffi:defcallback pop-right :float () (pop *right*)))
(defvar transformer* (ffi:defcallback transformer nil ()
                     (setf *left* (funcall *left-transformation* *left*)
                          *right* (funcall *right-transformation* *right*))))


;;;headers
(ffi:clines "
#include        <stdio.h>
#include        <string.h>

#include        <sndfile.h>

#define         BUFFER_LEN      8192
#define         MAX_CHANNELS    2

")

(defun transformin (infilename outfilename) "
Internal use: Applies the above lambdas.
"
(ffi:with-cstrings ((cinfilename infilename) (coutfilename outfilename))
 (ffi:c-inline (cinfilename coutfilename pusher* transformer*
                popleft* popright*)
              (:cstring :cstring :pointer-void :pointer-void :pointer-void
               :pointer-void) :int "
//callbacks
//        float (* right)(float) = (float (*)(float))#3;
void
(* pusher)(float, float) = (void (*)(float, float))#2;
void
(* transformer)() = (void (*)())#3;
float
(* popleft)() = (float (*)())#4;
float
(* popright)() = (float (*)())#5;

///callbacks
static float data[BUFFER_LEN];

SNDFILE *infile, *outfile;

SF_INFO         sfinfo;
int             readcount;
const char      *infilename = #0;
const char      *outfilename = #1;

memset(&sfinfo, 0, sizeof(sfinfo));

if (! (infile = sf_open(infilename, SFM_READ, &sfinfo))) {
       printf(\"Not able to open input file %s.\\n\", infilename);
       puts(sf_strerror(NULL));
       @(return)=1;
}

if (sfinfo.channels > MAX_CHANNELS) {
       printf(\"Too many channels\\n\");
       @(return)=1;
}

if (! (outfile = sf_open(outfilename, SFM_WRITE, &sfinfo))) {
       printf(\"Not able to open output file %s.\\n\", outfilename);
       puts(sf_strerror(NULL));
       @(return)=1;
}

int i;
while ((readcount = sf_read_float(infile, data, BUFFER_LEN))) {
       //Send both channels to lisp-land
       for (i=0;i<readcount/2;i++) pusher(data[2*i],data[2*i+1]);
       //transform
       transformer();
       //receive each channel back, store in data
       for (i=0;i<readcount/2;i++) {
           data[2*i]=popleft();
           data[2*i+1]=popright();
       }
       //Write to outfile
       sf_write_float(outfile, data, readcount);
}

sf_close (infile) ;
sf_close (outfile) ;

@(return)=0;
")))

(defun transform (inpath outpath left-lambda right-lambda) "
(defun transform (inpath outpath left-lambda right-lambda) )
paths are strings
lambdas are like (lambda (list) (values list))
The list was made by pushing, so it's backwards.
Applied on each stride, hardcoded l 8192 :
4096 elements in each list,
or less in the last list.
Otherwise your function can be arbitrary.
*left* *right* lists are also exported,
if you must.
"
(setf *left-transformation* left-lambda
     *right-transformation* right-lambda)
(transformin inpath outpath))

#|
(transform "test/glorafilia.wav" "test/foop.wav"
           *left-transformation* *right-transformation*)
(ext:quit)
|#