shithub: soundpipe

Download patch

ref: a901d5647d30cf20fc0a096a612c58b2f99b8551
author: Paul Batchelor <thisispaulbatchelor@gmail.com>
date: Sat Sep 5 12:30:21 EDT 2020

import

diff: cannot open b/h//null: file does not exist: 'b/h//null' diff: cannot open b/lib/dr_wav//null: file does not exist: 'b/lib/dr_wav//null' diff: cannot open b/lib/faust//null: file does not exist: 'b/lib/faust//null' diff: cannot open b/lib/fft//null: file does not exist: 'b/lib/fft//null' diff: cannot open b/lib/inih//null: file does not exist: 'b/lib/inih//null' diff: cannot open b/lib/kissfft//null: file does not exist: 'b/lib/kissfft//null' diff: cannot open b/lib/openlpc//null: file does not exist: 'b/lib/openlpc//null' diff: cannot open b/lib/spa//null: file does not exist: 'b/lib/spa//null' diff: cannot open b/lib//null: file does not exist: 'b/lib//null' diff: cannot open b/modules/data//null: file does not exist: 'b/modules/data//null' diff: cannot open b/modules//null: file does not exist: 'b/modules//null' diff: cannot open b/tangled//null: file does not exist: 'b/tangled//null' diff: cannot open b/test/p//null: file does not exist: 'b/test/p//null' diff: cannot open b/test/t//null: file does not exist: 'b/test/t//null' diff: cannot open b/test//null: file does not exist: 'b/test//null' diff: cannot open b/util/css//null: file does not exist: 'b/util/css//null' diff: cannot open b/util/faust//null: file does not exist: 'b/util/faust//null' diff: cannot open b/util//null: file does not exist: 'b/util//null'
--- /dev/null
+++ b/.gitignore
@@ -1,0 +1,20 @@
+*.o
+*.a
+*.wav
+*.raw
+*.swp
+*.dSYM
+soundpipe.h
+soundpipe.c
+.DS_Store
+docs
+*.html
+examples/plot.dat
+examples/*.bin
+config.mk
+test/*.bin
+lib/fft/fft.c
+
+# Generated files
+util/wav2smp
+sp_dict.lua
--- /dev/null
+++ b/LICENSE
@@ -1,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2020 Paul Batchelor
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+++ b/Makefile
@@ -1,0 +1,93 @@
+.PHONY: all clean install docs bootstrap util
+
+default: all
+
+VERSION = 2.0.0
+
+PREFIX ?= /usr/local
+
+LIBSOUNDPIPE = libsoundpipe.a
+
+ifndef CONFIG
+CONFIG = config.mk
+endif
+
+HPATHS += $(addprefix h/, $(addsuffix .h, $(MODULES)))
+MPATHS += $(addprefix modules/, $(addsuffix .o, $(MODULES)))
+
+include $(CONFIG)
+
+ifeq ($(USE_DOUBLE), 1)
+CFLAGS+=-DUSE_DOUBLE
+SPFLOAT=double
+else
+SPFLOAT=float
+endif
+
+CFLAGS += -DSP_VERSION=$(VERSION) -O3 -DSPFLOAT=${SPFLOAT}
+CFLAGS += -Ih -I/usr/local/include -fPIC
+CFLAGS += -I.
+CFLAGS += -Wall -pedantic
+UTIL += util/wav2smp
+
+C89=$(CC) -std=c89
+C99=$(CC) -std=c99
+
+libsoundpipe.a: $(MPATHS) $(LPATHS) $(TANGLED)
+	@echo "Creating $@"
+	@$(AR) rcs $@ $(MPATHS) $(LPATHS) $(TANGLED)
+
+h/soundpipe.h: $(HPATHS)
+	echo "#ifndef SOUNDPIPE_H" > $@
+ifdef USE_DOUBLE
+	echo "#define USE_DOUBLE" >> $@
+endif
+	echo "#define SOUNDPIPE_H" >> $@
+	cat $(HPATHS) >> $@
+	echo "#endif" >> $@
+
+h/sp_base.h: h/base.h
+	>$@
+	echo "#ifndef SOUNDPIPE_H" >> $@
+ifdef USE_DOUBLE
+	echo "#define USE_DOUBLE" >> $@
+endif
+	echo "#define SOUNDPIPE_H" >> $@
+	cat $< >> $@
+	echo "#endif" >> $@
+
+modules/%.o: modules/%.c h/soundpipe.h
+	$(C89) $(CFLAGS) -c -static $< -o $@
+
+tangled/%.o: %.c h/soundpipe.h
+	$(C89) $(CFLAGS) -c -static $< -o $@
+
+config.mk: config.def.mk
+	cp $< $@
+
+sp_dict.lua:
+	cat modules/data/*.lua > $@
+
+docs:
+	util/gendocs.sh
+
+all: config.mk libsoundpipe.a sp_dict.lua h/sp_base.h
+
+install: \
+	h/soundpipe.h \
+	h/sp_base.h \
+	libsoundpipe.a
+	install h/soundpipe.h /usr/local/include/
+	install h/sp_base.h /usr/local/include/
+	install libsoundpipe.a /usr/local/lib/
+
+clean:
+	$(RM) h/soundpipe.h
+	$(RM) -r docs
+	$(RM) libsoundpipe.a
+	$(RM) soundpipe.c
+	$(RM) sp_dict.lua
+	$(RM) $(LPATHS)
+	$(RM) $(MPATHS)
+	$(RM) $(TANGLED)
+	$(RM) h/sp_base.h
--- /dev/null
+++ b/README.md
@@ -1,0 +1,63 @@
+Soundpipe
+=========
+
+Soundpipe is a lightweight music DSP library written in C. It aims to provide
+a set of high-quality DSP modules for composers, sound designers,
+and creative coders.
+
+
+Compilation
+-----------
+
+To compile:
+
+make
+
+sudo make install
+
+
+Tests
+-----
+
+Tests in Soundpipe are used to determine whether or not modules behave as 
+expected. Tests write the output of a module to memory, and check the MD5 hash 
+value of the output against the MD5 value of a reference signal.
+
+To build a test file, go into the test folder, and run "make". Then, run 
+"./run.bin", which runs the tests. As the tests are run, an "ok" will appear in 
+the log if a test passes, and a "not ok" will appear if a test fails. 
+
+It is possible to hear the output of a particular test if you know the test 
+number. You will need to have sox installed. For example, 
+to hear what test 11 sounds like, run the following
+commands:
+
+./run.bin render 11
+
+./write_wave.sh 0011.raw
+
+This will generate a file called out.wav.
+
+The testing utility has a few optional arguments. To see all possible arguments,
+run "./run.bin help".
+
+The Soundpipe Model
+-------------------
+
+Soundpipe is callback driven. Every time Soundpipe needs a frame, it will
+call upon a single function specified by the user. Soundpipe modules are
+designed to process a signal one sample at a time.  Every module follows the
+same life cycle:
+
+1. Create: Memory is allocated for the data struct.
+2. Initialize: Buffers are allocated, and initial variables and constants
+are set.
+3. Compute: the module takes in inputs (if applicable), and generates a
+single sample of output.
+4. Destroy: All memory allocated is freed.
+
+Documentation
+-------------
+If you have lua installed on your computer, you can generate the current html
+documentation for soundpipe by running "make docs". A folder called "docs"
+will be created. The top page for the documentation is docs/index.html.
\ No newline at end of file
--- /dev/null
+++ b/config.def.mk
@@ -1,0 +1,130 @@
+MODULES= \
+base \
+ftbl \
+adsr \
+autowah \
+biscale \
+blsaw \
+blsquare \
+bltriangle \
+butlp \
+butbp \
+buthp \
+butbr \
+brown \
+clamp \
+clock \
+compressor \
+count \
+crossfade \
+delay \
+diode \
+dmetro \
+dtrig \
+expon \
+in \
+incr \
+jcrev \
+line \
+loadwav \
+lpc \
+maygate \
+metro \
+noise \
+nsmp \
+osc \
+paulstretch \
+peaklim \
+phaser \
+phasor \
+pinknoise \
+prop \
+pshift \
+randmt \
+random \
+randh \
+reverse \
+rpt \
+saturator \
+samphold \
+scale \
+scrambler \
+sdelay \
+slice \
+smoothdelay \
+smoother \
+spa \
+sparec \
+switch \
+tadsr \
+talkbox \
+tblrec \
+tdiv \
+tenv \
+tenv2 \
+tenvx \
+tgate \
+thresh \
+timer \
+tin \
+trand \
+tseg \
+tseq \
+voc \
+wavin \
+wavout \
+wpkorg35 \
+zitarev \
+bitcrush \
+bigverb \
+dcblocker \
+fmpair \
+rline \
+vardelay \
+peakeq \
+modalres \
+phasewarp \
+
+TANGLED += \
+tangled/osc.o \
+tangled/bigverb.o \
+tangled/dcblocker.o \
+tangled/fmpair.o \
+tangled/rline.o \
+tangled/vardelay.o \
+tangled/peakeq.o \
+tangled/modalres.o \
+tangled/phasewarp.o \
+
+NO_LIBSNDFILE=1
+CFLAGS += -DNO_LIBSNDFILE
+
+# ini parser needed for nsmp module
+include lib/inih/Makefile
+
+# Header files needed for modules generated with FAUST
+CFLAGS += -Ilib/faust
+
+# fft library
+include lib/fft/Makefile
+
+include lib/kissfft/Makefile
+MODULES += fftwrapper
+MODULES += padsynth
+
+# Uncomment to use FFTW3 instead of kissfft.
+# CFLAGS += -DUSE_FFTW3
+
+# Soundpipe audio
+include lib/spa/Makefile
+
+# openlpc
+include lib/openlpc/Makefile
+
+# drwav
+include lib/dr_wav/Makefile
+
+CFLAGS += -fPIC -g
+
+# Uncomment this to use double precision
+#USE_DOUBLE=1
--- /dev/null
+++ b/h/adsr.h
@@ -1,0 +1,19 @@
+typedef struct {
+    SPFLOAT atk;
+    SPFLOAT dec;
+    SPFLOAT sus;
+    SPFLOAT rel;
+    uint32_t timer;
+    uint32_t atk_time;
+    SPFLOAT a;
+    SPFLOAT b;
+    SPFLOAT y;
+    SPFLOAT x;
+    SPFLOAT prev;
+    int mode;
+} sp_adsr;
+
+int sp_adsr_create(sp_adsr **p);
+int sp_adsr_destroy(sp_adsr **p);
+int sp_adsr_init(sp_data *sp, sp_adsr *p);
+int sp_adsr_compute(sp_data *sp, sp_adsr *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/autowah.h
@@ -1,0 +1,13 @@
+typedef struct {
+    void *faust;
+    int argpos;
+    SPFLOAT *args[3];
+    SPFLOAT *level;
+    SPFLOAT *wah;
+    SPFLOAT *mix;
+} sp_autowah;
+
+int sp_autowah_create(sp_autowah **p);
+int sp_autowah_destroy(sp_autowah **p);
+int sp_autowah_init(sp_data *sp, sp_autowah *p);
+int sp_autowah_compute(sp_data *sp, sp_autowah *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/base.h
@@ -1,0 +1,97 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#define SP_BUFSIZE 4096
+#ifndef SPFLOAT
+#define SPFLOAT float
+#endif
+#define SP_OK 1
+#define SP_NOT_OK 0
+
+#define SP_RANDMAX 2147483648
+
+typedef unsigned long sp_frame;
+
+typedef struct sp_auxdata {
+    size_t size;
+    void *ptr;
+} sp_auxdata;
+
+typedef struct sp_data {
+    SPFLOAT *out;
+    int sr;
+    int nchan;
+    unsigned long len;
+    unsigned long pos;
+    char filename[200];
+    uint32_t rand;
+} sp_data;
+
+typedef struct {
+    char state;
+    SPFLOAT val;
+} sp_param;
+
+int sp_auxdata_alloc(sp_auxdata *aux, size_t size);
+int sp_auxdata_free(sp_auxdata *aux);
+
+int sp_create(sp_data **spp);
+int sp_createn(sp_data **spp, int nchan);
+
+int sp_destroy(sp_data **spp);
+int sp_process(sp_data *sp, void *ud, void (*callback)(sp_data *, void *));
+int sp_process_raw(sp_data *sp, void *ud, void (*callback)(sp_data *, void *));
+int sp_process_plot(sp_data *sp, void *ud, void (*callback)(sp_data *, void *));
+int sp_process_spa(sp_data *sp, void *ud, void (*callback)(sp_data *, void *));
+
+SPFLOAT sp_midi2cps(SPFLOAT nn);
+
+int sp_set(sp_param *p, SPFLOAT val);
+
+int sp_out(sp_data *sp, uint32_t chan, SPFLOAT val);
+
+uint32_t sp_rand(sp_data *sp);
+void sp_srand(sp_data *sp, uint32_t val);
+
+
+typedef struct {
+    SPFLOAT *utbl;
+    int16_t *BRLow;
+    int16_t *BRLowCpx;
+} sp_fft;
+
+void sp_fft_create(sp_fft **fft);
+void sp_fft_init(sp_fft *fft, int M);
+void sp_fftr(sp_fft *fft, SPFLOAT *buf, int FFTsize);
+void sp_fft_cpx(sp_fft *fft, SPFLOAT *buf, int FFTsize);
+void sp_ifftr(sp_fft *fft, SPFLOAT *buf, int FFTsize);
+void sp_fft_destroy(sp_fft *fft);
+#ifndef kiss_fft_scalar
+#define kiss_fft_scalar SPFLOAT
+#endif
+typedef struct {
+    kiss_fft_scalar r;
+    kiss_fft_scalar i;
+}kiss_fft_cpx;
+
+typedef struct kiss_fft_state* kiss_fft_cfg;
+typedef struct kiss_fftr_state* kiss_fftr_cfg;
+
+/* SPA: Soundpipe Audio */
+
+enum { SPA_READ, SPA_WRITE, SPA_NULL };
+
+typedef struct {
+    char magic;
+    char nchan;
+    uint16_t sr;
+    uint32_t len;
+} spa_header;
+
+typedef struct {
+    spa_header header;
+    size_t offset;
+    int mode;
+    FILE *fp;
+    uint32_t pos;
+} sp_audio;
--- /dev/null
+++ b/h/bigverb.h
@@ -1,0 +1,18 @@
+#ifndef SK_BIGVERB_H
+typedef struct sk_bigverb sk_bigverb;
+#endif
+
+typedef struct {
+    SPFLOAT feedback, lpfreq;
+    sk_bigverb *bv;
+} sp_bigverb;
+
+int sp_bigverb_create(sp_bigverb **p);
+int sp_bigverb_destroy(sp_bigverb **p);
+int sp_bigverb_init(sp_data *sp, sp_bigverb *p);
+int sp_bigverb_compute(sp_data *sp,
+                       sp_bigverb *p,
+                       SPFLOAT *in1,
+                       SPFLOAT *in2,
+                       SPFLOAT *out1,
+                       SPFLOAT *out2);
--- /dev/null
+++ b/h/biscale.h
@@ -1,0 +1,8 @@
+typedef struct {
+    SPFLOAT min, max;
+} sp_biscale;
+
+int sp_biscale_create(sp_biscale **p);
+int sp_biscale_destroy(sp_biscale **p);
+int sp_biscale_init(sp_data *sp, sp_biscale *p);
+int sp_biscale_compute(sp_data *sp, sp_biscale *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/bitcrush.h
@@ -1,0 +1,14 @@
+typedef struct {
+    SPFLOAT bitdepth;
+    SPFLOAT srate;
+
+    SPFLOAT incr;
+    SPFLOAT index;
+    int32_t sample_index;
+    SPFLOAT value;
+} sp_bitcrush;
+
+int sp_bitcrush_create(sp_bitcrush **p);
+int sp_bitcrush_destroy(sp_bitcrush **p);
+int sp_bitcrush_init(sp_data *sp, sp_bitcrush *p);
+int sp_bitcrush_compute(sp_data *sp, sp_bitcrush *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/blsaw.h
@@ -1,0 +1,12 @@
+typedef struct {
+    void *ud;
+    int argpos;
+    SPFLOAT *args[2];
+    SPFLOAT *freq;
+    SPFLOAT *amp;
+} sp_blsaw;
+
+int sp_blsaw_create(sp_blsaw **p);
+int sp_blsaw_destroy(sp_blsaw **p);
+int sp_blsaw_init(sp_data *sp, sp_blsaw *p);
+int sp_blsaw_compute(sp_data *sp, sp_blsaw *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/blsquare.h
@@ -1,0 +1,13 @@
+typedef struct {
+    void *ud;
+    int argpos;
+    SPFLOAT *args[3];
+    SPFLOAT *freq;
+    SPFLOAT *amp;
+    SPFLOAT *width;
+} sp_blsquare;
+
+int sp_blsquare_create(sp_blsquare **p);
+int sp_blsquare_destroy(sp_blsquare **p);
+int sp_blsquare_init(sp_data *sp, sp_blsquare *p);
+int sp_blsquare_compute(sp_data *sp, sp_blsquare *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/bltriangle.h
@@ -1,0 +1,12 @@
+typedef struct {
+    void *ud;
+    int argpos;
+    SPFLOAT *args[2];
+    SPFLOAT *freq;
+    SPFLOAT *amp;
+} sp_bltriangle;
+
+int sp_bltriangle_create(sp_bltriangle **p);
+int sp_bltriangle_destroy(sp_bltriangle **p);
+int sp_bltriangle_init(sp_data *sp, sp_bltriangle *p);
+int sp_bltriangle_compute(sp_data *sp, sp_bltriangle *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/brown.h
@@ -1,0 +1,8 @@
+typedef struct {
+    SPFLOAT brown;
+} sp_brown;
+
+int sp_brown_create(sp_brown **p);
+int sp_brown_destroy(sp_brown **p);
+int sp_brown_init(sp_data *sp, sp_brown *p);
+int sp_brown_compute(sp_data *sp, sp_brown *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/butbp.h
@@ -1,0 +1,11 @@
+typedef struct {
+    SPFLOAT freq, bw;
+    SPFLOAT lfreq, lbw;
+    SPFLOAT a[7];
+    SPFLOAT pidsr, tpidsr;
+} sp_butbp;
+
+int sp_butbp_create(sp_butbp **p);
+int sp_butbp_destroy(sp_butbp **p);
+int sp_butbp_init(sp_data *sp, sp_butbp *p);
+int sp_butbp_compute(sp_data *sp, sp_butbp *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/butbr.h
@@ -1,0 +1,11 @@
+typedef struct {
+    SPFLOAT freq, bw;
+    SPFLOAT lfreq, lbw;
+    SPFLOAT a[7];
+    SPFLOAT pidsr, tpidsr;
+} sp_butbr;
+
+int sp_butbr_create(sp_butbr **p);
+int sp_butbr_destroy(sp_butbr **p);
+int sp_butbr_init(sp_data *sp, sp_butbr *p);
+int sp_butbr_compute(sp_data *sp, sp_butbr *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/buthp.h
@@ -1,0 +1,11 @@
+typedef struct  {
+    SPFLOAT freq;
+    SPFLOAT lfreq;
+    SPFLOAT a[7];
+    SPFLOAT pidsr;
+} sp_buthp;
+
+int sp_buthp_create(sp_buthp **p);
+int sp_buthp_destroy(sp_buthp **p);
+int sp_buthp_init(sp_data *sp, sp_buthp *p);
+int sp_buthp_compute(sp_data *sp, sp_buthp *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/butlp.h
@@ -1,0 +1,11 @@
+typedef struct  {
+    SPFLOAT sr, freq;
+    SPFLOAT lfreq;
+    SPFLOAT a[7];
+    SPFLOAT pidsr;
+} sp_butlp;
+
+int sp_butlp_create(sp_butlp **p);
+int sp_butlp_destroy(sp_butlp **p);
+int sp_butlp_init(sp_data *sp, sp_butlp *p);
+int sp_butlp_compute(sp_data *sp, sp_butlp *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/clamp.h
@@ -1,0 +1,9 @@
+typedef struct {
+    SPFLOAT min;
+    SPFLOAT max;
+} sp_clamp;
+
+int sp_clamp_create(sp_clamp **p);
+int sp_clamp_destroy(sp_clamp **p);
+int sp_clamp_init(sp_data *sp, sp_clamp *p);
+int sp_clamp_compute(sp_data *sp, sp_clamp *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/clock.h
@@ -1,0 +1,10 @@
+typedef struct {
+    SPFLOAT bpm;
+    SPFLOAT subdiv;
+    uint32_t counter;
+} sp_clock;
+
+int sp_clock_create(sp_clock **p);
+int sp_clock_destroy(sp_clock **p);
+int sp_clock_init(sp_data *sp, sp_clock *p);
+int sp_clock_compute(sp_data *sp, sp_clock *p, SPFLOAT *trig, SPFLOAT *out);
--- /dev/null
+++ b/h/compressor.h
@@ -1,0 +1,14 @@
+typedef struct {
+    void *faust;
+    int argpos;
+    SPFLOAT *args[4];
+    SPFLOAT *ratio;
+    SPFLOAT *thresh;
+    SPFLOAT *atk;
+    SPFLOAT *rel;
+} sp_compressor;
+
+int sp_compressor_create(sp_compressor **p);
+int sp_compressor_destroy(sp_compressor **p);
+int sp_compressor_init(sp_data *sp, sp_compressor *p);
+int sp_compressor_compute(sp_data *sp, sp_compressor *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/count.h
@@ -1,0 +1,9 @@
+typedef struct sp_count{
+    int32_t count, curcount;
+    int mode;
+} sp_count;
+
+int sp_count_create(sp_count **p);
+int sp_count_destroy(sp_count **p);
+int sp_count_init(sp_data *sp, sp_count *p);
+int sp_count_compute(sp_data *sp, sp_count *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/crossfade.h
@@ -1,0 +1,8 @@
+typedef struct {
+    SPFLOAT pos;
+} sp_crossfade;
+
+int sp_crossfade_create(sp_crossfade **p);
+int sp_crossfade_destroy(sp_crossfade **p);
+int sp_crossfade_init(sp_data *sp, sp_crossfade *p);
+int sp_crossfade_compute(sp_data *sp, sp_crossfade *p, SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out);
--- /dev/null
+++ b/h/dcblocker.h
@@ -1,0 +1,13 @@
+#ifndef SK_DCBLOCKER_H
+typedef struct sk_dcblocker sk_dcblocker;
+#endif
+
+typedef struct {
+    sk_dcblocker *dcblocker;
+} sp_dcblocker;
+
+int sp_dcblocker_create(sp_dcblocker **p);
+int sp_dcblocker_destroy(sp_dcblocker **p);
+int sp_dcblocker_init(sp_data *sp, sp_dcblocker *p);
+int sp_dcblocker_compute(sp_data *sp, sp_dcblocker *p,
+                         SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/delay.h
@@ -1,0 +1,13 @@
+typedef struct {
+    SPFLOAT time;
+    SPFLOAT feedback;
+    SPFLOAT last;
+    sp_auxdata buf;
+    uint32_t bufsize;
+    uint32_t bufpos;
+} sp_delay;
+
+int sp_delay_create(sp_delay **p);
+int sp_delay_destroy(sp_delay **p);
+int sp_delay_init(sp_data *sp, sp_delay *p, SPFLOAT time);
+int sp_delay_compute(sp_data *sp, sp_delay *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/diode.h
@@ -1,0 +1,23 @@
+typedef struct {
+    /* 4 one-pole filters */
+    SPFLOAT opva_alpha[4];
+    SPFLOAT opva_beta[4];
+    SPFLOAT opva_gamma[4];
+    SPFLOAT opva_delta[4];
+    SPFLOAT opva_eps[4];
+    SPFLOAT opva_a0[4];
+    SPFLOAT opva_fdbk[4];
+    SPFLOAT opva_z1[4];
+    /* end one-pole filters */
+
+    SPFLOAT SG[4];
+    SPFLOAT gamma;
+    SPFLOAT freq;
+    SPFLOAT K;
+    SPFLOAT res;
+} sp_diode;
+
+int sp_diode_create(sp_diode **p);
+int sp_diode_destroy(sp_diode **p);
+int sp_diode_init(sp_data *sp, sp_diode *p);
+int sp_diode_compute(sp_data *sp, sp_diode *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/dmetro.h
@@ -1,0 +1,9 @@
+typedef struct {
+    SPFLOAT time;
+    uint32_t counter;
+} sp_dmetro;
+
+int sp_dmetro_create(sp_dmetro **p);
+int sp_dmetro_destroy(sp_dmetro **p);
+int sp_dmetro_init(sp_data *sp, sp_dmetro *p);
+int sp_dmetro_compute(sp_data *sp, sp_dmetro *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/dtrig.h
@@ -1,0 +1,14 @@
+typedef struct sp_dtrig{
+    sp_ftbl *ft;
+    uint32_t counter;
+    uint32_t pos;
+    int running;
+    int loop;
+    SPFLOAT delay;
+    SPFLOAT scale;
+} sp_dtrig;
+
+int sp_dtrig_create(sp_dtrig **p);
+int sp_dtrig_destroy(sp_dtrig **p);
+int sp_dtrig_init(sp_data *sp, sp_dtrig *p, sp_ftbl *ft);
+int sp_dtrig_compute(sp_data *sp, sp_dtrig *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/expon.h
@@ -1,0 +1,11 @@
+typedef struct {
+    SPFLOAT a, dur, b;
+    SPFLOAT val, incr;
+    uint32_t sdur, stime;
+    int init;
+} sp_expon;
+
+int sp_expon_create(sp_expon **p);
+int sp_expon_destroy(sp_expon **p);
+int sp_expon_init(sp_data *sp, sp_expon *p);
+int sp_expon_compute(sp_data *sp, sp_expon *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/fftwrapper.h
@@ -1,0 +1,31 @@
+#ifdef USE_FFTW3
+#include <fftw3.h>
+#endif
+
+#define fftw_real double
+#define rfftw_plan fftw_plan
+
+typedef struct FFTFREQS {
+    int size;
+    SPFLOAT *s,*c;
+} FFTFREQS;
+
+typedef struct {
+    int fftsize;
+#ifdef USE_FFTW3
+    fftw_real *tmpfftdata1, *tmpfftdata2;
+    rfftw_plan planfftw,planfftw_inv;
+#else
+    kiss_fftr_cfg fft, ifft;
+    kiss_fft_cpx *tmp1, *tmp2;
+#endif
+} FFTwrapper;
+
+void FFTwrapper_create(FFTwrapper **fw, int fftsize);
+void FFTwrapper_destroy(FFTwrapper **fw);
+
+void newFFTFREQS(FFTFREQS *f, int size);
+void deleteFFTFREQS(FFTFREQS *f);
+
+void smps2freqs(FFTwrapper *ft, SPFLOAT *smps, FFTFREQS *freqs);
+void freqs2smps(FFTwrapper *ft, FFTFREQS *freqs, SPFLOAT *smps);
--- /dev/null
+++ b/h/fmpair.h
@@ -1,0 +1,14 @@
+#ifndef SK_FMPAIR_H
+typedef struct sk_fmpair sk_fmpair;
+#endif
+
+typedef struct {
+    SPFLOAT amp, freq, car, mod, indx;
+    sk_fmpair *fmpair;
+} sp_fmpair;
+
+int sp_fmpair_create(sp_fmpair **p);
+int sp_fmpair_destroy(sp_fmpair **p);
+int sp_fmpair_init(sp_data *sp, sp_fmpair *p, sp_ftbl *ft);
+int sp_fmpair_compute(sp_data *sp, sp_fmpair *p,
+                      SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/foo.h
@@ -1,0 +1,8 @@
+typedef struct {
+    SPFLOAT bar;
+} sp_foo;
+
+int sp_foo_create(sp_foo **p);
+int sp_foo_destroy(sp_foo **p);
+int sp_foo_init(sp_data *sp, sp_foo *p);
+int sp_foo_compute(sp_data *sp, sp_foo *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/ftbl.h
@@ -1,0 +1,21 @@
+#define SP_FT_MAXLEN 0x1000000L
+#define SP_FT_PHMASK 0x0FFFFFFL
+
+typedef struct sp_ftbl{
+    size_t size;
+    SPFLOAT *tbl;
+    /* uint32_t lobits; */
+    /* uint32_t lomask; */
+    /* SPFLOAT lodiv; */
+    /* SPFLOAT sicvt; */
+    /* char del; */
+} sp_ftbl;
+
+int sp_ftbl_create(sp_data *sp, sp_ftbl **ft, size_t size);
+int sp_ftbl_init(sp_data *sp, sp_ftbl *ft, size_t size);
+int sp_ftbl_bind(sp_data *sp, sp_ftbl **ft, SPFLOAT *tbl, size_t size);
+int sp_ftbl_destroy(sp_ftbl **ft);
+int sp_ftbl_loadfile(sp_data *sp, sp_ftbl **ft, const char *filename);
+int sp_ftbl_loadspa(sp_data *sp, sp_ftbl **ft, const char *filename);
+int sp_gen_vals(sp_data *sp, sp_ftbl *ft, const char *string);
+int sp_gen_sine(sp_data *sp, sp_ftbl *ft);
--- /dev/null
+++ b/h/in.h
@@ -1,0 +1,8 @@
+typedef struct {
+    FILE *fp;
+} sp_in;
+
+int sp_in_create(sp_in **p);
+int sp_in_destroy(sp_in **p);
+int sp_in_init(sp_data *sp, sp_in *p);
+int sp_in_compute(sp_data *sp, sp_in *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/incr.h
@@ -1,0 +1,11 @@
+typedef struct {
+    SPFLOAT step;
+    SPFLOAT min;
+    SPFLOAT max;
+    SPFLOAT val;
+} sp_incr;
+
+int sp_incr_create(sp_incr **p);
+int sp_incr_destroy(sp_incr **p);
+int sp_incr_init(sp_data *sp, sp_incr *p, SPFLOAT val);
+int sp_incr_compute(sp_data *sp, sp_incr *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/jack.h
@@ -1,0 +1,1 @@
+int sp_jack_process(sp_data *sp, void *ud, void (*callback)(sp_data *, void *));
--- /dev/null
+++ b/h/jcrev.h
@@ -1,0 +1,8 @@
+typedef struct {
+    void *ud;
+} sp_jcrev;
+
+int sp_jcrev_create(sp_jcrev **p);
+int sp_jcrev_destroy(sp_jcrev **p);
+int sp_jcrev_init(sp_data *sp, sp_jcrev *p);
+int sp_jcrev_compute(sp_data *sp, sp_jcrev *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/line.h
@@ -1,0 +1,11 @@
+typedef struct {
+    SPFLOAT a, dur, b;
+    SPFLOAT val, incr;
+    uint32_t sdur, stime;
+    int init;
+} sp_line;
+
+int sp_line_create(sp_line **p);
+int sp_line_destroy(sp_line **p);
+int sp_line_init(sp_data *sp, sp_line *p);
+int sp_line_compute(sp_data *sp, sp_line *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/loadwav.h
@@ -1,0 +1,1 @@
+int sp_ftbl_loadwav(sp_data *sp, sp_ftbl **ft, const char *filename);
--- /dev/null
+++ b/h/lpc.h
@@ -1,0 +1,26 @@
+typedef struct {
+    struct openlpc_e_state *e;
+    struct openlpc_d_state *d;
+    int counter;
+    short *in;
+    short *out;
+    unsigned char data[7];
+    SPFLOAT y[7];
+    SPFLOAT smooth;
+    SPFLOAT samp;
+    unsigned int clock;
+    unsigned int block;
+    int framesize;
+    sp_auxdata m_in;
+    sp_auxdata m_out;
+    sp_auxdata m_e;
+    sp_auxdata m_d;
+    int mode;
+    sp_ftbl *ft;
+} sp_lpc;
+
+int sp_lpc_create(sp_lpc **lpc);
+int sp_lpc_destroy(sp_lpc **lpc);
+int sp_lpc_init(sp_data *sp, sp_lpc *lpc, int framesize);
+int sp_lpc_synth(sp_data *sp, sp_lpc *lpc, sp_ftbl *ft);
+int sp_lpc_compute(sp_data *sp, sp_lpc *lpc, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/maygate.h
@@ -1,0 +1,10 @@
+typedef struct sp_maygate{
+    SPFLOAT prob;
+    SPFLOAT gate;
+    int mode;
+} sp_maygate;
+
+int sp_maygate_create(sp_maygate **p);
+int sp_maygate_destroy(sp_maygate **p);
+int sp_maygate_init(sp_data *sp, sp_maygate *p);
+int sp_maygate_compute(sp_data *sp, sp_maygate *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/metro.h
@@ -1,0 +1,11 @@
+typedef struct sp_metro{
+    SPFLOAT freq;
+    SPFLOAT phs;
+    int init;
+    SPFLOAT onedsr;
+} sp_metro;
+
+int sp_metro_create(sp_metro **p);
+int sp_metro_destroy(sp_metro **p);
+int sp_metro_init(sp_data *sp, sp_metro *p);
+int sp_metro_compute(sp_data *sp, sp_metro *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/modalres.h
@@ -1,0 +1,14 @@
+#ifndef SK_MODALRES_H
+typedef struct sk_modalres sk_modalres;
+#endif
+
+typedef struct {
+    SPFLOAT freq, q;
+    sk_modalres *modalres;
+} sp_modalres;
+
+int sp_modalres_create(sp_modalres **p);
+int sp_modalres_destroy(sp_modalres **p);
+int sp_modalres_init(sp_data *sp, sp_modalres *p);
+int sp_modalres_compute(sp_data *sp, sp_modalres *p,
+                      SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/noise.h
@@ -1,0 +1,8 @@
+typedef struct{
+    SPFLOAT amp;
+}sp_noise;
+
+int sp_noise_create(sp_noise **ns);
+int sp_noise_init(sp_data *sp, sp_noise *ns);
+int sp_noise_compute(sp_data *sp, sp_noise *ns, SPFLOAT *in, SPFLOAT *out);
+int sp_noise_destroy(sp_noise **ns);
--- /dev/null
+++ b/h/nsmp.h
@@ -1,0 +1,38 @@
+typedef struct nano_entry {
+    char name[50];
+    uint32_t pos;
+    uint32_t size;
+    SPFLOAT speed;
+    struct nano_entry *next;
+} nano_entry;
+
+typedef struct {
+    int nval;
+    int init;
+    nano_entry root;
+    nano_entry *last;
+} nano_dict;
+
+typedef struct {
+    char ini[100];
+    SPFLOAT curpos;
+    nano_dict dict;
+    int selected;
+    nano_entry *sample;
+    nano_entry **index;
+    sp_ftbl *ft;
+    int sr;
+} nanosamp;
+
+typedef struct {
+    nanosamp *smp;
+    uint32_t index;
+    int triggered;
+} sp_nsmp;
+
+int sp_nsmp_create(sp_nsmp **p);
+int sp_nsmp_destroy(sp_nsmp **p);
+int sp_nsmp_init(sp_data *sp, sp_nsmp *p, sp_ftbl *ft, int sr, const char *ini);
+int sp_nsmp_compute(sp_data *sp, sp_nsmp *p, SPFLOAT *in, SPFLOAT *out);
+
+int sp_nsmp_print_index(sp_data *sp, sp_nsmp *p);
--- /dev/null
+++ b/h/osc.h
@@ -1,0 +1,13 @@
+#ifndef SK_OSC_H
+typedef struct sk_osc sk_osc;
+#endif
+
+typedef struct {
+    SPFLOAT freq, amp, iphs;
+    sk_osc *osc;
+} sp_osc;
+
+int sp_osc_create(sp_osc **osc);
+int sp_osc_destroy(sp_osc **osc);
+int sp_osc_init(sp_data *sp, sp_osc *osc, sp_ftbl *ft, SPFLOAT iphs);
+int sp_osc_compute(sp_data *sp, sp_osc *osc, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/oscmorph.h
@@ -1,0 +1,13 @@
+typedef struct {
+    SPFLOAT freq, amp, iphs;
+    int32_t lphs;
+    sp_ftbl **tbl;
+    int inc;
+    SPFLOAT wtpos;
+    int nft;
+} sp_oscmorph;
+
+int sp_oscmorph_create(sp_oscmorph **p);
+int sp_oscmorph_destroy(sp_oscmorph **p);
+int sp_oscmorph_init(sp_data *sp, sp_oscmorph *osc, sp_ftbl **ft, int nft, SPFLOAT iphs);
+int sp_oscmorph_compute(sp_data *sp, sp_oscmorph *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/padsynth.h
@@ -1,0 +1,14 @@
+typedef struct sp_padsynth {
+    SPFLOAT cps;
+    SPFLOAT bw;
+    sp_ftbl *amps;
+} sp_padsynth;
+
+int sp_gen_padsynth(sp_data *sp, sp_ftbl *ps, sp_ftbl *amps, SPFLOAT f, SPFLOAT bw);
+
+SPFLOAT sp_padsynth_profile(SPFLOAT fi, SPFLOAT bwi);
+
+int sp_padsynth_ifft(int N, SPFLOAT *freq_amp,
+        SPFLOAT *freq_phase, SPFLOAT *smp);
+
+int sp_padsynth_normalize(int N, SPFLOAT *smp);
--- /dev/null
+++ b/h/paulstretch.h
@@ -1,0 +1,27 @@
+typedef struct {
+    uint32_t windowsize;
+    uint32_t half_windowsize;
+    SPFLOAT stretch;
+    SPFLOAT start_pos;
+    SPFLOAT displace_pos;
+    SPFLOAT *window;
+    SPFLOAT *old_windowed_buf;
+    SPFLOAT *hinv_buf;
+    SPFLOAT *buf;
+    SPFLOAT *output;
+    sp_ftbl *ft;
+    kiss_fftr_cfg fft, ifft;
+    kiss_fft_cpx *tmp1, *tmp2;
+    uint32_t counter;
+    sp_auxdata m_window;
+    sp_auxdata m_old_windowed_buf;
+    sp_auxdata m_hinv_buf;
+    sp_auxdata m_buf;
+    sp_auxdata m_output;
+    unsigned char wrap;
+} sp_paulstretch;
+
+int sp_paulstretch_create(sp_paulstretch **p);
+int sp_paulstretch_destroy(sp_paulstretch **p);
+int sp_paulstretch_init(sp_data *sp, sp_paulstretch *p, sp_ftbl *ft, SPFLOAT windowsize, SPFLOAT stretch);
+int sp_paulstretch_compute(sp_data *sp, sp_paulstretch *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/peakeq.h
@@ -1,0 +1,14 @@
+#ifndef SK_PEAKEQ_H
+typedef struct sk_peakeq sk_peakeq;
+#endif
+
+typedef struct {
+    SPFLOAT freq, bw, gain;
+    sk_peakeq *peakeq;
+} sp_peakeq;
+
+int sp_peakeq_create(sp_peakeq **p);
+int sp_peakeq_destroy(sp_peakeq **p);
+int sp_peakeq_init(sp_data *sp, sp_peakeq *p);
+int sp_peakeq_compute(sp_data *sp, sp_peakeq *p,
+                      SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/peaklim.h
@@ -1,0 +1,10 @@
+typedef struct {
+    SPFLOAT atk, rel, thresh;
+    SPFLOAT patk, prel;
+	SPFLOAT b0_r, a1_r, b0_a, a1_a, level;
+} sp_peaklim;
+
+int sp_peaklim_create(sp_peaklim **p);
+int sp_peaklim_destroy(sp_peaklim **p);
+int sp_peaklim_init(sp_data *sp, sp_peaklim *p);
+int sp_peaklim_compute(sp_data *sp, sp_peaklim *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/phaser.h
@@ -1,0 +1,21 @@
+typedef struct {
+    void *faust;
+    int argpos;
+    SPFLOAT *args[10];
+    SPFLOAT *MaxNotch1Freq;
+    SPFLOAT *MinNotch1Freq;
+    SPFLOAT *Notch_width;
+    SPFLOAT *NotchFreq;
+    SPFLOAT *VibratoMode;
+    SPFLOAT *depth;
+    SPFLOAT *feedback_gain;
+    SPFLOAT *invert;
+    SPFLOAT *level;
+    SPFLOAT *lfobpm;
+} sp_phaser;
+
+int sp_phaser_create(sp_phaser **p);
+int sp_phaser_destroy(sp_phaser **p);
+int sp_phaser_init(sp_data *sp, sp_phaser *p);
+int sp_phaser_compute(sp_data *sp, sp_phaser *p,
+	SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out1, SPFLOAT *out2);
--- /dev/null
+++ b/h/phasewarp.h
@@ -1,0 +1,13 @@
+#ifndef SK_PHASEWARP_H
+typedef struct sk_phasewarp sk_phasewarp;
+#endif
+
+typedef struct {
+    SPFLOAT amount;
+} sp_phasewarp;
+
+int sp_phasewarp_create(sp_phasewarp **p);
+int sp_phasewarp_destroy(sp_phasewarp **p);
+int sp_phasewarp_init(sp_data *sp, sp_phasewarp *p);
+int sp_phasewarp_compute(sp_data *sp, sp_phasewarp *p,
+                      SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/phasor.h
@@ -1,0 +1,9 @@
+typedef struct sp_phasor{
+    SPFLOAT freq, phs;
+    SPFLOAT onedsr;
+} sp_phasor;
+
+int sp_phasor_create(sp_phasor **p);
+int sp_phasor_destroy(sp_phasor **p);
+int sp_phasor_init(sp_data *sp, sp_phasor *p, SPFLOAT iphs);
+int sp_phasor_compute(sp_data *sp, sp_phasor *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/pinknoise.h
@@ -1,0 +1,15 @@
+typedef struct {
+    SPFLOAT amp;
+    unsigned int newrand;
+    unsigned int prevrand;
+    unsigned int k;
+    unsigned int seed;
+    unsigned int total;
+    uint32_t counter;
+    unsigned int dice[7];
+} sp_pinknoise;
+
+int sp_pinknoise_create(sp_pinknoise **p);
+int sp_pinknoise_destroy(sp_pinknoise **p);
+int sp_pinknoise_init(sp_data *sp, sp_pinknoise *p);
+int sp_pinknoise_compute(sp_data *sp, sp_pinknoise *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/prop.h
@@ -1,0 +1,59 @@
+typedef struct {
+    char type;
+    uint32_t pos;
+    uint32_t val;
+    uint32_t cons;
+} prop_event;
+
+typedef struct {
+    char type;
+    void *ud;
+} prop_val;
+
+typedef struct prop_entry {
+    prop_val val;
+    struct prop_entry *next;
+} prop_entry;
+
+typedef struct prop_list {
+    prop_entry root;
+    prop_entry *last;
+    uint32_t size;
+    uint32_t pos;
+    struct prop_list *top;
+    uint32_t lvl;
+} prop_list;
+
+typedef struct {
+    uint32_t stack[16];
+    int pos;
+} prop_stack;
+
+typedef struct {
+    uint32_t mul;
+    uint32_t div;
+    uint32_t tmp;
+    uint32_t cons_mul;
+    uint32_t cons_div;
+    SPFLOAT scale;
+    int mode;
+    uint32_t pos;
+    prop_list top;
+    prop_list *main;
+    prop_stack mstack;
+    prop_stack cstack;
+} prop_data;
+
+typedef struct {
+   prop_data *prp;
+   prop_event evt;
+   uint32_t count;
+   SPFLOAT bpm;
+   SPFLOAT lbpm;
+} sp_prop;
+
+int sp_prop_create(sp_prop **p);
+int sp_prop_destroy(sp_prop **p);
+int sp_prop_reset(sp_data *sp, sp_prop *p);
+int sp_prop_init(sp_data *sp, sp_prop *p, const char *str);
+int sp_prop_compute(sp_data *sp, sp_prop *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/pshift.h
@@ -1,0 +1,13 @@
+typedef struct {
+    void *faust;
+    int argpos;
+    SPFLOAT *args[3];
+    SPFLOAT *shift;
+    SPFLOAT *window;
+    SPFLOAT *xfade;
+} sp_pshift;
+
+int sp_pshift_create(sp_pshift **p);
+int sp_pshift_destroy(sp_pshift **p);
+int sp_pshift_init(sp_data *sp, sp_pshift *p);
+int sp_pshift_compute(sp_data *sp, sp_pshift *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/randh.h
@@ -1,0 +1,11 @@
+typedef struct {
+    SPFLOAT freq;
+    SPFLOAT min, max;
+    SPFLOAT val;
+    uint32_t counter, dur;
+} sp_randh;
+
+int sp_randh_create(sp_randh **p);
+int sp_randh_destroy(sp_randh **p);
+int sp_randh_init(sp_data *sp, sp_randh *p);
+int sp_randh_compute(sp_data *sp, sp_randh *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/randmt.h
@@ -1,0 +1,10 @@
+typedef struct {
+    int mti;
+    /* do not change value 624 */
+    uint32_t mt[624];
+} sp_randmt;
+
+void sp_randmt_seed(sp_randmt *p,
+    const uint32_t *initKey, uint32_t keyLength);
+
+uint32_t sp_randmt_compute(sp_randmt *p);
--- /dev/null
+++ b/h/random.h
@@ -1,0 +1,9 @@
+typedef struct {
+    SPFLOAT min;
+    SPFLOAT max;
+} sp_random;
+
+int sp_random_create(sp_random **p);
+int sp_random_destroy(sp_random **p);
+int sp_random_init(sp_data *sp, sp_random *p);
+int sp_random_compute(sp_data *sp, sp_random *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/reverse.h
@@ -1,0 +1,11 @@
+typedef struct  {
+    SPFLOAT delay;
+    uint32_t bufpos;
+    uint32_t bufsize;
+    sp_auxdata buf;
+} sp_reverse;
+
+int sp_reverse_create(sp_reverse **p);
+int sp_reverse_destroy(sp_reverse **p);
+int sp_reverse_init(sp_data *sp, sp_reverse *p, SPFLOAT delay);
+int sp_reverse_compute(sp_data *sp, sp_reverse *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/rline.h
@@ -1,0 +1,14 @@
+#ifndef SK_RLINE_H
+typedef struct sk_rline sk_rline;
+#endif
+
+typedef struct {
+    SPFLOAT min, max, cps;
+    sk_rline *rline;
+} sp_rline;
+
+int sp_rline_create(sp_rline **p);
+int sp_rline_destroy(sp_rline **p);
+int sp_rline_init(sp_data *sp, sp_rline *p);
+int sp_rline_compute(sp_data *sp, sp_rline *p,
+                         SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/rpi.h
@@ -1,0 +1,6 @@
+typedef struct sp_rpi{
+    sp_data *sp;
+    void *ud;
+    void (*callback)(sp_data *, void *);
+}sp_rpi;
+int sp_rpi_process(sp_data *sp, void *ud, void (*callback)(sp_data *, void *));
--- /dev/null
+++ b/h/rpt.h
@@ -1,0 +1,18 @@
+typedef struct sp_rpt{
+    uint32_t playpos;
+    uint32_t bufpos;
+    int running;
+    int count, reps;
+    SPFLOAT sr;
+    uint32_t size;
+    SPFLOAT bpm;
+    int div, rep;
+    sp_auxdata aux;
+    int rc;
+} sp_rpt;
+
+int sp_rpt_create(sp_rpt **p);
+int sp_rpt_destroy(sp_rpt **p);
+int sp_rpt_init(sp_data *sp, sp_rpt *p, SPFLOAT maxdur);
+int sp_rpt_compute(sp_data *sp, sp_rpt *p, SPFLOAT *trig,
+        SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/samphold.h
@@ -1,0 +1,8 @@
+typedef struct {
+    SPFLOAT val;
+} sp_samphold;
+
+int sp_samphold_create(sp_samphold **p);
+int sp_samphold_destroy(sp_samphold **p);
+int sp_samphold_init(sp_data *sp, sp_samphold *p);
+int sp_samphold_compute(sp_data *sp, sp_samphold *p, SPFLOAT *trig, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/saturator.h
@@ -1,0 +1,15 @@
+typedef struct
+{
+    SPFLOAT drive;
+    SPFLOAT dcoffset;
+
+    SPFLOAT dcblocker[2][7];
+
+    SPFLOAT ai[6][7];
+    SPFLOAT aa[6][7];
+} sp_saturator;
+
+int sp_saturator_create(sp_saturator **p);
+int sp_saturator_destroy(sp_saturator **p);
+int sp_saturator_init(sp_data *sp, sp_saturator *p);
+int sp_saturator_compute(sp_data *sp, sp_saturator *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/scale.h
@@ -1,0 +1,8 @@
+typedef struct {
+    SPFLOAT min, max;
+} sp_scale;
+
+int sp_scale_create(sp_scale **p);
+int sp_scale_destroy(sp_scale **p);
+int sp_scale_init(sp_data *sp, sp_scale *p);
+int sp_scale_compute(sp_data *sp, sp_scale *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/scrambler.h
@@ -1,0 +1,1 @@
+int sp_gen_scrambler(sp_data *sp, sp_ftbl *src, sp_ftbl **dest);
--- /dev/null
+++ b/h/sdelay.h
@@ -1,0 +1,9 @@
+typedef struct {
+    int size, pos;
+    SPFLOAT *buf;
+} sp_sdelay;
+
+int sp_sdelay_create(sp_sdelay **p);
+int sp_sdelay_destroy(sp_sdelay **p);
+int sp_sdelay_init(sp_data *sp, sp_sdelay *p, int size);
+int sp_sdelay_compute(sp_data *sp, sp_sdelay *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/slice.h
@@ -1,0 +1,12 @@
+typedef struct {
+    sp_ftbl *vals;
+    sp_ftbl *buf;
+    uint32_t id;
+    uint32_t pos;
+    uint32_t nextpos;
+} sp_slice;
+
+int sp_slice_create(sp_slice **p);
+int sp_slice_destroy(sp_slice **p);
+int sp_slice_init(sp_data *sp, sp_slice *p, sp_ftbl *vals, sp_ftbl *buf);
+int sp_slice_compute(sp_data *sp, sp_slice *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/smoothdelay.h
@@ -1,0 +1,25 @@
+typedef struct {
+    SPFLOAT del, maxdel, pdel;
+    SPFLOAT sr;
+    SPFLOAT feedback;
+
+    int counter;
+    int maxcount;
+
+    uint32_t maxbuf;
+
+    sp_auxdata buf1;
+    uint32_t bufpos1;
+    uint32_t deltime1;
+
+    sp_auxdata buf2;
+    uint32_t bufpos2;
+    uint32_t deltime2;
+    int curbuf;
+} sp_smoothdelay;
+
+int sp_smoothdelay_create(sp_smoothdelay **p);
+int sp_smoothdelay_destroy(sp_smoothdelay **p);
+int sp_smoothdelay_init(sp_data *sp, sp_smoothdelay *p,
+        SPFLOAT maxdel, uint32_t interp);
+int sp_smoothdelay_compute(sp_data *sp, sp_smoothdelay *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/smoother.h
@@ -1,0 +1,11 @@
+typedef struct{
+    SPFLOAT smooth;
+    SPFLOAT a1, b0, y0, psmooth;
+    SPFLOAT onedsr;
+}sp_smoother;
+
+int sp_smoother_create(sp_smoother **p);
+int sp_smoother_destroy(sp_smoother **p);
+int sp_smoother_init(sp_data *sp, sp_smoother *p);
+int sp_smoother_compute(sp_data *sp, sp_smoother *p, SPFLOAT *in, SPFLOAT *out);
+int sp_smoother_reset(sp_data *sp, sp_smoother *p, SPFLOAT *in);
--- /dev/null
+++ b/h/spa.h
@@ -1,0 +1,12 @@
+typedef struct {
+    SPFLOAT *buf;
+    uint32_t pos;
+    uint32_t bufsize;
+    sp_audio spa;
+    sp_auxdata aux;
+} sp_spa;
+
+int sp_spa_create(sp_spa **p);
+int sp_spa_destroy(sp_spa **p);
+int sp_spa_init(sp_data *sp, sp_spa *p, const char *filename);
+int sp_spa_compute(sp_data *sp, sp_spa *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/sparec.h
@@ -1,0 +1,13 @@
+typedef struct {
+    SPFLOAT *buf;
+    uint32_t pos;
+    uint32_t bufsize;
+    sp_audio spa;
+    sp_auxdata aux;
+} sp_sparec;
+
+int sp_sparec_create(sp_sparec **p);
+int sp_sparec_destroy(sp_sparec **p);
+int sp_sparec_init(sp_data *sp, sp_sparec *p, const char *filename);
+int sp_sparec_compute(sp_data *sp, sp_sparec *p, SPFLOAT *in, SPFLOAT *out);
+int sp_sparec_close(sp_data *sp, sp_sparec *p);
--- /dev/null
+++ b/h/switch.h
@@ -1,0 +1,9 @@
+typedef struct {
+    SPFLOAT mode;
+} sp_switch;
+
+int sp_switch_create(sp_switch **p);
+int sp_switch_destroy(sp_switch **p);
+int sp_switch_init(sp_data *sp, sp_switch *p);
+int sp_switch_compute(sp_data *sp, sp_switch *p, SPFLOAT *trig,
+    SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out);
--- /dev/null
+++ b/h/tadsr.h
@@ -1,0 +1,20 @@
+typedef struct {
+    SPFLOAT value;
+    SPFLOAT target;
+    SPFLOAT rate;
+    int state;
+    SPFLOAT attackRate;
+    SPFLOAT decayRate;
+    SPFLOAT sustainLevel;
+    SPFLOAT releaseRate;
+    SPFLOAT atk;
+    SPFLOAT rel;
+    SPFLOAT sus;
+    SPFLOAT dec;
+    int mode;
+} sp_tadsr;
+
+int sp_tadsr_create(sp_tadsr **p);
+int sp_tadsr_destroy(sp_tadsr **p);
+int sp_tadsr_init(sp_data *sp, sp_tadsr *p);
+int sp_tadsr_compute(sp_data *sp, sp_tadsr *p, SPFLOAT *trig, SPFLOAT *out);
--- /dev/null
+++ b/h/talkbox.h
@@ -1,0 +1,23 @@
+
+#ifndef SP_TALKBOX_BUFMAX
+#define SP_TALKBOX_BUFMAX 1600
+#endif
+
+typedef struct {
+    SPFLOAT quality;
+    SPFLOAT d0, d1, d2, d3, d4;
+    SPFLOAT u0, u1, u2, u3, u4;
+    SPFLOAT FX;
+    SPFLOAT emphasis;
+    SPFLOAT car0[SP_TALKBOX_BUFMAX];
+    SPFLOAT car1[SP_TALKBOX_BUFMAX];
+    SPFLOAT window[SP_TALKBOX_BUFMAX];
+    SPFLOAT buf0[SP_TALKBOX_BUFMAX];
+    SPFLOAT buf1[SP_TALKBOX_BUFMAX];
+    uint32_t K, N, O, pos;
+} sp_talkbox;
+
+int sp_talkbox_create(sp_talkbox **p);
+int sp_talkbox_destroy(sp_talkbox **p);
+int sp_talkbox_init(sp_data *sp, sp_talkbox *p);
+int sp_talkbox_compute(sp_data *sp, sp_talkbox *p, SPFLOAT *src, SPFLOAT *exc, SPFLOAT *out);
--- /dev/null
+++ b/h/tblrec.h
@@ -1,0 +1,10 @@
+typedef struct {
+    sp_ftbl *ft;
+    uint32_t index;
+    int record;
+} sp_tblrec;
+
+int sp_tblrec_create(sp_tblrec **p);
+int sp_tblrec_destroy(sp_tblrec **p);
+int sp_tblrec_init(sp_data *sp, sp_tblrec *p, sp_ftbl *ft);
+int sp_tblrec_compute(sp_data *sp, sp_tblrec *p, SPFLOAT *in, SPFLOAT *trig, SPFLOAT *out);
--- /dev/null
+++ b/h/tdiv.h
@@ -1,0 +1,8 @@
+typedef struct {
+    uint32_t num, counter, offset;
+} sp_tdiv;
+
+int sp_tdiv_create(sp_tdiv **p);
+int sp_tdiv_destroy(sp_tdiv **p);
+int sp_tdiv_init(sp_data *sp, sp_tdiv *p);
+int sp_tdiv_compute(sp_data *sp, sp_tdiv *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/tenv.h
@@ -1,0 +1,14 @@
+typedef struct sp_tenv{
+    uint32_t pos, atk_end, rel_start, sr, totaldur;
+    SPFLOAT atk, rel, hold;
+    SPFLOAT atk_slp, rel_slp;
+    SPFLOAT last;
+    int sigmode;
+    SPFLOAT input;
+    int started;
+} sp_tenv;
+
+int sp_tenv_create(sp_tenv **p);
+int sp_tenv_destroy(sp_tenv **p);
+int sp_tenv_init(sp_data *sp, sp_tenv *p);
+int sp_tenv_compute(sp_data *sp, sp_tenv *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/tenv2.h
@@ -1,0 +1,13 @@
+typedef struct {
+    int state;
+    SPFLOAT atk, rel;
+    uint32_t totaltime;
+    uint32_t timer;
+    SPFLOAT slope;
+    SPFLOAT last;
+} sp_tenv2;
+
+int sp_tenv2_create(sp_tenv2 **p);
+int sp_tenv2_destroy(sp_tenv2 **p);
+int sp_tenv2_init(sp_data *sp, sp_tenv2 *p);
+int sp_tenv2_compute(sp_data *sp, sp_tenv2 *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/tenvx.h
@@ -1,0 +1,13 @@
+typedef struct sp_tenvx{
+    SPFLOAT atk, rel, hold;
+    SPFLOAT patk, prel;
+    uint32_t count;
+    SPFLOAT a_a, b_a;
+    SPFLOAT a_r, b_r;
+    SPFLOAT y;
+} sp_tenvx;
+
+int sp_tenvx_create(sp_tenvx **p);
+int sp_tenvx_destroy(sp_tenvx **p);
+int sp_tenvx_init(sp_data *sp, sp_tenvx *p);
+int sp_tenvx_compute(sp_data *sp, sp_tenvx *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/tgate.h
@@ -1,0 +1,9 @@
+typedef struct {
+    SPFLOAT time;
+    uint32_t timer;
+} sp_tgate;
+
+int sp_tgate_create(sp_tgate **p);
+int sp_tgate_destroy(sp_tgate **p);
+int sp_tgate_init(sp_data *sp, sp_tgate *p);
+int sp_tgate_compute(sp_data *sp, sp_tgate *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/thresh.h
@@ -1,0 +1,9 @@
+typedef struct {
+    int init;
+    SPFLOAT prev, thresh, mode;
+} sp_thresh;
+
+int sp_thresh_create(sp_thresh **p);
+int sp_thresh_destroy(sp_thresh **p);
+int sp_thresh_init(sp_data *sp, sp_thresh *p);
+int sp_thresh_compute(sp_data *sp, sp_thresh *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/timer.h
@@ -1,0 +1,10 @@
+typedef struct {
+    int mode;
+    uint32_t pos;
+    SPFLOAT time;
+} sp_timer;
+
+int sp_timer_create(sp_timer **p);
+int sp_timer_destroy(sp_timer **p);
+int sp_timer_init(sp_data *sp, sp_timer *p);
+int sp_timer_compute(sp_data *sp, sp_timer *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/tin.h
@@ -1,0 +1,9 @@
+typedef struct {
+    FILE *fp;
+    SPFLOAT val;
+} sp_tin;
+
+int sp_tin_create(sp_tin **p);
+int sp_tin_destroy(sp_tin **p);
+int sp_tin_init(sp_data *sp, sp_tin *p);
+int sp_tin_compute(sp_data *sp, sp_tin *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/trand.h
@@ -1,0 +1,8 @@
+typedef struct {
+    SPFLOAT min, max, val;
+} sp_trand;
+
+int sp_trand_create(sp_trand **p);
+int sp_trand_destroy(sp_trand **p);
+int sp_trand_init(sp_data *sp, sp_trand *p);
+int sp_trand_compute(sp_data *sp, sp_trand *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/tseg.h
@@ -1,0 +1,14 @@
+typedef struct {
+    SPFLOAT beg,dur,end;
+    uint32_t steps;
+    uint32_t count;
+    SPFLOAT val;
+    SPFLOAT type;
+    SPFLOAT slope;
+    SPFLOAT tdivnsteps;
+} sp_tseg;
+
+int sp_tseg_create(sp_tseg **p);
+int sp_tseg_destroy(sp_tseg **p);
+int sp_tseg_init(sp_data *sp, sp_tseg *p, SPFLOAT ibeg);
+int sp_tseg_compute(sp_data *sp, sp_tseg *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/tseq.h
@@ -1,0 +1,11 @@
+typedef struct sp_tseq {
+    sp_ftbl *ft;
+    SPFLOAT val;
+    int32_t pos;
+    int shuf;
+} sp_tseq;
+
+int sp_tseq_create(sp_tseq **p);
+int sp_tseq_destroy(sp_tseq **p);
+int sp_tseq_init(sp_data *sp, sp_tseq *p, sp_ftbl *ft);
+int sp_tseq_compute(sp_data *sp, sp_tseq *p, SPFLOAT *trig, SPFLOAT *val);
--- /dev/null
+++ b/h/vardelay.h
@@ -1,0 +1,18 @@
+#ifndef SK_VARDELAY_H
+typedef struct sk_vardelay sk_vardelay;
+#endif
+
+typedef struct {
+    SPFLOAT del, maxdel;
+    SPFLOAT feedback;
+    sk_vardelay *v;
+    SPFLOAT *buf;
+} sp_vardelay;
+
+int sp_vardelay_create(sp_vardelay **p);
+int sp_vardelay_destroy(sp_vardelay **p);
+int sp_vardelay_init(sp_data *sp, sp_vardelay *p, SPFLOAT maxdel);
+int sp_vardelay_compute(sp_data *sp,
+                       sp_vardelay *p,
+                       SPFLOAT *in,
+                       SPFLOAT *out);
--- /dev/null
+++ b/h/voc.h
@@ -1,0 +1,39 @@
+
+#ifndef SP_VOC
+#define SP_VOC
+typedef struct sp_voc sp_voc;
+
+int sp_voc_create(sp_voc **voc);
+int sp_voc_destroy(sp_voc **voc);
+int sp_voc_init(sp_data *sp, sp_voc *voc);
+int sp_voc_compute(sp_data *sp, sp_voc *voc, SPFLOAT *out);
+int sp_voc_tract_compute(sp_data *sp, sp_voc *voc, SPFLOAT *in, SPFLOAT *out);
+
+void sp_voc_set_frequency(sp_voc *voc, SPFLOAT freq);
+SPFLOAT * sp_voc_get_frequency_ptr(sp_voc *voc);
+
+SPFLOAT* sp_voc_get_tract_diameters(sp_voc *voc);
+SPFLOAT* sp_voc_get_current_tract_diameters(sp_voc *voc);
+int sp_voc_get_tract_size(sp_voc *voc);
+SPFLOAT* sp_voc_get_nose_diameters(sp_voc *voc);
+int sp_voc_get_nose_size(sp_voc *voc);
+void sp_voc_set_tongue_shape(sp_voc *voc,
+    SPFLOAT tongue_index,
+    SPFLOAT tongue_diameter);
+void sp_voc_set_tenseness(sp_voc *voc, SPFLOAT breathiness);
+SPFLOAT * sp_voc_get_tenseness_ptr(sp_voc *voc);
+void sp_voc_set_velum(sp_voc *voc, SPFLOAT velum);
+SPFLOAT * sp_voc_get_velum_ptr(sp_voc *voc);
+
+void sp_voc_set_diameters(sp_voc *voc,
+    int blade_start,
+    int lip_start,
+    int tip_start,
+    SPFLOAT tongue_index,
+    SPFLOAT tongue_diameter,
+    SPFLOAT *diameters);
+
+int sp_voc_get_counter(sp_voc *voc);
+
+
+#endif
--- /dev/null
+++ b/h/wavin.h
@@ -1,0 +1,8 @@
+typedef struct sp_wavin sp_wavin;
+int sp_wavin_create(sp_wavin **p);
+int sp_wavin_destroy(sp_wavin **p);
+int sp_wavin_init(sp_data *sp, sp_wavin *p, const char *filename);
+int sp_wavin_compute(sp_data *sp, sp_wavin *p, SPFLOAT *in, SPFLOAT *out);
+int sp_wavin_get_sample(sp_data *sp, sp_wavin *p, SPFLOAT *out, SPFLOAT pos);
+int sp_wavin_reset_to_start(sp_data *sp, sp_wavin *p);
+int sp_wavin_seek(sp_data *sp, sp_wavin *p, unsigned long sample);
--- /dev/null
+++ b/h/wavout.h
@@ -1,0 +1,5 @@
+typedef struct sp_wavout sp_wavout;
+int sp_wavout_create(sp_wavout **p);
+int sp_wavout_destroy(sp_wavout **p);
+int sp_wavout_init(sp_data *sp, sp_wavout *p, const char *filename);
+int sp_wavout_compute(sp_data *sp, sp_wavout *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/wpkorg35.h
@@ -1,0 +1,31 @@
+typedef struct {
+    /* LPF1 */
+    SPFLOAT lpf1_a;
+    SPFLOAT lpf1_z;
+
+    /* LPF2 */
+    SPFLOAT lpf2_a;
+    SPFLOAT lpf2_b;
+    SPFLOAT lpf2_z;
+
+    /* HPF */
+    SPFLOAT hpf_a;
+    SPFLOAT hpf_b;
+    SPFLOAT hpf_z;
+
+    SPFLOAT alpha;
+
+    SPFLOAT cutoff;
+    SPFLOAT res;
+    SPFLOAT saturation;
+
+    SPFLOAT pcutoff;
+    SPFLOAT pres;
+
+    uint32_t nonlinear;
+} sp_wpkorg35;
+
+int sp_wpkorg35_create(sp_wpkorg35 **p);
+int sp_wpkorg35_destroy(sp_wpkorg35 **p);
+int sp_wpkorg35_init(sp_data *sp, sp_wpkorg35 *p);
+int sp_wpkorg35_compute(sp_data *sp, sp_wpkorg35 *p, SPFLOAT *in, SPFLOAT *out);
--- /dev/null
+++ b/h/zitarev.h
@@ -1,0 +1,21 @@
+typedef struct {
+    void *faust;
+    int argpos;
+    SPFLOAT *args[11];
+    SPFLOAT *in_delay;
+    SPFLOAT *lf_x;
+    SPFLOAT *rt60_low;
+    SPFLOAT *rt60_mid;
+    SPFLOAT *hf_damping;
+    SPFLOAT *eq1_freq;
+    SPFLOAT *eq1_level;
+    SPFLOAT *eq2_freq;
+    SPFLOAT *eq2_level;
+    SPFLOAT *mix;
+    SPFLOAT *level;
+} sp_zitarev;
+
+int sp_zitarev_create(sp_zitarev **p);
+int sp_zitarev_destroy(sp_zitarev **p);
+int sp_zitarev_init(sp_data *sp, sp_zitarev *p);
+int sp_zitarev_compute(sp_data *sp, sp_zitarev *p, SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out1, SPFLOAT *out2);
--- /dev/null
+++ b/lib/dr_wav/Makefile
@@ -1,0 +1,5 @@
+CFLAGS += -Ilib/dr_wav/
+LPATHS += lib/dr_wav/dr_wav.o
+
+lib/dr_wav/dr_wav.o: lib/dr_wav/dr_wav.c
+	$(C99) $(CFLAGS) $< -c -o $@
--- /dev/null
+++ b/lib/dr_wav/dr_wav.c
@@ -1,0 +1,56 @@
+#define DR_WAV_IMPLEMENTATION
+#include "dr_wav.h"
+
+size_t sp_drwav_size(void)
+{
+    return sizeof(drwav);
+}
+
+int sp_drwav_init_file(drwav* pWav, const char* filename)
+{
+    return drwav_init_file(pWav, filename);
+}
+
+size_t sp_drwav_read_f32(drwav* pWav,
+                         size_t samplesToRead,
+                         float* pBufferOut)
+{
+    return drwav_read_f32(pWav, samplesToRead, pBufferOut);
+}
+
+size_t sp_drwav_sampcount(drwav *wav)
+{
+    return wav->totalSampleCount;
+}
+
+void sp_drwav_uninit(drwav *wav)
+{
+    drwav_uninit(wav);
+}
+
+int sp_drwav_seek_to_sample(drwav* pWav, size_t sample)
+{
+    return drwav_seek_to_sample(pWav, sample);
+}
+
+drwav * sp_drwav_open_mono_write(const char *filename, int sr)
+{
+    drwav_data_format format;
+    format.container = drwav_container_riff;
+    format.format = DR_WAVE_FORMAT_IEEE_FLOAT;
+    format.channels = 1;
+    format.sampleRate = sr;
+    format.bitsPerSample = 32;
+
+    return drwav_open_file_write(filename, &format);
+}
+
+size_t sp_drwav_write(drwav* pWav, size_t samplesToWrite, const void* pData)
+{
+    return drwav_write(pWav, samplesToWrite, pData);
+}
+
+void sp_drwav_close(drwav* pWav)
+{
+    drwav_close(pWav);
+}
--- /dev/null
+++ b/lib/dr_wav/dr_wav.h
@@ -1,0 +1,3490 @@
+// WAV audio loader and writer. Public domain. See "unlicense" statement at the end of this file.
+// dr_wav - v0.7 - 2017-11-04
+//
+// David Reid - mackron@gmail.com
+
+// USAGE
+//
+// This is a single-file library. To use it, do something like the following in one .c file.
+//     #define DR_WAV_IMPLEMENTATION
+//     #include "dr_wav.h"
+//
+// You can then #include this file in other parts of the program as you would with any other header file. Do something
+// like the following to read audio data:
+//
+//     drwav wav;
+//     if (!drwav_init_file(&wav, "my_song.wav")) {
+//         // Error opening WAV file.
+//     }
+//
+//     drwav_int32* pDecodedInterleavedSamples = malloc(wav.totalSampleCount * sizeof(drwav_int32));
+//     size_t numberOfSamplesActuallyDecoded = drwav_read_s32(&wav, wav.totalSampleCount, pDecodedInterleavedSamples);
+//
+//     ...
+//
+//     drwav_uninit(&wav);
+//
+// You can also use drwav_open() to allocate and initialize the loader for you:
+//
+//     drwav* pWav = drwav_open_file("my_song.wav");
+//     if (pWav == NULL) {
+//         // Error opening WAV file.
+//     }
+//
+//     ...
+//
+//     drwav_close(pWav);
+//
+// If you just want to quickly open and read the audio data in a single operation you can do something like this:
+//
+//     unsigned int channels;
+//     unsigned int sampleRate;
+//     drwav_uint64 totalSampleCount;
+//     float* pSampleData = drwav_open_and_read_file_s32("my_song.wav", &channels, &sampleRate, &totalSampleCount);
+//     if (pSampleData == NULL) {
+//         // Error opening and reading WAV file.
+//     }
+//
+//     ...
+//
+//     drwav_free(pSampleData);
+//
+// The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in
+// this case), but you can still output the audio data in it's internal format (see notes below for supported formats):
+//
+//     size_t samplesRead = drwav_read(&wav, wav.totalSampleCount, pDecodedInterleavedSamples);
+//
+// You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for
+// a particular data format:
+//
+//     size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer);
+//
+//
+// dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work
+// without any manual intervention.
+//
+//
+// dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at
+// drwav_open_write(), drwav_open_file_write(), etc. Use drwav_write() to write samples, or drwav_write_raw() to write
+// raw data in the "data" chunk.
+//
+//     drwav_data_format format;
+//     format.container = drwav_container_riff;     // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
+//     format.format = DR_WAVE_FORMAT_PCM;          // <-- Any of the DR_WAVE_FORMAT_* codes.
+//     format.channels = 2;
+//     format.sampleRate = 44100;
+//     format.bitsPerSample = 16;
+//     drwav* pWav = drwav_open_file_write("data/recording.wav", &format);
+//
+//     ...
+//
+//     drwav_uint64 samplesWritten = drwav_write(pWav, sampleCount, pSamples);
+//
+//
+//
+// OPTIONS
+// #define these options before including this file.
+//
+// #define DR_WAV_NO_CONVERSION_API
+//   Disables conversion APIs such as drwav_read_f32() and drwav_s16_to_f32().
+//
+// #define DR_WAV_NO_STDIO
+//   Disables drwav_open_file(), drwav_open_file_write(), etc.
+//
+//
+//
+// QUICK NOTES
+// - Samples are always interleaved.
+// - The default read function does not do any data conversion. Use drwav_read_f32() to read and convert audio data
+//   to IEEE 32-bit floating point samples, drwav_read_s32() to read samples as signed 32-bit PCM and drwav_read_s16()
+//   to read samples as signed 16-bit PCM. Tested and supported internal formats include the following:
+//   - Unsigned 8-bit PCM
+//   - Signed 12-bit PCM
+//   - Signed 16-bit PCM
+//   - Signed 24-bit PCM
+//   - Signed 32-bit PCM
+//   - IEEE 32-bit floating point.
+//   - IEEE 64-bit floating point.
+//   - A-law and u-law
+//   - Microsoft ADPCM
+//   - IMA ADPCM (DVI, format code 0x11)
+// - dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format.
+
+
+#ifndef dr_wav_h
+#define dr_wav_h
+
+#include <stddef.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+typedef   signed char    drwav_int8;
+typedef unsigned char    drwav_uint8;
+typedef   signed short   drwav_int16;
+typedef unsigned short   drwav_uint16;
+typedef   signed int     drwav_int32;
+typedef unsigned int     drwav_uint32;
+typedef   signed __int64 drwav_int64;
+typedef unsigned __int64 drwav_uint64;
+#else
+#include <stdint.h>
+typedef int8_t           drwav_int8;
+typedef uint8_t          drwav_uint8;
+typedef int16_t          drwav_int16;
+typedef uint16_t         drwav_uint16;
+typedef int32_t          drwav_int32;
+typedef uint32_t         drwav_uint32;
+typedef int64_t          drwav_int64;
+typedef uint64_t         drwav_uint64;
+#endif
+typedef drwav_uint8      drwav_bool8;
+typedef drwav_uint32     drwav_bool32;
+#define DRWAV_TRUE       1
+#define DRWAV_FALSE      0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Common data formats.
+#define DR_WAVE_FORMAT_PCM          0x1
+#define DR_WAVE_FORMAT_ADPCM        0x2
+#define DR_WAVE_FORMAT_IEEE_FLOAT   0x3
+#define DR_WAVE_FORMAT_ALAW         0x6
+#define DR_WAVE_FORMAT_MULAW        0x7
+#define DR_WAVE_FORMAT_DVI_ADPCM    0x11
+#define DR_WAVE_FORMAT_EXTENSIBLE   0xFFFE
+
+typedef enum
+{
+    drwav_seek_origin_start,
+    drwav_seek_origin_current
+} drwav_seek_origin;
+
+typedef enum
+{
+    drwav_container_riff,
+    drwav_container_w64
+} drwav_container;
+
+// Callback for when data is read. Return value is the number of bytes actually read.
+//
+// pUserData   [in]  The user data that was passed to drwav_init(), drwav_open() and family.
+// pBufferOut  [out] The output buffer.
+// bytesToRead [in]  The number of bytes to read.
+//
+// Returns the number of bytes actually read.
+//
+// A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until
+// either the entire bytesToRead is filled or you have reached the end of the stream.
+typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
+
+// Callback for when data is written. Returns value is the number of bytes actually written.
+//
+// pUserData    [in]  The user data that was passed to drwav_init_write(), drwav_open_write() and family.
+// pData        [out] A pointer to the data to write.
+// bytesToWrite [in]  The number of bytes to write.
+//
+// Returns the number of bytes actually written.
+//
+// If the return value differs from bytesToWrite, it indicates an error.
+typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite);
+
+// Callback for when data needs to be seeked.
+//
+// pUserData [in] The user data that was passed to drwav_init(), drwav_open() and family.
+// offset    [in] The number of bytes to move, relative to the origin. Will never be negative.
+// origin    [in] The origin of the seek - the current position or the start of the stream.
+//
+// Returns whether or not the seek was successful.
+//
+// Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which
+// will be either drwav_seek_origin_start or drwav_seek_origin_current.
+typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin);
+
+// Structure for internal use. Only used for loaders opened with drwav_open_memory().
+typedef struct
+{
+    const drwav_uint8* data;
+    size_t dataSize;
+    size_t currentReadPos;
+} drwav__memory_stream;
+
+// Structure for internal use. Only used for writers opened with drwav_open_memory_write().
+typedef struct
+{
+    void** ppData;
+    size_t* pDataSize;
+    size_t dataSize;
+    size_t dataCapacity;
+    size_t currentWritePos;
+} drwav__memory_stream_write;
+
+typedef struct
+{
+    drwav_container container;  // RIFF, W64.
+    drwav_uint32 format;        // DR_WAVE_FORMAT_*
+    drwav_uint32 channels;
+    drwav_uint32 sampleRate;
+    drwav_uint32 bitsPerSample;
+} drwav_data_format;
+
+typedef struct
+{
+    // The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications
+    // that require support for data formats not natively supported by dr_wav.
+    drwav_uint16 formatTag;
+
+    // The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc.
+    drwav_uint16 channels;
+
+    // The sample rate. Usually set to something like 44100.
+    drwav_uint32 sampleRate;
+
+    // Average bytes per second. You probably don't need this, but it's left here for informational purposes.
+    drwav_uint32 avgBytesPerSec;
+
+    // Block align. This is equal to the number of channels * bytes per sample.
+    drwav_uint16 blockAlign;
+
+    // Bit's per sample.
+    drwav_uint16 bitsPerSample;
+
+    // The size of the extended data. Only used internally for validation, but left here for informational purposes.
+    drwav_uint16 extendedSize;
+
+    // The number of valid bits per sample. When <formatTag> is equal to WAVE_FORMAT_EXTENSIBLE, <bitsPerSample>
+    // is always rounded up to the nearest multiple of 8. This variable contains information about exactly how
+    // many bits a valid per sample. Mainly used for informational purposes.
+    drwav_uint16 validBitsPerSample;
+
+    // The channel mask. Not used at the moment.
+    drwav_uint32 channelMask;
+
+    // The sub-format, exactly as specified by the wave file.
+    drwav_uint8 subFormat[16];
+} drwav_fmt;
+
+typedef struct drwav
+{
+    // A pointer to the function to call when more data is needed.
+    drwav_read_proc onRead;
+
+    // A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode.
+    drwav_write_proc onWrite;
+
+    // A pointer to the function to call when the wav file needs to be seeked.
+    drwav_seek_proc onSeek;
+
+    // The user data to pass to callbacks.
+    void* pUserData;
+
+
+    // Whether or not the WAV file is formatted as a standard RIFF file or W64.
+    drwav_container container;
+
+
+    // Structure containing format information exactly as specified by the wav file.
+    drwav_fmt fmt;
+
+    // The sample rate. Will be set to something like 44100.
+    drwav_uint32 sampleRate;
+
+    // The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc.
+    drwav_uint16 channels;
+
+    // The bits per sample. Will be set to somthing like 16, 24, etc.
+    drwav_uint16 bitsPerSample;
+
+    // The number of bytes per sample.
+    drwav_uint16 bytesPerSample;
+
+    // Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE).
+    drwav_uint16 translatedFormatTag;
+
+    // The total number of samples making up the audio data. Use <totalSampleCount> * <bytesPerSample> to calculate
+    // the required size of a buffer to hold the entire audio data.
+    drwav_uint64 totalSampleCount;
+
+
+    // The size in bytes of the data chunk.
+    drwav_uint64 dataChunkDataSize;
+
+    // The position in the stream of the first byte of the data chunk. This is used for seeking.
+    drwav_uint64 dataChunkDataPos;
+
+    // The number of bytes remaining in the data chunk.
+    drwav_uint64 bytesRemaining;
+
+
+    // A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_open_memory().
+    drwav__memory_stream memoryStream;
+    drwav__memory_stream_write memoryStreamWrite;
+
+    // Generic data for compressed formats. This data is shared across all block-compressed formats.
+    struct
+    {
+        drwav_uint64 iCurrentSample;    // The index of the next sample that will be read by drwav_read_*(). This is used with "totalSampleCount" to ensure we don't read excess samples at the end of the last block.
+    } compressed;
+
+    // Microsoft ADPCM specific data.
+    struct
+    {
+        drwav_uint32 bytesRemainingInBlock;
+        drwav_uint16 predictor[2];
+        drwav_int32  delta[2];
+        drwav_int32  cachedSamples[4];  // Samples are stored in this cache during decoding.
+        drwav_uint32 cachedSampleCount;
+        drwav_int32  prevSamples[2][2]; // The previous 2 samples for each channel (2 channels at most).
+    } msadpcm;
+
+    // IMA ADPCM specific data.
+    struct
+    {
+        drwav_uint32 bytesRemainingInBlock;
+        drwav_int32  predictor[2];
+        drwav_int32  stepIndex[2];
+        drwav_int32  cachedSamples[16]; // Samples are stored in this cache during decoding.
+        drwav_uint32 cachedSampleCount;
+    } ima;
+} drwav;
+
+
+// Initializes a pre-allocated drwav object.
+//
+// onRead    [in]           The function to call when data needs to be read from the client.
+// onSeek    [in]           The function to call when the read position of the client data needs to move.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
+//
+// Returns true if successful; false otherwise.
+//
+// Close the loader with drwav_uninit().
+//
+// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
+// to open the stream from a file or from a block of memory respectively.
+//
+// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate
+// a drwav object on the heap and return a pointer to it.
+//
+// See also: drwav_init_file(), drwav_init_memory(), drwav_uninit()
+drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData);
+
+// Initializes a pre-allocated drwav object for writing.
+//
+// onWrite   [in]           The function to call when data needs to be written.
+// onSeek    [in]           The function to call when the write position needs to move.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
+//
+// Returns true if successful; false otherwise.
+//
+// Close the writer with drwav_uninit().
+//
+// This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory()
+// to open the stream from a file or from a block of memory respectively.
+//
+// If you want dr_wav to manage the memory allocation for you, consider using drwav_open() instead. This will allocate
+// a drwav object on the heap and return a pointer to it.
+//
+// See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit()
+drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData);
+
+// Uninitializes the given drwav object.
+//
+// Use this only for objects initialized with drwav_init().
+void drwav_uninit(drwav* pWav);
+
+
+// Opens a wav file using the given callbacks.
+//
+// onRead    [in]           The function to call when data needs to be read from the client.
+// onSeek    [in]           The function to call when the read position of the client data needs to move.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek.
+//
+// Returns null on error.
+//
+// Close the loader with drwav_close().
+//
+// This is the lowest level function for opening a WAV file. You can also use drwav_open_file() and drwav_open_memory()
+// to open the stream from a file or from a block of memory respectively.
+//
+// This is different from drwav_init() in that it will allocate the drwav object for you via DRWAV_MALLOC() before
+// initializing it.
+//
+// See also: drwav_open_file(), drwav_open_memory(), drwav_close()
+drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData);
+
+// Opens a wav file for writing using the given callbacks.
+//
+// onWrite   [in]           The function to call when data needs to be written.
+// onSeek    [in]           The function to call when the write position needs to move.
+// pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek.
+//
+// Returns null on error.
+//
+// Close the loader with drwav_close().
+//
+// This is the lowest level function for opening a WAV file. You can also use drwav_open_file_write() and drwav_open_memory_write()
+// to open the stream from a file or from a block of memory respectively.
+//
+// This is different from drwav_init_write() in that it will allocate the drwav object for you via DRWAV_MALLOC() before
+// initializing it.
+//
+// See also: drwav_open_file_write(), drwav_open_memory_write(), drwav_close()
+drwav* drwav_open_write(const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData);
+
+// Uninitializes and deletes the the given drwav object.
+//
+// Use this only for objects created with drwav_open().
+void drwav_close(drwav* pWav);
+
+
+// Reads raw audio data.
+//
+// This is the lowest level function for reading audio data. It simply reads the given number of
+// bytes of the raw internal sample data.
+//
+// Consider using drwav_read_s16(), drwav_read_s32() or drwav_read_f32() for reading sample data in
+// a consistent format.
+//
+// Returns the number of bytes actually read.
+size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut);
+
+// Reads a chunk of audio data in the native internal format.
+//
+// This is typically the most efficient way to retrieve audio data, but it does not do any format
+// conversions which means you'll need to convert the data manually if required.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached or
+// you have requested more samples than can possibly fit in the output buffer.
+//
+// This function will only work when sample data is of a fixed size and uncompressed. If you are
+// using a compressed format consider using drwav_read_raw() or drwav_read_s16/s32/f32/etc().
+drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut);
+
+// Seeks to the given sample.
+//
+// Returns true if successful; false otherwise.
+drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample);
+
+
+// Writes raw audio data.
+//
+// Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error.
+size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData);
+
+// Writes audio data based on sample counts.
+//
+// Returns the number of samples written.
+drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData);
+
+
+
+//// Convertion Utilities ////
+#ifndef DR_WAV_NO_CONVERSION_API
+
+// Reads a chunk of audio data and converts it to signed 16-bit PCM samples.
+//
+// Returns the number of samples actually read.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached.
+drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut);
+
+// Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples.
+void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples.
+void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples.
+void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples.
+void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples.
+void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount);
+
+// Low-level function for converting A-law samples to signed 16-bit PCM samples.
+void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting u-law samples to signed 16-bit PCM samples.
+void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+
+// Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples.
+//
+// Returns the number of samples actually read.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached.
+drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut);
+
+// Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples.
+void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples.
+void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount);
+
+// Low-level function for converting A-law samples to IEEE 32-bit floating point samples.
+void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting u-law samples to IEEE 32-bit floating point samples.
+void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+
+// Reads a chunk of audio data and converts it to signed 32-bit PCM samples.
+//
+// Returns the number of samples actually read.
+//
+// If the return value is less than <samplesToRead> it means the end of the file has been reached.
+drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut);
+
+// Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples.
+void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples.
+void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount);
+
+// Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples.
+void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples.
+void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount);
+
+// Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples.
+void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount);
+
+// Low-level function for converting A-law samples to signed 32-bit PCM samples.
+void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+// Low-level function for converting u-law samples to signed 32-bit PCM samples.
+void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount);
+
+#endif  //DR_WAV_NO_CONVERSION_API
+
+
+//// High-Level Convenience Helpers ////
+
+#ifndef DR_WAV_NO_STDIO
+
+// Helper for initializing a wave file using stdio.
+//
+// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
+// objects because the operating system may restrict the number of file handles an application can have open at
+// any given time.
+drwav_bool32 drwav_init_file(drwav* pWav, const char* filename);
+
+// Helper for initializing a wave file for writing using stdio.
+//
+// This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav
+// objects because the operating system may restrict the number of file handles an application can have open at
+// any given time.
+drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat);
+
+// Helper for opening a wave file using stdio.
+//
+// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav
+// objects because the operating system may restrict the number of file handles an application can have open at
+// any given time.
+drwav* drwav_open_file(const char* filename);
+
+// Helper for opening a wave file for writing using stdio.
+//
+// This holds the internal FILE object until drwav_close() is called. Keep this in mind if you're caching drwav
+// objects because the operating system may restrict the number of file handles an application can have open at
+// any given time.
+drwav* drwav_open_file_write(const char* filename, const drwav_data_format* pFormat);
+
+#endif  //DR_WAV_NO_STDIO
+
+// Helper for initializing a loader from a pre-allocated memory buffer.
+//
+// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
+// the lifetime of the drwav object.
+//
+// The buffer should contain the contents of the entire wave file, not just the sample data.
+drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize);
+
+// Helper for initializing a writer which outputs data to a memory buffer.
+//
+// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
+//
+// The buffer will remain allocated even after drwav_uninit() is called. Indeed, the buffer should not be
+// considered valid until after drwav_uninit() has been called anyway.
+drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat);
+
+// Helper for opening a loader from a pre-allocated memory buffer.
+//
+// This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for
+// the lifetime of the drwav object.
+//
+// The buffer should contain the contents of the entire wave file, not just the sample data.
+drwav* drwav_open_memory(const void* data, size_t dataSize);
+
+// Helper for opening a writer which outputs data to a memory buffer.
+//
+// dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free().
+//
+// The buffer will remain allocated even after drwav_close() is called. Indeed, the buffer should not be
+// considered valid until after drwav_close() has been called anyway.
+drwav* drwav_open_memory_write(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat);
+
+
+#ifndef DR_WAV_NO_CONVERSION_API
+// Opens and reads a wav file in a single operation.
+drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+#ifndef DR_WAV_NO_STDIO
+// Opens an decodes a wav file in a single operation.
+drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+#endif
+
+// Opens an decodes a wav file from a block of memory in a single operation.
+drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount);
+#endif
+
+// Frees data that was allocated internally by dr_wav.
+void drwav_free(void* pDataReturnedByOpenAndRead);
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // dr_wav_h
+
+
+/////////////////////////////////////////////////////
+//
+// IMPLEMENTATION
+//
+/////////////////////////////////////////////////////
+
+#ifdef DR_WAV_IMPLEMENTATION
+#include <stdlib.h>
+#include <string.h> // For memcpy(), memset()
+#include <limits.h> // For INT_MAX
+
+#ifndef DR_WAV_NO_STDIO
+#include <stdio.h>
+#endif
+
+// Standard library stuff.
+#ifndef DRWAV_ASSERT
+#include <assert.h>
+#define DRWAV_ASSERT(expression)           assert(expression)
+#endif
+#ifndef DRWAV_MALLOC
+#define DRWAV_MALLOC(sz)                   malloc((sz))
+#endif
+#ifndef DRWAV_REALLOC
+#define DRWAV_REALLOC(p, sz)               realloc((p), (sz))
+#endif
+#ifndef DRWAV_FREE
+#define DRWAV_FREE(p)                      free((p))
+#endif
+#ifndef DRWAV_COPY_MEMORY
+#define DRWAV_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
+#endif
+#ifndef DRWAV_ZERO_MEMORY
+#define DRWAV_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
+#endif
+
+#define drwav_countof(x)                   (sizeof(x) / sizeof(x[0]))
+#define drwav_align(x, a)                  ((((x) + (a) - 1) / (a)) * (a))
+#define drwav_min(a, b)                    (((a) < (b)) ? (a) : (b))
+#define drwav_max(a, b)                    (((a) > (b)) ? (a) : (b))
+#define drwav_clamp(x, lo, hi)             (drwav_max((lo), drwav_min((hi), (x))))
+
+#define drwav_assert                       DRWAV_ASSERT
+#define drwav_copy_memory                  DRWAV_COPY_MEMORY
+#define drwav_zero_memory                  DRWAV_ZERO_MEMORY
+
+
+#define DRWAV_MAX_SIMD_VECTOR_SIZE         64  // 64 for AVX-512 in the future.
+
+#ifdef _MSC_VER
+#define DRWAV_INLINE __forceinline
+#else
+#ifdef __GNUC__
+#define DRWAV_INLINE inline __attribute__((always_inline))
+#else
+#define DRWAV_INLINE inline
+#endif
+#endif
+
+// I couldn't figure out where SIZE_MAX was defined for VC6. If anybody knows, let me know.
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+    #if defined(_WIN64)
+        #define SIZE_MAX    ((drwav_uint64)0xFFFFFFFFFFFFFFFF)
+    #else
+        #define SIZE_MAX    0xFFFFFFFF
+    #endif
+#endif
+
+static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00};    // 66666972-912E-11CF-A5D6-28DB04C10000
+static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};    // 65766177-ACF3-11D3-8CD1-00C04F8EDB8A
+static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};    // 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A
+static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};    // 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A
+static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};    // 74636166-ACF3-11D3-8CD1-00C04F8EDB8A
+static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};    // 61746164-ACF3-11D3-8CD1-00C04F8EDB8A
+
+static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16])
+{
+    const drwav_uint32* a32 = (const drwav_uint32*)a;
+    const drwav_uint32* b32 = (const drwav_uint32*)b;
+
+    return
+        a32[0] == b32[0] &&
+        a32[1] == b32[1] &&
+        a32[2] == b32[2] &&
+        a32[3] == b32[3];
+}
+
+static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const unsigned char* a, const char* b)
+{
+    return
+        a[0] == b[0] &&
+        a[1] == b[1] &&
+        a[2] == b[2] &&
+        a[3] == b[3];
+}
+
+
+
+static DRWAV_INLINE int drwav__is_little_endian()
+{
+    int n = 1;
+    return (*(char*)&n) == 1;
+}
+
+static DRWAV_INLINE unsigned short drwav__bytes_to_u16(const unsigned char* data)
+{
+    if (drwav__is_little_endian()) {
+        return (data[0] << 0) | (data[1] << 8);
+    } else {
+        return (data[1] << 0) | (data[0] << 8);
+    }
+}
+
+static DRWAV_INLINE short drwav__bytes_to_s16(const unsigned char* data)
+{
+    return (short)drwav__bytes_to_u16(data);
+}
+
+static DRWAV_INLINE unsigned int drwav__bytes_to_u32(const unsigned char* data)
+{
+    if (drwav__is_little_endian()) {
+        return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+    } else {
+        return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
+    }
+}
+
+static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const unsigned char* data)
+{
+    if (drwav__is_little_endian()) {
+        return
+            ((drwav_uint64)data[0] <<  0) | ((drwav_uint64)data[1] <<  8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) |
+            ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56);
+    } else {
+        return
+            ((drwav_uint64)data[7] <<  0) | ((drwav_uint64)data[6] <<  8) | ((drwav_uint64)data[5] << 16) | ((drwav_uint64)data[4] << 24) |
+            ((drwav_uint64)data[3] << 32) | ((drwav_uint64)data[2] << 40) | ((drwav_uint64)data[1] << 48) | ((drwav_uint64)data[0] << 56);
+    }
+}
+
+static DRWAV_INLINE void drwav__bytes_to_guid(const unsigned char* data, drwav_uint8* guid)
+{
+    int i;
+    for (i = 0; i < 16; ++i) {
+        guid[i] = data[i];
+    }
+}
+
+
+static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag)
+{
+    return
+        formatTag == DR_WAVE_FORMAT_ADPCM ||
+        formatTag == DR_WAVE_FORMAT_DVI_ADPCM;
+}
+
+
+typedef struct
+{
+    union
+    {
+        drwav_uint8 fourcc[4];
+        drwav_uint8 guid[16];
+    } id;
+
+    // The size in bytes of the chunk.
+    drwav_uint64 sizeInBytes;
+
+    // RIFF = 2 byte alignment.
+    // W64  = 8 byte alignment.
+    unsigned int paddingSize;
+
+} drwav__chunk_header;
+
+static drwav_bool32 drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav__chunk_header* pHeaderOut)
+{
+    if (container == drwav_container_riff) {
+        if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) {
+            return DRWAV_FALSE;
+        }
+
+        unsigned char sizeInBytes[4];
+        if (onRead(pUserData, sizeInBytes, 4) != 4) {
+            return DRWAV_FALSE;
+        }
+
+        pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes);
+        pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 2);
+        *pRunningBytesReadOut += 8;
+    } else {
+        if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) {
+            return DRWAV_FALSE;
+        }
+
+        unsigned char sizeInBytes[8];
+        if (onRead(pUserData, sizeInBytes, 8) != 8) {
+            return DRWAV_FALSE;
+        }
+
+        pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24;    // <-- Subtract 24 because w64 includes the size of the header.
+        pHeaderOut->paddingSize = (unsigned int)(pHeaderOut->sizeInBytes % 8);
+        pRunningBytesReadOut += 24;
+    }
+
+    return DRWAV_TRUE;
+}
+
+static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData)
+{
+    drwav_uint64 bytesRemainingToSeek = offset;
+    while (bytesRemainingToSeek > 0) {
+        if (bytesRemainingToSeek > 0x7FFFFFFF) {
+            if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) {
+                return DRWAV_FALSE;
+            }
+            bytesRemainingToSeek -= 0x7FFFFFFF;
+        } else {
+            if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) {
+                return DRWAV_FALSE;
+            }
+            bytesRemainingToSeek = 0;
+        }
+    }
+
+    return DRWAV_TRUE;
+}
+
+
+static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut)
+{
+    drwav__chunk_header header;
+    if (!drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header)) {
+        return DRWAV_FALSE;
+    }
+
+
+    // Skip junk chunks.
+    if ((container == drwav_container_riff && drwav__fourcc_equal(header.id.fourcc, "JUNK")) || (container == drwav_container_w64 && drwav__guid_equal(header.id.guid, drwavGUID_W64_JUNK))) {
+        if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) {
+            return DRWAV_FALSE;
+        }
+        *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize;
+
+        return drwav__read_fmt(onRead, onSeek, pUserData, container, pRunningBytesReadOut, fmtOut);
+    }
+
+
+    // Validation.
+    if (container == drwav_container_riff) {
+        if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) {
+            return DRWAV_FALSE;
+        }
+    } else {
+        if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) {
+            return DRWAV_FALSE;
+        }
+    }
+
+
+    unsigned char fmt[16];
+    if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) {
+        return DRWAV_FALSE;
+    }
+    *pRunningBytesReadOut += sizeof(fmt);
+
+    fmtOut->formatTag      = drwav__bytes_to_u16(fmt + 0);
+    fmtOut->channels       = drwav__bytes_to_u16(fmt + 2);
+    fmtOut->sampleRate     = drwav__bytes_to_u32(fmt + 4);
+    fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8);
+    fmtOut->blockAlign     = drwav__bytes_to_u16(fmt + 12);
+    fmtOut->bitsPerSample  = drwav__bytes_to_u16(fmt + 14);
+
+    fmtOut->extendedSize       = 0;
+    fmtOut->validBitsPerSample = 0;
+    fmtOut->channelMask        = 0;
+    memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
+
+    if (header.sizeInBytes > 16) {
+        unsigned char fmt_cbSize[2];
+        if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) {
+            return DRWAV_FALSE;    // Expecting more data.
+        }
+        *pRunningBytesReadOut += sizeof(fmt_cbSize);
+
+        int bytesReadSoFar = 18;
+
+        fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize);
+        if (fmtOut->extendedSize > 0) {
+            // Simple validation.
+            if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
+                if (fmtOut->extendedSize != 22) {
+                    return DRWAV_FALSE;
+                }
+            }
+
+            if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
+                unsigned char fmtext[22];
+                if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) {
+                    return DRWAV_FALSE;    // Expecting more data.
+                }
+
+                fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0);
+                fmtOut->channelMask        = drwav__bytes_to_u32(fmtext + 2);
+                drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat);
+            } else {
+                if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) {
+                    return DRWAV_FALSE;
+                }
+            }
+            *pRunningBytesReadOut += fmtOut->extendedSize;
+
+            bytesReadSoFar += fmtOut->extendedSize;
+        }
+
+        // Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size.
+        if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) {
+            return DRWAV_FALSE;
+        }
+        *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar);
+    }
+
+    if (header.paddingSize > 0) {
+        if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) {
+            return DRWAV_FALSE;
+        }
+        *pRunningBytesReadOut += header.paddingSize;
+    }
+
+    return DRWAV_TRUE;
+}
+
+
+#ifndef DR_WAV_NO_STDIO
+static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
+{
+    return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData);
+}
+
+static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite)
+{
+    return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData);
+}
+
+static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin)
+{
+    return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
+}
+
+drwav_bool32 drwav_init_file(drwav* pWav, const char* filename)
+{
+    FILE* pFile;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+    if (fopen_s(&pFile, filename, "rb") != 0) {
+        return DRWAV_FALSE;
+    }
+#else
+    pFile = fopen(filename, "rb");
+    if (pFile == NULL) {
+        return DRWAV_FALSE;
+    }
+#endif
+
+    return drwav_init(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile);
+}
+
+drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat)
+{
+    FILE* pFile;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+    if (fopen_s(&pFile, filename, "wb") != 0) {
+        return DRWAV_FALSE;
+    }
+#else
+    pFile = fopen(filename, "wb");
+    if (pFile == NULL) {
+        return DRWAV_FALSE;
+    }
+#endif
+
+    return drwav_init_write(pWav, pFormat, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile);
+}
+
+drwav* drwav_open_file(const char* filename)
+{
+    FILE* pFile;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+    if (fopen_s(&pFile, filename, "rb") != 0) {
+        return NULL;
+    }
+#else
+    pFile = fopen(filename, "rb");
+    if (pFile == NULL) {
+        return NULL;
+    }
+#endif
+
+    drwav* pWav = drwav_open(drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile);
+    if (pWav == NULL) {
+        fclose(pFile);
+        return NULL;
+    }
+
+    return pWav;
+}
+
+drwav* drwav_open_file_write(const char* filename, const drwav_data_format* pFormat)
+{
+    FILE* pFile;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+    if (fopen_s(&pFile, filename, "wb") != 0) {
+        return NULL;
+    }
+#else
+    pFile = fopen(filename, "wb");
+    if (pFile == NULL) {
+        return NULL;
+    }
+#endif
+
+    drwav* pWav = drwav_open_write(pFormat, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile);
+    if (pWav == NULL) {
+        fclose(pFile);
+        return NULL;
+    }
+
+    return pWav;
+}
+#endif  //DR_WAV_NO_STDIO
+
+
+static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead)
+{
+    drwav__memory_stream* memory = (drwav__memory_stream*)pUserData;
+    drwav_assert(memory != NULL);
+    drwav_assert(memory->dataSize >= memory->currentReadPos);
+
+    size_t bytesRemaining = memory->dataSize - memory->currentReadPos;
+    if (bytesToRead > bytesRemaining) {
+        bytesToRead = bytesRemaining;
+    }
+
+    if (bytesToRead > 0) {
+        DRWAV_COPY_MEMORY(pBufferOut, memory->data + memory->currentReadPos, bytesToRead);
+        memory->currentReadPos += bytesToRead;
+    }
+
+    return bytesToRead;
+}
+
+static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin)
+{
+    drwav__memory_stream* memory = (drwav__memory_stream*)pUserData;
+    drwav_assert(memory != NULL);
+
+    if (origin == drwav_seek_origin_current) {
+        if (offset > 0) {
+            if (memory->currentReadPos + offset > memory->dataSize) {
+                offset = (int)(memory->dataSize - memory->currentReadPos);  // Trying to seek too far forward.
+            }
+        } else {
+            if (memory->currentReadPos < (size_t)-offset) {
+                offset = -(int)memory->currentReadPos;  // Trying to seek too far backwards.
+            }
+        }
+
+        // This will never underflow thanks to the clamps above.
+        memory->currentReadPos += offset;
+    } else {
+        if ((drwav_uint32)offset <= memory->dataSize) {
+            memory->currentReadPos = offset;
+        } else {
+            memory->currentReadPos = memory->dataSize;  // Trying to seek too far forward.
+        }
+    }
+
+    return DRWAV_TRUE;
+}
+
+static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite)
+{
+    drwav__memory_stream_write* memory = (drwav__memory_stream_write*)pUserData;
+    drwav_assert(memory != NULL);
+    drwav_assert(memory->dataCapacity >= memory->currentWritePos);
+
+    size_t bytesRemaining = memory->dataCapacity - memory->currentWritePos;
+    if (bytesRemaining < bytesToWrite) {
+        // Need to reallocate.
+        size_t newDataCapacity = (memory->dataCapacity == 0) ? 256 : memory->dataCapacity * 2;
+
+        // If doubling wasn't enough, just make it the minimum required size to write the data.
+        if ((newDataCapacity - memory->currentWritePos) < bytesToWrite) {
+            newDataCapacity = memory->currentWritePos + bytesToWrite;
+        }
+
+        void* pNewData = DRWAV_REALLOC(*memory->ppData, newDataCapacity);
+        if (pNewData == NULL) {
+            return 0;
+        }
+
+        *memory->ppData = pNewData;
+        memory->dataCapacity = newDataCapacity;
+    }
+
+    drwav_uint8* pDataOut = (drwav_uint8*)(*memory->ppData);
+    DRWAV_COPY_MEMORY(pDataOut + memory->currentWritePos, pDataIn, bytesToWrite);
+
+    memory->currentWritePos += bytesToWrite;
+    if (memory->dataSize < memory->currentWritePos) {
+        memory->dataSize = memory->currentWritePos;
+    }
+
+    *memory->pDataSize = memory->dataSize;
+
+    return bytesToWrite;
+}
+
+static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin)
+{
+    drwav__memory_stream_write* memory = (drwav__memory_stream_write*)pUserData;
+    drwav_assert(memory != NULL);
+
+    if (origin == drwav_seek_origin_current) {
+        if (offset > 0) {
+            if (memory->currentWritePos + offset > memory->dataSize) {
+                offset = (int)(memory->dataSize - memory->currentWritePos);  // Trying to seek too far forward.
+            }
+        } else {
+            if (memory->currentWritePos < (size_t)-offset) {
+                offset = -(int)memory->currentWritePos;  // Trying to seek too far backwards.
+            }
+        }
+
+        // This will never underflow thanks to the clamps above.
+        memory->currentWritePos += offset;
+    } else {
+        if ((drwav_uint32)offset <= memory->dataSize) {
+            memory->currentWritePos = offset;
+        } else {
+            memory->currentWritePos = memory->dataSize;  // Trying to seek too far forward.
+        }
+    }
+
+    return DRWAV_TRUE;
+}
+
+drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize)
+{
+    if (data == NULL || dataSize == 0) {
+        return DRWAV_FALSE;
+    }
+
+    drwav__memory_stream memoryStream;
+    drwav_zero_memory(&memoryStream, sizeof(memoryStream));
+    memoryStream.data = (const unsigned char*)data;
+    memoryStream.dataSize = dataSize;
+    memoryStream.currentReadPos = 0;
+
+    if (!drwav_init(pWav, drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream)) {
+        return DRWAV_FALSE;
+    }
+
+    pWav->memoryStream = memoryStream;
+    pWav->pUserData = &pWav->memoryStream;
+    return DRWAV_TRUE;
+}
+
+drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat)
+{
+    if (ppData == NULL) {
+        return DRWAV_FALSE;
+    }
+
+    *ppData = NULL; // Important because we're using realloc()!
+    *pDataSize = 0;
+
+    drwav__memory_stream_write memoryStreamWrite;
+    drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite));
+    memoryStreamWrite.ppData = ppData;
+    memoryStreamWrite.pDataSize = pDataSize;
+    memoryStreamWrite.dataSize = 0;
+    memoryStreamWrite.dataCapacity = 0;
+    memoryStreamWrite.currentWritePos = 0;
+
+    if (!drwav_init_write(pWav, pFormat, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite)) {
+        return DRWAV_FALSE;
+    }
+
+    pWav->memoryStreamWrite = memoryStreamWrite;
+    pWav->pUserData = &pWav->memoryStreamWrite;
+    return DRWAV_TRUE;
+}
+
+drwav* drwav_open_memory(const void* data, size_t dataSize)
+{
+    if (data == NULL || dataSize == 0) {
+        return NULL;
+    }
+
+    drwav__memory_stream memoryStream;
+    drwav_zero_memory(&memoryStream, sizeof(memoryStream));
+    memoryStream.data = (const unsigned char*)data;
+    memoryStream.dataSize = dataSize;
+    memoryStream.currentReadPos = 0;
+
+    drwav* pWav = drwav_open(drwav__on_read_memory, drwav__on_seek_memory, (void*)&memoryStream);
+    if (pWav == NULL) {
+        return NULL;
+    }
+
+    pWav->memoryStream = memoryStream;
+    pWav->pUserData = &pWav->memoryStream;
+    return pWav;
+}
+
+drwav* drwav_open_memory_write(void** ppData, size_t* pDataSize, const drwav_data_format* pFormat)
+{
+    if (ppData == NULL) {
+        return NULL;
+    }
+
+    *ppData = NULL; // Important because we're using realloc()!
+    *pDataSize = 0;
+
+    drwav__memory_stream_write memoryStreamWrite;
+    drwav_zero_memory(&memoryStreamWrite, sizeof(memoryStreamWrite));
+    memoryStreamWrite.ppData = ppData;
+    memoryStreamWrite.pDataSize = pDataSize;
+    memoryStreamWrite.dataSize = 0;
+    memoryStreamWrite.dataCapacity = 0;
+    memoryStreamWrite.currentWritePos = 0;
+
+    drwav* pWav = drwav_open_write(pFormat, drwav__on_write_memory, drwav__on_seek_memory_write, (void*)&memoryStreamWrite);
+    if (pWav == NULL) {
+        return NULL;
+    }
+
+    pWav->memoryStreamWrite = memoryStreamWrite;
+    pWav->pUserData = &pWav->memoryStreamWrite;
+    return pWav;
+}
+
+
+drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData)
+{
+    int i;
+    if (onRead == NULL || onSeek == NULL) {
+        return DRWAV_FALSE;
+    }
+
+    drwav_zero_memory(pWav, sizeof(*pWav));
+
+
+    // The first 4 bytes should be the RIFF identifier.
+    unsigned char riff[4];
+    if (onRead(pUserData, riff, sizeof(riff)) != sizeof(riff)) {
+        return DRWAV_FALSE;    // Failed to read data.
+    }
+
+    // The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for
+    // w64 it will start with "riff".
+    if (drwav__fourcc_equal(riff, "RIFF")) {
+        pWav->container = drwav_container_riff;
+    } else if (drwav__fourcc_equal(riff, "riff")) {
+        pWav->container = drwav_container_w64;
+
+        // Check the rest of the GUID for validity.
+        drwav_uint8 riff2[12];
+        if (onRead(pUserData, riff2, sizeof(riff2)) != sizeof(riff2)) {
+            return DRWAV_FALSE;
+        }
+
+        for (i = 0; i < 12; ++i) {
+            if (riff2[i] != drwavGUID_W64_RIFF[i+4]) {
+                return DRWAV_FALSE;
+            }
+        }
+    } else {
+        return DRWAV_FALSE;   // Unknown or unsupported container.
+    }
+
+
+    if (pWav->container == drwav_container_riff) {
+        // RIFF/WAVE
+        unsigned char chunkSizeBytes[4];
+        if (onRead(pUserData, chunkSizeBytes, sizeof(chunkSizeBytes)) != sizeof(chunkSizeBytes)) {
+            return DRWAV_FALSE;
+        }
+
+        unsigned int chunkSize = drwav__bytes_to_u32(chunkSizeBytes);
+        if (chunkSize < 36) {
+            return DRWAV_FALSE;    // Chunk size should always be at least 36 bytes.
+        }
+
+        unsigned char wave[4];
+        if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) {
+            return DRWAV_FALSE;
+        }
+
+        if (!drwav__fourcc_equal(wave, "WAVE")) {
+            return DRWAV_FALSE;    // Expecting "WAVE".
+        }
+
+        pWav->dataChunkDataPos = 4 + sizeof(chunkSizeBytes) + sizeof(wave);
+    } else {
+        // W64
+        unsigned char chunkSize[8];
+        if (onRead(pUserData, chunkSize, sizeof(chunkSize)) != sizeof(chunkSize)) {
+            return DRWAV_FALSE;
+        }
+
+        if (drwav__bytes_to_u64(chunkSize) < 80) {
+            return DRWAV_FALSE;
+        }
+
+        drwav_uint8 wave[16];
+        if (onRead(pUserData, wave, sizeof(wave)) != sizeof(wave)) {
+            return DRWAV_FALSE;
+        }
+
+        if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) {
+            return DRWAV_FALSE;
+        }
+
+        pWav->dataChunkDataPos = 16 + sizeof(chunkSize) + sizeof(wave);
+    }
+
+
+    // The next 24 bytes should be the "fmt " chunk.
+    drwav_fmt fmt;
+    if (!drwav__read_fmt(onRead, onSeek, pUserData, pWav->container, &pWav->dataChunkDataPos, &fmt)) {
+        return DRWAV_FALSE;    // Failed to read the "fmt " chunk.
+    }
+
+
+    // Translate the internal format.
+    unsigned short translatedFormatTag = fmt.formatTag;
+    if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) {
+        translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0);
+    }
+
+
+    drwav_uint64 sampleCountFromFactChunk = 0;
+
+    // The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop.
+    drwav_uint64 dataSize;
+    for (;;)
+    {
+        drwav__chunk_header header;
+        if (!drwav__read_chunk_header(onRead, pUserData, pWav->container, &pWav->dataChunkDataPos, &header)) {
+            return DRWAV_FALSE;
+        }
+
+        dataSize = header.sizeInBytes;
+        if (pWav->container == drwav_container_riff) {
+            if (drwav__fourcc_equal(header.id.fourcc, "data")) {
+                break;
+            }
+        } else {
+            if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) {
+                break;
+            }
+        }
+
+        // Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats.
+        if (pWav->container == drwav_container_riff) {
+            if (drwav__fourcc_equal(header.id.fourcc, "fact")) {
+                drwav_uint32 sampleCount;
+                if (onRead(pUserData, &sampleCount, 4) != 4) {
+                    return DRWAV_FALSE;
+                }
+                pWav->dataChunkDataPos += 4;
+                dataSize -= 4;
+
+                // The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this
+                // for Microsoft ADPCM formats.
+                if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
+                    sampleCountFromFactChunk = sampleCount;
+                } else {
+                    sampleCountFromFactChunk = 0;
+                }
+            }
+        } else {
+            if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) {
+                if (onRead(pUserData, &sampleCountFromFactChunk, 8) != 8) {
+                    return DRWAV_FALSE;
+                }
+                pWav->dataChunkDataPos += 4;
+                dataSize -= 8;
+            }
+        }
+
+        // If we get here it means we didn't find the "data" chunk. Seek past it.
+
+        // Make sure we seek past the padding.
+        dataSize += header.paddingSize;
+        drwav__seek_forward(onSeek, dataSize, pUserData);
+        pWav->dataChunkDataPos += dataSize;
+    }
+
+    // At this point we should be sitting on the first byte of the raw audio data.
+
+    pWav->onRead              = onRead;
+    pWav->onSeek              = onSeek;
+    pWav->pUserData           = pUserData;
+    pWav->fmt                 = fmt;
+    pWav->sampleRate          = fmt.sampleRate;
+    pWav->channels            = fmt.channels;
+    pWav->bitsPerSample       = fmt.bitsPerSample;
+    pWav->bytesPerSample      = (unsigned int)(fmt.blockAlign / fmt.channels);
+    pWav->bytesRemaining      = dataSize;
+    pWav->translatedFormatTag = translatedFormatTag;
+    pWav->dataChunkDataSize   = dataSize;
+
+    if (sampleCountFromFactChunk != 0) {
+        pWav->totalSampleCount = sampleCountFromFactChunk * fmt.channels;
+    } else {
+        pWav->totalSampleCount = dataSize / pWav->bytesPerSample;
+
+        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
+            drwav_uint64 blockCount = dataSize / fmt.blockAlign;
+            pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2;  // x2 because two samples per byte.
+        }
+        if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
+            drwav_uint64 blockCount = dataSize / fmt.blockAlign;
+            pWav->totalSampleCount = ((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels);
+        }
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
+        pWav->bytesPerSample = 0;
+    }
+
+#ifdef DR_WAV_LIBSNDFILE_COMPAT
+    // I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website),
+    // it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count
+    // from the number of blocks, however this results in the inclusion of the extra silent samples at the end of the last block. The correct
+    // way to know the total sample count is to inspect the "fact" chunk which should always be present for compressed formats, and should
+    // always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my
+    // correctness tests against libsndfile and is disabled by default.
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
+        drwav_uint64 blockCount = dataSize / fmt.blockAlign;
+        pWav->totalSampleCount = (blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2;  // x2 because two samples per byte.
+    }
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
+        drwav_uint64 blockCount = dataSize / fmt.blockAlign;
+        pWav->totalSampleCount = ((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels);
+    }
+#endif
+
+    return DRWAV_TRUE;
+}
+
+drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData)
+{
+    if (onWrite == NULL || onSeek == NULL) {
+        return DRWAV_FALSE;
+    }
+
+    // Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this.
+    if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) {
+        return DRWAV_FALSE;
+    }
+    if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) {
+        return DRWAV_FALSE;
+    }
+
+
+    drwav_zero_memory(pWav, sizeof(*pWav));
+    pWav->onWrite = onWrite;
+    pWav->onSeek = onSeek;
+    pWav->pUserData = pUserData;
+    pWav->fmt.formatTag = (drwav_uint16)pFormat->format;
+    pWav->fmt.channels = (drwav_uint16)pFormat->channels;
+    pWav->fmt.sampleRate = pFormat->sampleRate;
+    pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) >> 3);
+    pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) >> 3);
+    pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
+    pWav->fmt.extendedSize = 0;
+
+    size_t runningPos = 0;
+
+    // "RIFF" chunk.
+    drwav_uint64 chunkSizeRIFF = 0;
+    if (pFormat->container == drwav_container_riff) {
+        runningPos += pWav->onWrite(pUserData, "RIFF", 4);
+        runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 4);
+        runningPos += pWav->onWrite(pUserData, "WAVE", 4);
+    } else {
+        runningPos += pWav->onWrite(pUserData, drwavGUID_W64_RIFF, 16);
+        runningPos += pWav->onWrite(pUserData, &chunkSizeRIFF, 8);
+        runningPos += pWav->onWrite(pUserData, drwavGUID_W64_WAVE, 16);
+    }
+
+    // "fmt " chunk.
+    drwav_uint64 chunkSizeFMT;
+    if (pFormat->container == drwav_container_riff) {
+        chunkSizeFMT = 16;
+        runningPos += pWav->onWrite(pUserData, "fmt ", 4);
+        runningPos += pWav->onWrite(pUserData, &chunkSizeFMT, 4);
+    } else {
+        chunkSizeFMT = 40;
+        runningPos += pWav->onWrite(pUserData, drwavGUID_W64_FMT, 16);
+        runningPos += pWav->onWrite(pUserData, &chunkSizeFMT, 8);
+    }
+
+    runningPos += pWav->onWrite(pUserData, &pWav->fmt.formatTag,      2);
+    runningPos += pWav->onWrite(pUserData, &pWav->fmt.channels,       2);
+    runningPos += pWav->onWrite(pUserData, &pWav->fmt.sampleRate,     4);
+    runningPos += pWav->onWrite(pUserData, &pWav->fmt.avgBytesPerSec, 4);
+    runningPos += pWav->onWrite(pUserData, &pWav->fmt.blockAlign,     2);
+    runningPos += pWav->onWrite(pUserData, &pWav->fmt.bitsPerSample,  2);
+
+    pWav->dataChunkDataPos = runningPos;
+    pWav->dataChunkDataSize = 0;
+
+    // "data" chunk.
+    drwav_uint64 chunkSizeDATA = 0;
+    if (pFormat->container == drwav_container_riff) {
+        runningPos += pWav->onWrite(pUserData, "data", 4);
+        runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 4);
+    } else {
+        runningPos += pWav->onWrite(pUserData, drwavGUID_W64_DATA, 16);
+        runningPos += pWav->onWrite(pUserData, &chunkSizeDATA, 8);
+    }
+
+
+    // Simple validation.
+    if (pFormat->container == drwav_container_riff) {
+        if (runningPos != 20 + chunkSizeFMT + 8) {
+            return DRWAV_FALSE;
+        }
+    } else {
+        if (runningPos != 40 + chunkSizeFMT + 24) {
+            return DRWAV_FALSE;
+        }
+    }
+
+
+
+    // Set some properties for the client's convenience.
+    pWav->container = pFormat->container;
+    pWav->channels = (drwav_uint16)pFormat->channels;
+    pWav->sampleRate = pFormat->sampleRate;
+    pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample;
+    pWav->bytesPerSample = (drwav_uint16)(pFormat->bitsPerSample >> 3);
+    pWav->translatedFormatTag = (drwav_uint16)pFormat->format;
+
+    return DRWAV_TRUE;
+}
+
+void drwav_uninit(drwav* pWav)
+{
+    if (pWav == NULL) {
+        return;
+    }
+
+    // If the drwav object was opened in write mode we'll need to finialize a few things:
+    //   - Make sure the "data" chunk is aligned to 16-bits
+    //   - Set the size of the "data" chunk.
+    if (pWav->onWrite != NULL) {
+        // Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding.
+        drwav_uint32 paddingSize = 0;
+        if (pWav->container == drwav_container_riff) {
+            paddingSize = (drwav_uint32)(pWav->dataChunkDataSize % 2);
+        } else {
+            paddingSize = (drwav_uint32)(pWav->dataChunkDataSize % 8);
+        }
+
+        if (paddingSize > 0) {
+            drwav_uint64 paddingData = 0;
+            pWav->onWrite(pWav->pUserData, &paddingData, paddingSize);
+        }
+
+
+        // Chunk sizes.
+        if (pWav->onSeek) {
+            if (pWav->container == drwav_container_riff) {
+                // The "RIFF" chunk size.
+                if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) {
+                    drwav_uint32 riffChunkSize = 36;
+                    if (pWav->dataChunkDataSize <= (0xFFFFFFFF - 36)) {
+                        riffChunkSize = 36 + (drwav_uint32)pWav->dataChunkDataSize;
+                    } else {
+                        riffChunkSize = 0xFFFFFFFF;
+                    }
+
+                    pWav->onWrite(pWav->pUserData, &riffChunkSize, 4);
+                }
+
+                // the "data" chunk size.
+                if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) {
+                    drwav_uint32 dataChunkSize = 0;
+                    if (pWav->dataChunkDataSize <= 0xFFFFFFFF) {
+                        dataChunkSize = (drwav_uint32)pWav->dataChunkDataSize;
+                    } else {
+                        dataChunkSize = 0xFFFFFFFF;
+                    }
+
+                    pWav->onWrite(pWav->pUserData, &dataChunkSize, 4);
+                }
+            } else {
+                // The "RIFF" chunk size.
+                if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) {
+                    drwav_uint64 riffChunkSize = 80 + 24 + pWav->dataChunkDataSize;
+                    pWav->onWrite(pWav->pUserData, &riffChunkSize, 8);
+                }
+
+                // The "data" chunk size.
+                if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) {
+                    drwav_uint64 dataChunkSize = 24 + pWav->dataChunkDataSize;  // +24 because W64 includes the size of the GUID and size fields.
+                    pWav->onWrite(pWav->pUserData, &dataChunkSize, 8);
+                }
+            }
+        }
+    }
+
+#ifndef DR_WAV_NO_STDIO
+    // If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file()
+    // was used by looking at the onRead and onSeek callbacks.
+    if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) {
+        fclose((FILE*)pWav->pUserData);
+    }
+#endif
+}
+
+
+drwav* drwav_open(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData)
+{
+    drwav* pWav = (drwav*)DRWAV_MALLOC(sizeof(*pWav));
+    if (pWav == NULL) {
+        return NULL;
+    }
+
+    if (!drwav_init(pWav, onRead, onSeek, pUserData)) {
+        DRWAV_FREE(pWav);
+        return NULL;
+    }
+
+    return pWav;
+}
+
+drwav* drwav_open_write(const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData)
+{
+    drwav* pWav = (drwav*)DRWAV_MALLOC(sizeof(*pWav));
+    if (pWav == NULL) {
+        return NULL;
+    }
+
+    if (!drwav_init_write(pWav, pFormat, onWrite, onSeek, pUserData)) {
+        DRWAV_FREE(pWav);
+        return NULL;
+    }
+
+    return pWav;
+}
+
+void drwav_close(drwav* pWav)
+{
+    drwav_uninit(pWav);
+    DRWAV_FREE(pWav);
+}
+
+
+size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut)
+{
+    if (pWav == NULL || bytesToRead == 0 || pBufferOut == NULL) {
+        return 0;
+    }
+
+    if (bytesToRead > pWav->bytesRemaining) {
+        bytesToRead = (size_t)pWav->bytesRemaining;
+    }
+
+    size_t bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead);
+
+    pWav->bytesRemaining -= bytesRead;
+    return bytesRead;
+}
+
+drwav_uint64 drwav_read(drwav* pWav, drwav_uint64 samplesToRead, void* pBufferOut)
+{
+    if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) {
+        return 0;
+    }
+
+    // Cannot use this function for compressed formats.
+    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
+        return 0;
+    }
+
+    // Don't try to read more samples than can potentially fit in the output buffer.
+    if (samplesToRead * pWav->bytesPerSample > SIZE_MAX) {
+        samplesToRead = SIZE_MAX / pWav->bytesPerSample;
+    }
+
+    size_t bytesRead = drwav_read_raw(pWav, (size_t)(samplesToRead * pWav->bytesPerSample), pBufferOut);
+    return bytesRead / pWav->bytesPerSample;
+}
+
+drwav_bool32 drwav_seek_to_first_sample(drwav* pWav)
+{
+    if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) {
+        return DRWAV_FALSE;
+    }
+
+    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
+        pWav->compressed.iCurrentSample = 0;
+    }
+
+    pWav->bytesRemaining = pWav->dataChunkDataSize;
+    return DRWAV_TRUE;
+}
+
+drwav_bool32 drwav_seek_to_sample(drwav* pWav, drwav_uint64 sample)
+{
+    // Seeking should be compatible with wave files > 2GB.
+
+    if (pWav == NULL || pWav->onSeek == NULL) {
+        return DRWAV_FALSE;
+    }
+
+    // If there are no samples, just return DRWAV_TRUE without doing anything.
+    if (pWav->totalSampleCount == 0) {
+        return DRWAV_TRUE;
+    }
+
+    // Make sure the sample is clamped.
+    if (sample >= pWav->totalSampleCount) {
+        sample  = pWav->totalSampleCount - 1;
+    }
+
+
+    // For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need
+    // to seek back to the start.
+    if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) {
+        // TODO: This can be optimized.
+        if (sample > pWav->compressed.iCurrentSample) {
+            // Seeking forward - just move from the current position.
+            drwav_uint64 offset = sample - pWav->compressed.iCurrentSample;
+
+            drwav_int16 devnull[2048];
+            while (offset > 0) {
+                drwav_uint64 samplesToRead = sample;
+                if (samplesToRead > 2048) {
+                    samplesToRead = 2048;
+                }
+
+                drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull);
+                if (samplesRead != samplesToRead) {
+                    return DRWAV_FALSE;
+                }
+
+                offset -= samplesRead;
+            }
+        } else {
+            // Seeking backwards. Just use the fallback.
+            goto fallback;
+        }
+    } else {
+        drwav_uint64 totalSizeInBytes = pWav->totalSampleCount * pWav->bytesPerSample;
+        drwav_assert(totalSizeInBytes >= pWav->bytesRemaining);
+
+        drwav_uint64 currentBytePos = totalSizeInBytes - pWav->bytesRemaining;
+        drwav_uint64 targetBytePos  = sample * pWav->bytesPerSample;
+
+        drwav_uint64 offset;
+        if (currentBytePos < targetBytePos) {
+            // Offset forwards.
+            offset = (targetBytePos - currentBytePos);
+        } else {
+            // Offset backwards.
+            if (!drwav_seek_to_first_sample(pWav)) {
+                return DRWAV_FALSE;
+            }
+            offset = targetBytePos;
+        }
+
+        while (offset > 0) {
+            int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset);
+            if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) {
+                return DRWAV_FALSE;
+            }
+
+            pWav->bytesRemaining -= offset32;
+            offset -= offset32;
+        }
+    }
+
+    return DRWAV_TRUE;
+
+fallback:
+    // This is a generic seek implementation that just continuously reads samples into a temporary buffer. This should work for all supported
+    // formats, but it is not efficient. This should be used as a fall back.
+    if (!drwav_seek_to_first_sample(pWav)) {
+        return DRWAV_FALSE;
+    }
+
+    drwav_int16 devnull[2048];
+    while (sample > 0) {
+        drwav_uint64 samplesToRead = sample;
+        if (samplesToRead > 2048) {
+            samplesToRead = 2048;
+        }
+
+        drwav_uint64 samplesRead = drwav_read_s16(pWav, samplesToRead, devnull);
+        if (samplesRead != samplesToRead) {
+            return DRWAV_FALSE;
+        }
+
+        sample -= samplesRead;
+    }
+
+    return DRWAV_TRUE;
+}
+
+
+size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData)
+{
+    if (pWav == NULL || bytesToWrite == 0 || pData == NULL) {
+        return 0;
+    }
+
+    size_t bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite);
+    pWav->dataChunkDataSize += bytesWritten;
+
+    return bytesWritten;
+}
+
+drwav_uint64 drwav_write(drwav* pWav, drwav_uint64 samplesToWrite, const void* pData)
+{
+    if (pWav == NULL || samplesToWrite == 0 || pData == NULL) {
+        return 0;
+    }
+
+    drwav_uint64 bytesToWrite = ((samplesToWrite * pWav->bitsPerSample) / 8);
+    if (bytesToWrite > SIZE_MAX) {
+        return 0;
+    }
+
+    size_t bytesWritten = drwav_write_raw(pWav, (size_t)bytesToWrite, pData);
+    return ((drwav_uint64)bytesWritten * 8) / pWav->bitsPerSample;
+}
+
+
+#ifndef DR_WAV_NO_CONVERSION_API
+static unsigned short g_drwavAlawTable[256] = {
+    0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580,
+    0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0,
+    0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600,
+    0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00,
+    0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58,
+    0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58,
+    0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960,
+    0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0,
+    0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80,
+    0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40,
+    0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00,
+    0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500,
+    0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8,
+    0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8,
+    0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0,
+    0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350
+};
+
+static unsigned short g_drwavMulawTable[256] = {
+    0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84,
+    0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84,
+    0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004,
+    0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844,
+    0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64,
+    0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74,
+    0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C,
+    0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000,
+    0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C,
+    0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C,
+    0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC,
+    0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC,
+    0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C,
+    0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C,
+    0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084,
+    0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000
+};
+
+static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn)
+{
+    return (short)g_drwavAlawTable[sampleIn];
+}
+
+static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn)
+{
+    return (short)g_drwavMulawTable[sampleIn];
+}
+
+
+
+static void drwav__pcm_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample)
+{
+    unsigned int i;
+    unsigned short j;
+    // Special case for 8-bit sample data because it's treated as unsigned.
+    if (bytesPerSample == 1) {
+        drwav_u8_to_s16(pOut, pIn, totalSampleCount);
+        return;
+    }
+
+
+    // Slightly more optimal implementation for common formats.
+    if (bytesPerSample == 2) {
+        for (i = 0; i < totalSampleCount; ++i) {
+           *pOut++ = ((drwav_int16*)pIn)[i];
+        }
+        return;
+    }
+    if (bytesPerSample == 3) {
+        drwav_s24_to_s16(pOut, pIn, totalSampleCount);
+        return;
+    }
+    if (bytesPerSample == 4) {
+        drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount);
+        return;
+    }
+
+
+    // Generic, slow converter.
+    for (i = 0; i < totalSampleCount; ++i) {
+        unsigned short sample = 0;
+        unsigned short shift  = (8 - bytesPerSample) * 8;
+        for (j = 0; j < bytesPerSample && j < 2; ++j) {
+            sample |= (unsigned short)(pIn[j]) << shift;
+            shift  += 8;
+        }
+
+        pIn += bytesPerSample;
+        *pOut++ = sample;
+    }
+}
+
+static void drwav__ieee_to_s16(drwav_int16* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample)
+{
+    if (bytesPerSample == 4) {
+        drwav_f32_to_s16(pOut, (float*)pIn, totalSampleCount);
+        return;
+    } else {
+        drwav_f64_to_s16(pOut, (double*)pIn, totalSampleCount);
+        return;
+    }
+}
+
+drwav_uint64 drwav_read_s16__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
+{
+    // Fast path.
+    if (pWav->bytesPerSample == 2) {
+        return drwav_read(pWav, samplesToRead, pBufferOut);
+    }
+
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
+{
+    drwav_assert(pWav != NULL);
+    drwav_assert(samplesToRead > 0);
+    drwav_assert(pBufferOut != NULL);
+
+    // TODO: Lots of room for optimization here.
+
+    drwav_uint64 totalSamplesRead = 0;
+
+    while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) {
+        // If there are no cached samples we need to load a new block.
+        if (pWav->msadpcm.cachedSampleCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) {
+            if (pWav->channels == 1) {
+                // Mono.
+                drwav_uint8 header[7];
+                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
+                    return totalSamplesRead;
+                }
+                pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
+
+                pWav->msadpcm.predictor[0] = header[0];
+                pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 1);
+                pWav->msadpcm.prevSamples[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3);
+                pWav->msadpcm.prevSamples[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5);
+                pWav->msadpcm.cachedSamples[2] = pWav->msadpcm.prevSamples[0][0];
+                pWav->msadpcm.cachedSamples[3] = pWav->msadpcm.prevSamples[0][1];
+                pWav->msadpcm.cachedSampleCount = 2;
+            } else {
+                // Stereo.
+                drwav_uint8 header[14];
+                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
+                    return totalSamplesRead;
+                }
+                pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
+
+                pWav->msadpcm.predictor[0] = header[0];
+                pWav->msadpcm.predictor[1] = header[1];
+                pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 2);
+                pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4);
+                pWav->msadpcm.prevSamples[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6);
+                pWav->msadpcm.prevSamples[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8);
+                pWav->msadpcm.prevSamples[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10);
+                pWav->msadpcm.prevSamples[1][0] = (drwav_int32)drwav__bytes_to_s16(header + 12);
+
+                pWav->msadpcm.cachedSamples[0] = pWav->msadpcm.prevSamples[0][0];
+                pWav->msadpcm.cachedSamples[1] = pWav->msadpcm.prevSamples[1][0];
+                pWav->msadpcm.cachedSamples[2] = pWav->msadpcm.prevSamples[0][1];
+                pWav->msadpcm.cachedSamples[3] = pWav->msadpcm.prevSamples[1][1];
+                pWav->msadpcm.cachedSampleCount = 4;
+            }
+        }
+
+        // Output anything that's cached.
+        while (samplesToRead > 0 && pWav->msadpcm.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) {
+            pBufferOut[0] = (drwav_int16)pWav->msadpcm.cachedSamples[drwav_countof(pWav->msadpcm.cachedSamples) - pWav->msadpcm.cachedSampleCount];
+            pWav->msadpcm.cachedSampleCount -= 1;
+
+            pBufferOut += 1;
+            samplesToRead -= 1;
+            totalSamplesRead += 1;
+            pWav->compressed.iCurrentSample += 1;
+        }
+
+        if (samplesToRead == 0) {
+            return totalSamplesRead;
+        }
+
+
+        // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next
+        // loop iteration which will trigger the loading of a new block.
+        if (pWav->msadpcm.cachedSampleCount == 0) {
+            if (pWav->msadpcm.bytesRemainingInBlock == 0) {
+                continue;
+            } else {
+                drwav_uint8 nibbles;
+                if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) {
+                    return totalSamplesRead;
+                }
+                pWav->msadpcm.bytesRemainingInBlock -= 1;
+
+                // TODO: Optimize away these if statements.
+                drwav_int32 nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; }
+                drwav_int32 nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; }
+
+                static drwav_int32 adaptationTable[] = {
+                    230, 230, 230, 230, 307, 409, 512, 614,
+                    768, 614, 512, 409, 307, 230, 230, 230
+                };
+                static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460,  392 };
+                static drwav_int32 coeff2Table[] = { 0,  -256, 0, 64,  0,  -208, -232 };
+
+                if (pWav->channels == 1) {
+                    // Mono.
+                    drwav_int32 newSample0;
+                    newSample0  = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
+                    newSample0 += nibble0 * pWav->msadpcm.delta[0];
+                    newSample0  = drwav_clamp(newSample0, -32768, 32767);
+
+                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
+                    if (pWav->msadpcm.delta[0] < 16) {
+                        pWav->msadpcm.delta[0] = 16;
+                    }
+
+                    pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1];
+                    pWav->msadpcm.prevSamples[0][1] = newSample0;
+
+
+                    drwav_int32 newSample1;
+                    newSample1  = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
+                    newSample1 += nibble1 * pWav->msadpcm.delta[0];
+                    newSample1  = drwav_clamp(newSample1, -32768, 32767);
+
+                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8;
+                    if (pWav->msadpcm.delta[0] < 16) {
+                        pWav->msadpcm.delta[0] = 16;
+                    }
+
+                    pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1];
+                    pWav->msadpcm.prevSamples[0][1] = newSample1;
+
+
+                    pWav->msadpcm.cachedSamples[2] = newSample0;
+                    pWav->msadpcm.cachedSamples[3] = newSample1;
+                    pWav->msadpcm.cachedSampleCount = 2;
+                } else {
+                    // Stereo.
+
+                    // Left.
+                    drwav_int32 newSample0;
+                    newSample0  = ((pWav->msadpcm.prevSamples[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevSamples[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8;
+                    newSample0 += nibble0 * pWav->msadpcm.delta[0];
+                    newSample0  = drwav_clamp(newSample0, -32768, 32767);
+
+                    pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8;
+                    if (pWav->msadpcm.delta[0] < 16) {
+                        pWav->msadpcm.delta[0] = 16;
+                    }
+
+                    pWav->msadpcm.prevSamples[0][0] = pWav->msadpcm.prevSamples[0][1];
+                    pWav->msadpcm.prevSamples[0][1] = newSample0;
+
+
+                    // Right.
+                    drwav_int32 newSample1;
+                    newSample1  = ((pWav->msadpcm.prevSamples[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevSamples[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8;
+                    newSample1 += nibble1 * pWav->msadpcm.delta[1];
+                    newSample1  = drwav_clamp(newSample1, -32768, 32767);
+
+                    pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8;
+                    if (pWav->msadpcm.delta[1] < 16) {
+                        pWav->msadpcm.delta[1] = 16;
+                    }
+
+                    pWav->msadpcm.prevSamples[1][0] = pWav->msadpcm.prevSamples[1][1];
+                    pWav->msadpcm.prevSamples[1][1] = newSample1;
+
+                    pWav->msadpcm.cachedSamples[2] = newSample0;
+                    pWav->msadpcm.cachedSamples[3] = newSample1;
+                    pWav->msadpcm.cachedSampleCount = 2;
+                }
+            }
+        }
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
+{
+    drwav_uint32 iChannel;
+    drwav_uint32 iByte;
+    drwav_assert(pWav != NULL);
+    drwav_assert(samplesToRead > 0);
+    drwav_assert(pBufferOut != NULL);
+
+    // TODO: Lots of room for optimization here.
+
+    drwav_uint64 totalSamplesRead = 0;
+
+    while (samplesToRead > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) {
+        // If there are no cached samples we need to load a new block.
+        if (pWav->ima.cachedSampleCount == 0 && pWav->ima.bytesRemainingInBlock == 0) {
+            if (pWav->channels == 1) {
+                // Mono.
+                drwav_uint8 header[4];
+                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
+                    return totalSamplesRead;
+                }
+                pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
+
+                pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0);
+                pWav->ima.stepIndex[0] = header[2];
+                pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 1] = pWav->ima.predictor[0];
+                pWav->ima.cachedSampleCount = 1;
+            } else {
+                // Stereo.
+                drwav_uint8 header[8];
+                if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) {
+                    return totalSamplesRead;
+                }
+                pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header);
+
+                pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0);
+                pWav->ima.stepIndex[0] = header[2];
+                pWav->ima.predictor[1] = drwav__bytes_to_s16(header + 4);
+                pWav->ima.stepIndex[1] = header[6];
+
+                pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 2] = pWav->ima.predictor[0];
+                pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - 1] = pWav->ima.predictor[1];
+                pWav->ima.cachedSampleCount = 2;
+            }
+        }
+
+        // Output anything that's cached.
+        while (samplesToRead > 0 && pWav->ima.cachedSampleCount > 0 && pWav->compressed.iCurrentSample < pWav->totalSampleCount) {
+            pBufferOut[0] = (drwav_int16)pWav->ima.cachedSamples[drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount];
+            pWav->ima.cachedSampleCount -= 1;
+
+            pBufferOut += 1;
+            samplesToRead -= 1;
+            totalSamplesRead += 1;
+            pWav->compressed.iCurrentSample += 1;
+        }
+
+        if (samplesToRead == 0) {
+            return totalSamplesRead;
+        }
+
+        // If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next
+        // loop iteration which will trigger the loading of a new block.
+        if (pWav->ima.cachedSampleCount == 0) {
+            if (pWav->ima.bytesRemainingInBlock == 0) {
+                continue;
+            } else {
+                static drwav_int32 indexTable[16] = {
+                    -1, -1, -1, -1, 2, 4, 6, 8,
+                    -1, -1, -1, -1, 2, 4, 6, 8
+                };
+
+                static drwav_int32 stepTable[89] = {
+                    7,     8,     9,     10,    11,    12,    13,    14,    16,    17,
+                    19,    21,    23,    25,    28,    31,    34,    37,    41,    45,
+                    50,    55,    60,    66,    73,    80,    88,    97,    107,   118,
+                    130,   143,   157,   173,   190,   209,   230,   253,   279,   307,
+                    337,   371,   408,   449,   494,   544,   598,   658,   724,   796,
+                    876,   963,   1060,  1166,  1282,  1411,  1552,  1707,  1878,  2066,
+                    2272,  2499,  2749,  3024,  3327,  3660,  4026,  4428,  4871,  5358,
+                    5894,  6484,  7132,  7845,  8630,  9493,  10442, 11487, 12635, 13899,
+                    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+                };
+
+                // From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the
+                // left channel, 4 bytes for the right channel.
+                pWav->ima.cachedSampleCount = 8 * pWav->channels;
+                for (iChannel = 0; iChannel < pWav->channels; ++iChannel) {
+                    drwav_uint8 nibbles[4];
+                    if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) {
+                        return totalSamplesRead;
+                    }
+                    pWav->ima.bytesRemainingInBlock -= 4;
+
+                    for (iByte = 0; iByte < 4; ++iByte) {
+                        drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0);
+                        drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4);
+
+                        drwav_int32 step      = stepTable[pWav->ima.stepIndex[iChannel]];
+                        drwav_int32 predictor = pWav->ima.predictor[iChannel];
+
+                        drwav_int32      diff  = step >> 3;
+                        if (nibble0 & 1) diff += step >> 2;
+                        if (nibble0 & 2) diff += step >> 1;
+                        if (nibble0 & 4) diff += step;
+                        if (nibble0 & 8) diff  = -diff;
+
+                        predictor = drwav_clamp(predictor + diff, -32768, 32767);
+                        pWav->ima.predictor[iChannel] = predictor;
+                        pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1);
+                        pWav->ima.cachedSamples[(drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount) + (iByte*2+0)*pWav->channels + iChannel] = predictor;
+
+
+                        step      = stepTable[pWav->ima.stepIndex[iChannel]];
+                        predictor = pWav->ima.predictor[iChannel];
+
+                                         diff  = step >> 3;
+                        if (nibble1 & 1) diff += step >> 2;
+                        if (nibble1 & 2) diff += step >> 1;
+                        if (nibble1 & 4) diff += step;
+                        if (nibble1 & 8) diff  = -diff;
+
+                        predictor = drwav_clamp(predictor + diff, -32768, 32767);
+                        pWav->ima.predictor[iChannel] = predictor;
+                        pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1);
+                        pWav->ima.cachedSamples[(drwav_countof(pWav->ima.cachedSamples) - pWav->ima.cachedSampleCount) + (iByte*2+1)*pWav->channels + iChannel] = predictor;
+                    }
+                }
+            }
+        }
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s16__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s16__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s16__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)samplesRead);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s16(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut)
+{
+    if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) {
+        return 0;
+    }
+
+    // Don't try to read more samples than can potentially fit in the output buffer.
+    if (samplesToRead * sizeof(drwav_int16) > SIZE_MAX) {
+        samplesToRead = SIZE_MAX / sizeof(drwav_int16);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
+        return drwav_read_s16__pcm(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
+        return drwav_read_s16__msadpcm(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
+        return drwav_read_s16__ieee(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
+        return drwav_read_s16__alaw(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
+        return drwav_read_s16__mulaw(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
+        return drwav_read_s16__ima(pWav, samplesToRead, pBufferOut);
+    }
+
+    return 0;
+}
+
+void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    int r;
+    size_t i;
+    for (i = 0; i < sampleCount; ++i) {
+        int x = pIn[i];
+        r = x - 128;
+        r = r << 8;
+        pOut[i] = (short)r;
+    }
+}
+
+void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    int r;
+    size_t i;
+    for (i = 0; i < sampleCount; ++i) {
+        int x = ((int)(((unsigned int)(((unsigned char*)pIn)[i*3+0]) << 8) | ((unsigned int)(((unsigned char*)pIn)[i*3+1]) << 16) | ((unsigned int)(((unsigned char*)pIn)[i*3+2])) << 24)) >> 8;
+        r = x >> 8;
+        pOut[i] = (short)r;
+    }
+}
+
+void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount)
+{
+    int r;
+    size_t i;
+    for (i = 0; i < sampleCount; ++i) {
+        int x = pIn[i];
+        r = x >> 16;
+        pOut[i] = (short)r;
+    }
+}
+
+void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount)
+{
+/*
+    int r;
+    for (size_t i = 0; i < sampleCount; ++i) {
+        float x = pIn[i];
+        float c;
+        int s;
+        c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
+        s = ((*((int*)&x)) & 0x80000000) >> 31;
+        s = s + 32767;
+        r = (int)(c * s);
+        pOut[i] = (short)r;
+    }
+*/
+    fprintf(stderr, "Warning: drwav_f32_to_s16 has been deactivated!\n");
+}
+
+void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount)
+{
+/*
+    int r;
+    for (size_t i = 0; i < sampleCount; ++i) {
+        double x = pIn[i];
+        double c;
+        int s;
+        c = ((x < -1) ? -1 : ((x > 1) ? 1 : x));
+        s = (int)(((*((drwav_uint64*)&x)) & (drwav_uint64)0x8000000000000000) >> 63);
+        s = s + 32767;
+        r = (int)(c * s);
+        pOut[i] = (short)r;
+    }
+*/
+    fprintf(stderr, "Warning: drwav_f64_to_s16 has been deactivated!\n");
+}
+
+void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    for (i = 0; i < sampleCount; ++i) {
+        pOut[i] = drwav__alaw_to_s16(pIn[i]);
+    }
+}
+
+void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    for (i = 0; i < sampleCount; ++i) {
+        pOut[i] = drwav__mulaw_to_s16(pIn[i]);
+    }
+}
+
+
+
+static void drwav__pcm_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample)
+{
+    unsigned int i;
+    unsigned short j;
+    // Special case for 8-bit sample data because it's treated as unsigned.
+    if (bytesPerSample == 1) {
+        drwav_u8_to_f32(pOut, pIn, sampleCount);
+        return;
+    }
+
+    // Slightly more optimal implementation for common formats.
+    if (bytesPerSample == 2) {
+        drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount);
+        return;
+    }
+    if (bytesPerSample == 3) {
+        drwav_s24_to_f32(pOut, pIn, sampleCount);
+        return;
+    }
+    if (bytesPerSample == 4) {
+        drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount);
+        return;
+    }
+
+    // Generic, slow converter.
+    for (i = 0; i < sampleCount; ++i) {
+        unsigned int sample = 0;
+        unsigned int shift  = (8 - bytesPerSample) * 8;
+        for (j = 0; j < bytesPerSample && j < 4; ++j) {
+            sample |= (unsigned int)(pIn[j]) << shift;
+            shift  += 8;
+        }
+
+        pIn += bytesPerSample;
+        *pOut++ = (float)((int)sample / 2147483648.0);
+    }
+}
+
+static void drwav__ieee_to_f32(float* pOut, const unsigned char* pIn, size_t sampleCount, unsigned short bytesPerSample)
+{
+    unsigned int i;
+    if (bytesPerSample == 4) {
+        for (i = 0; i < sampleCount; ++i) {
+            *pOut++ = ((float*)pIn)[i];
+        }
+        return;
+    } else {
+        drwav_f64_to_f32(pOut, (double*)pIn, sampleCount);
+        return;
+    }
+}
+
+
+drwav_uint64 drwav_read_f32__pcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+        pBufferOut += samplesRead;
+
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_f32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
+{
+    // We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't
+    // want to duplicate that code.
+    drwav_uint64 totalSamplesRead = 0;
+    drwav_int16 samples16[2048];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead);   // <-- Safe cast because we're clamping to 2048.
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_f32__ima(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
+{
+    // We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't
+    // want to duplicate that code.
+    drwav_uint64 totalSamplesRead = 0;
+    drwav_int16 samples16[2048];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_s16_to_f32(pBufferOut, samples16, (size_t)samplesRead);   // <-- Safe cast because we're clamping to 2048.
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_f32__ieee(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
+{
+    // Fast path.
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bytesPerSample == 4) {
+        return drwav_read(pWav, samplesToRead, pBufferOut);
+    }
+
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_f32__alaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_f32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)samplesRead);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_f32(drwav* pWav, drwav_uint64 samplesToRead, float* pBufferOut)
+{
+    if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) {
+        return 0;
+    }
+
+    // Don't try to read more samples than can potentially fit in the output buffer.
+    if (samplesToRead * sizeof(float) > SIZE_MAX) {
+        samplesToRead = SIZE_MAX / sizeof(float);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
+        return drwav_read_f32__pcm(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
+        return drwav_read_f32__msadpcm(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
+        return drwav_read_f32__ieee(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
+        return drwav_read_f32__alaw(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
+        return drwav_read_f32__mulaw(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
+        return drwav_read_f32__ima(pWav, samplesToRead, pBufferOut);
+    }
+
+    return 0;
+}
+
+void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+#ifdef DR_WAV_LIBSNDFILE_COMPAT
+    // It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears
+    // libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note
+    // the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated
+    // correctness testing. This is disabled by default.
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = (pIn[i] / 256.0f) * 2 - 1;
+    }
+#else
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = (pIn[i] / 255.0f) * 2 - 1;
+    }
+#endif
+}
+
+void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = pIn[i] / 32768.0f;
+    }
+}
+
+void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        unsigned int s0 = pIn[i*3 + 0];
+        unsigned int s1 = pIn[i*3 + 1];
+        unsigned int s2 = pIn[i*3 + 2];
+
+        int sample32 = (int)((s0 << 8) | (s1 << 16) | (s2 << 24));
+        *pOut++ = (float)(sample32 / 2147483648.0);
+    }
+}
+
+void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = (float)(pIn[i] / 2147483648.0);
+    }
+}
+
+void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = (float)pIn[i];
+    }
+}
+
+void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f;
+    }
+}
+
+void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f;
+    }
+}
+
+
+
+static void drwav__pcm_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample)
+{
+    unsigned int i;
+    unsigned short j;
+    // Special case for 8-bit sample data because it's treated as unsigned.
+    if (bytesPerSample == 1) {
+        drwav_u8_to_s32(pOut, pIn, totalSampleCount);
+        return;
+    }
+
+    // Slightly more optimal implementation for common formats.
+    if (bytesPerSample == 2) {
+        drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount);
+        return;
+    }
+    if (bytesPerSample == 3) {
+        drwav_s24_to_s32(pOut, pIn, totalSampleCount);
+        return;
+    }
+    if (bytesPerSample == 4) {
+        for (i = 0; i < totalSampleCount; ++i) {
+           *pOut++ = ((drwav_int32*)pIn)[i];
+        }
+        return;
+    }
+
+    // Generic, slow converter.
+    for (i = 0; i < totalSampleCount; ++i) {
+        unsigned int sample = 0;
+        unsigned int shift  = (8 - bytesPerSample) * 8;
+        for (j = 0; j < bytesPerSample && j < 4; ++j) {
+            sample |= (unsigned int)(pIn[j]) << shift;
+            shift  += 8;
+        }
+
+        pIn += bytesPerSample;
+        *pOut++ = sample;
+    }
+}
+
+static void drwav__ieee_to_s32(drwav_int32* pOut, const unsigned char* pIn, size_t totalSampleCount, unsigned short bytesPerSample)
+{
+    if (bytesPerSample == 4) {
+        drwav_f32_to_s32(pOut, (float*)pIn, totalSampleCount);
+        return;
+    } else {
+        drwav_f64_to_s32(pOut, (double*)pIn, totalSampleCount);
+        return;
+    }
+}
+
+
+drwav_uint64 drwav_read_s32__pcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
+{
+    // Fast path.
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bytesPerSample == 4) {
+        return drwav_read(pWav, samplesToRead, pBufferOut);
+    }
+
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s32__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
+{
+    // We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't
+    // want to duplicate that code.
+    drwav_uint64 totalSamplesRead = 0;
+    drwav_int16 samples16[2048];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead);   // <-- Safe cast because we're clamping to 2048.
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s32__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
+{
+    // We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't
+    // want to duplicate that code.
+    drwav_uint64 totalSamplesRead = 0;
+    drwav_int16 samples16[2048];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read_s16(pWav, drwav_min(samplesToRead, 2048), samples16);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_s16_to_s32(pBufferOut, samples16, (size_t)samplesRead);   // <-- Safe cast because we're clamping to 2048.
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s32__ieee(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)samplesRead, pWav->bytesPerSample);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s32__alaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s32__mulaw(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
+{
+    drwav_uint64 totalSamplesRead = 0;
+    unsigned char sampleData[4096];
+    while (samplesToRead > 0) {
+        drwav_uint64 samplesRead = drwav_read(pWav, drwav_min(samplesToRead, sizeof(sampleData)/pWav->bytesPerSample), sampleData);
+        if (samplesRead == 0) {
+            break;
+        }
+
+        drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)samplesRead);
+
+        pBufferOut       += samplesRead;
+        samplesToRead    -= samplesRead;
+        totalSamplesRead += samplesRead;
+    }
+
+    return totalSamplesRead;
+}
+
+drwav_uint64 drwav_read_s32(drwav* pWav, drwav_uint64 samplesToRead, drwav_int32* pBufferOut)
+{
+    if (pWav == NULL || samplesToRead == 0 || pBufferOut == NULL) {
+        return 0;
+    }
+
+    // Don't try to read more samples than can potentially fit in the output buffer.
+    if (samplesToRead * sizeof(drwav_int32) > SIZE_MAX) {
+        samplesToRead = SIZE_MAX / sizeof(drwav_int32);
+    }
+
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) {
+        return drwav_read_s32__pcm(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) {
+        return drwav_read_s32__msadpcm(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) {
+        return drwav_read_s32__ieee(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) {
+        return drwav_read_s32__alaw(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) {
+        return drwav_read_s32__mulaw(pWav, samplesToRead, pBufferOut);
+    }
+
+    if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) {
+        return drwav_read_s32__ima(pWav, samplesToRead, pBufferOut);
+    }
+
+    return 0;
+}
+
+void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = ((int)pIn[i] - 128) << 24;
+    }
+}
+
+void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = pIn[i] << 16;
+    }
+}
+
+void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        unsigned int s0 = pIn[i*3 + 0];
+        unsigned int s1 = pIn[i*3 + 1];
+        unsigned int s2 = pIn[i*3 + 2];
+
+        drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24));
+        *pOut++ = sample32;
+    }
+}
+
+void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
+    }
+}
+
+void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]);
+    }
+}
+
+void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i = 0; i < sampleCount; ++i) {
+        *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16;
+    }
+}
+
+void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount)
+{
+    size_t i;
+    if (pOut == NULL || pIn == NULL) {
+        return;
+    }
+
+    for (i= 0; i < sampleCount; ++i) {
+        *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16;
+    }
+}
+
+
+
+drwav_int16* drwav__read_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    drwav_assert(pWav != NULL);
+
+    drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int16);
+    if (sampleDataSize > SIZE_MAX) {
+        drwav_uninit(pWav);
+        return NULL;    // File's too big.
+    }
+
+    drwav_int16* pSampleData = (drwav_int16*)DRWAV_MALLOC((size_t)sampleDataSize);    // <-- Safe cast due to the check above.
+    if (pSampleData == NULL) {
+        drwav_uninit(pWav);
+        return NULL;    // Failed to allocate memory.
+    }
+
+    drwav_uint64 samplesRead = drwav_read_s16(pWav, (size_t)pWav->totalSampleCount, pSampleData);
+    if (samplesRead != pWav->totalSampleCount) {
+        DRWAV_FREE(pSampleData);
+        drwav_uninit(pWav);
+        return NULL;    // There was an error reading the samples.
+    }
+
+    drwav_uninit(pWav);
+
+    if (sampleRate) *sampleRate = pWav->sampleRate;
+    if (channels) *channels = pWav->channels;
+    if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount;
+    return pSampleData;
+}
+
+float* drwav__read_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    drwav_assert(pWav != NULL);
+
+    drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(float);
+    if (sampleDataSize > SIZE_MAX) {
+        drwav_uninit(pWav);
+        return NULL;    // File's too big.
+    }
+
+    float* pSampleData = (float*)DRWAV_MALLOC((size_t)sampleDataSize);    // <-- Safe cast due to the check above.
+    if (pSampleData == NULL) {
+        drwav_uninit(pWav);
+        return NULL;    // Failed to allocate memory.
+    }
+
+    drwav_uint64 samplesRead = drwav_read_f32(pWav, (size_t)pWav->totalSampleCount, pSampleData);
+    if (samplesRead != pWav->totalSampleCount) {
+        DRWAV_FREE(pSampleData);
+        drwav_uninit(pWav);
+        return NULL;    // There was an error reading the samples.
+    }
+
+    drwav_uninit(pWav);
+
+    if (sampleRate) *sampleRate = pWav->sampleRate;
+    if (channels) *channels = pWav->channels;
+    if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount;
+    return pSampleData;
+}
+
+drwav_int32* drwav__read_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    drwav_assert(pWav != NULL);
+
+    drwav_uint64 sampleDataSize = pWav->totalSampleCount * sizeof(drwav_int32);
+    if (sampleDataSize > SIZE_MAX) {
+        drwav_uninit(pWav);
+        return NULL;    // File's too big.
+    }
+
+    drwav_int32* pSampleData = (drwav_int32*)DRWAV_MALLOC((size_t)sampleDataSize);    // <-- Safe cast due to the check above.
+    if (pSampleData == NULL) {
+        drwav_uninit(pWav);
+        return NULL;    // Failed to allocate memory.
+    }
+
+    drwav_uint64 samplesRead = drwav_read_s32(pWav, (size_t)pWav->totalSampleCount, pSampleData);
+    if (samplesRead != pWav->totalSampleCount) {
+        DRWAV_FREE(pSampleData);
+        drwav_uninit(pWav);
+        return NULL;    // There was an error reading the samples.
+    }
+
+    drwav_uninit(pWav);
+
+    if (sampleRate) *sampleRate = pWav->sampleRate;
+    if (channels) *channels = pWav->channels;
+    if (totalSampleCount) *totalSampleCount = pWav->totalSampleCount;
+    return pSampleData;
+}
+
+
+drwav_int16* drwav_open_and_read_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init(&wav, onRead, onSeek, pUserData)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount);
+}
+
+float* drwav_open_and_read_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init(&wav, onRead, onSeek, pUserData)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+drwav_int32* drwav_open_and_read_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init(&wav, onRead, onSeek, pUserData)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+#ifndef DR_WAV_NO_STDIO
+drwav_int16* drwav_open_and_read_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init_file(&wav, filename)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount);
+}
+
+float* drwav_open_and_read_file_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init_file(&wav, filename)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+drwav_int32* drwav_open_and_read_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init_file(&wav, filename)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount);
+}
+#endif
+
+drwav_int16* drwav_open_and_read_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init_memory(&wav, data, dataSize)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_s16(&wav, channels, sampleRate, totalSampleCount);
+}
+
+float* drwav_open_and_read_memory_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init_memory(&wav, data, dataSize)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_f32(&wav, channels, sampleRate, totalSampleCount);
+}
+
+drwav_int32* drwav_open_and_read_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalSampleCount)
+{
+    if (sampleRate) *sampleRate = 0;
+    if (channels) *channels = 0;
+    if (totalSampleCount) *totalSampleCount = 0;
+
+    drwav wav;
+    if (!drwav_init_memory(&wav, data, dataSize)) {
+        return NULL;
+    }
+
+    return drwav__read_and_close_s32(&wav, channels, sampleRate, totalSampleCount);
+}
+#endif  //DR_WAV_NO_CONVERSION_API
+
+
+void drwav_free(void* pDataReturnedByOpenAndRead)
+{
+    DRWAV_FREE(pDataReturnedByOpenAndRead);
+}
+
+#endif  //DR_WAV_IMPLEMENTATION
+
+
+// REVISION HISTORY
+//
+// v0.7 - 2017-11-04
+//   - Add writing APIs.
+//
+// v0.6 - 2017-08-16
+//   - API CHANGE: Rename dr_* types to drwav_*.
+//   - Add support for custom implementations of malloc(), realloc(), etc.
+//   - Add support for Microsoft ADPCM.
+//   - Add support for IMA ADPCM (DVI, format code 0x11).
+//   - Optimizations to drwav_read_s16().
+//   - Bug fixes.
+//
+// v0.5g - 2017-07-16
+//   - Change underlying type for booleans to unsigned.
+//
+// v0.5f - 2017-04-04
+//   - Fix a minor bug with drwav_open_and_read_s16() and family.
+//
+// v0.5e - 2016-12-29
+//   - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this.
+//   - Minor fixes to documentation.
+//
+// v0.5d - 2016-12-28
+//   - Use drwav_int*/drwav_uint* sized types to improve compiler support.
+//
+// v0.5c - 2016-11-11
+//   - Properly handle JUNK chunks that come before the FMT chunk.
+//
+// v0.5b - 2016-10-23
+//   - A minor change to drwav_bool8 and drwav_bool32 types.
+//
+// v0.5a - 2016-10-11
+//   - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering.
+//   - Improve A-law and mu-law efficiency.
+//
+// v0.5 - 2016-09-29
+//   - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to
+//     keep it consistent with dr_audio and drwav_flac.
+//
+// v0.4b - 2016-09-18
+//   - Fixed a typo in documentation.
+//
+// v0.4a - 2016-09-18
+//   - Fixed a typo.
+//   - Change date format to ISO 8601 (YYYY-MM-DD)
+//
+// v0.4 - 2016-07-13
+//   - API CHANGE. Make onSeek consistent with drwav_flac.
+//   - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with drwav_flac.
+//   - Added support for Sony Wave64.
+//
+// v0.3a - 2016-05-28
+//   - API CHANGE. Return drwav_bool32 instead of int in onSeek callback.
+//   - Fixed a memory leak.
+//
+// v0.3 - 2016-05-22
+//   - Lots of API changes for consistency.
+//
+// v0.2a - 2016-05-16
+//   - Fixed Linux/GCC build.
+//
+// v0.2 - 2016-05-11
+//   - Added support for reading data as signed 32-bit PCM for consistency with drwav_flac.
+//
+// v0.1a - 2016-05-07
+//   - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize.
+//
+// v0.1 - 2016-05-04
+//   - Initial versioned release.
+
+
+/*
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
+*/
--- /dev/null
+++ b/lib/dr_wav/sp_dr_wav.h
@@ -1,0 +1,17 @@
+#ifndef SP_DRWAV_H
+#define SP_DRWAV_H
+#ifndef dr_wav_h
+typedef struct drwav drwav;
+#endif
+size_t sp_drwav_size(void);
+int sp_drwav_init_file(drwav* pWav, const char* filename);
+size_t sp_drwav_read_f32(drwav* pWav,
+                         size_t samplesToRead,
+                         float* pBufferOut);
+size_t sp_drwav_sampcount(drwav *wav);
+void sp_drwav_uninit(drwav *wav);
+int sp_drwav_seek_to_sample(drwav* pWav, size_t sample);
+drwav * sp_drwav_open_mono_write(const char *filename, int sr);
+size_t sp_drwav_write(drwav* pWav, size_t samplesToWrite, const void* pData);
+void sp_drwav_close(drwav* pWav);
+#endif
--- /dev/null
+++ b/lib/faust/CUI.h
@@ -1,0 +1,16 @@
+#include <stdlib.h>
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT SPFLOAT
+#endif
+
+typedef void (* addHorizontalSliderFun) (void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
+typedef void (* addVerticalSliderFun) (void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
+typedef void (* addCheckButtonFun) (void* ui_interface, const char* label, FAUSTFLOAT* zone);
+
+typedef struct {
+    void* uiInterface;
+    addHorizontalSliderFun addHorizontalSlider;
+    addVerticalSliderFun addVerticalSlider;
+    addCheckButtonFun addCheckButton;
+} UIGlue;
--- /dev/null
+++ b/lib/fft/Makefile
@@ -1,0 +1,9 @@
+LPATHS += lib/fft/fft.o
+UTIL += lib/fft/fft.c
+
+lib/fft/fft.c: lib/fft/fftlib.c lib/fft/sp_fft.c
+	echo "/* THIS IS A GENERATED FILE. DO NOT EDIT BY HAND */" > $@
+	cat $^ >> $@
+
+lib/fft/fft.o: lib/fft/fft.c
+	$(C89) $< -c $(CFLAGS) -o $@
--- /dev/null
+++ b/lib/fft/fftlib.c
@@ -1,0 +1,3080 @@
+/* Public domain FFT implementation in C by John Green */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include "base.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define POW2(m) ((uint32_t) 1 << (m))       /* integer power of 2 for m<32 */
+
+/* fft's with M bigger than this bust primary cache */
+#define MCACHE  (11 - (sizeof(SPFLOAT) / 8))
+
+/* some math constants to 40 decimal places */
+#define MYPI      3.141592653589793238462643383279502884197   /* pi         */
+#define MYROOT2   1.414213562373095048801688724209698078569   /* sqrt(2)    */
+#define MYCOSPID8 0.9238795325112867561281831893967882868224  /* cos(pi/8)  */
+#define MYSINPID8 0.3826834323650897717284599840303988667613  /* sin(pi/8)  */
+
+/*****************************************************
+* routines to initialize tables used by fft routines *
+*****************************************************/
+
+static void fftCosInit(int M, SPFLOAT *Utbl)
+{
+    /* Compute Utbl, the cosine table for ffts  */
+    /* of size (pow(2,M)/4 +1)                  */
+    /* INPUTS                                   */
+    /*   M = log2 of fft size                   */
+    /* OUTPUTS                                  */
+    /*   *Utbl = cosine table                   */
+    unsigned int fftN = POW2(M);
+    unsigned int i1;
+
+    Utbl[0] = 1.0;
+    for (i1 = 1; i1 < fftN/4; i1++)
+      Utbl[i1] = cos((2.0 * M_PI * (SPFLOAT)i1) / (SPFLOAT)fftN);
+    Utbl[fftN/4] = 0.0;
+}
+
+void fftBRInit(int M, int16_t *BRLow)
+{
+    /* Compute BRLow, the bit reversed table for ffts */
+    /* of size pow(2,M/2 -1)                          */
+    /* INPUTS                                         */
+    /*   M = log2 of fft size                         */
+    /* OUTPUTS                                        */
+    /*   *BRLow = bit reversed counter table          */
+    int Mroot_1 = M / 2 - 1;
+    int Nroot_1 = POW2(Mroot_1);
+    int i1;
+    int bitsum;
+    int bitmask;
+    int bit;
+
+    for (i1 = 0; i1 < Nroot_1; i1++) {
+      bitsum = 0;
+      bitmask = 1;
+      for (bit = 1; bit <= Mroot_1; bitmask <<= 1, bit++)
+        if (i1 & bitmask)
+          bitsum = bitsum + (Nroot_1 >> bit);
+      BRLow[i1] = bitsum;
+    }
+}
+
+/*****************
+* parts of ffts1 *
+*****************/
+
+static void bitrevR2(SPFLOAT *ioptr, int M, int16_t *BRLow)
+{
+    /*** bit reverse and first radix 2 stage of forward or inverse fft ***/
+    SPFLOAT f0r;
+    SPFLOAT f0i;
+    SPFLOAT f1r;
+    SPFLOAT f1i;
+    SPFLOAT f2r;
+    SPFLOAT f2i;
+    SPFLOAT f3r;
+    SPFLOAT f3i;
+    SPFLOAT f4r;
+    SPFLOAT f4i;
+    SPFLOAT f5r;
+    SPFLOAT f5i;
+    SPFLOAT f6r;
+    SPFLOAT f6i;
+    SPFLOAT f7r;
+    SPFLOAT f7i;
+    SPFLOAT t0r;
+    SPFLOAT t0i;
+    SPFLOAT t1r;
+    SPFLOAT t1i;
+    SPFLOAT *p0r;
+    SPFLOAT *p1r;
+    SPFLOAT *IOP;
+    SPFLOAT *iolimit;
+    int Colstart;
+    int iCol;
+    unsigned int posA;
+    unsigned int posAi;
+    unsigned int posB;
+    unsigned int posBi;
+
+    const unsigned int Nrems2 = POW2((M + 3) / 2);
+    const unsigned int Nroot_1_ColInc = POW2(M) - Nrems2;
+    const unsigned int Nroot_1 = POW2(M / 2 - 1) - 1;
+    const unsigned int ColstartShift = (M + 1) / 2 + 1;
+
+    posA = POW2(M);               /* 1/2 of POW2(M) complexes */
+    posAi = posA + 1;
+    posB = posA + 2;
+    posBi = posB + 1;
+
+    iolimit = ioptr + Nrems2;
+    for (; ioptr < iolimit; ioptr += POW2(M / 2 + 1)) {
+      for (Colstart = Nroot_1; Colstart >= 0; Colstart--) {
+        iCol = Nroot_1;
+        p0r = ioptr + Nroot_1_ColInc + BRLow[Colstart] * 4;
+        IOP = ioptr + (Colstart << ColstartShift);
+        p1r = IOP + BRLow[iCol] * 4;
+        f0r = *(p0r);
+        f0i = *(p0r + 1);
+        f1r = *(p0r + posA);
+        f1i = *(p0r + posAi);
+        for (; iCol > Colstart;) {
+          f2r = *(p0r + 2);
+          f2i = *(p0r + (2 + 1));
+          f3r = *(p0r + posB);
+          f3i = *(p0r + posBi);
+          f4r = *(p1r);
+          f4i = *(p1r + 1);
+          f5r = *(p1r + posA);
+          f5i = *(p1r + posAi);
+          f6r = *(p1r + 2);
+          f6i = *(p1r + (2 + 1));
+          f7r = *(p1r + posB);
+          f7i = *(p1r + posBi);
+
+          t0r = f0r + f1r;
+          t0i = f0i + f1i;
+          f1r = f0r - f1r;
+          f1i = f0i - f1i;
+          t1r = f2r + f3r;
+          t1i = f2i + f3i;
+          f3r = f2r - f3r;
+          f3i = f2i - f3i;
+          f0r = f4r + f5r;
+          f0i = f4i + f5i;
+          f5r = f4r - f5r;
+          f5i = f4i - f5i;
+          f2r = f6r + f7r;
+          f2i = f6i + f7i;
+          f7r = f6r - f7r;
+          f7i = f6i - f7i;
+
+          *(p1r) = t0r;
+          *(p1r + 1) = t0i;
+          *(p1r + 2) = f1r;
+          *(p1r + (2 + 1)) = f1i;
+          *(p1r + posA) = t1r;
+          *(p1r + posAi) = t1i;
+          *(p1r + posB) = f3r;
+          *(p1r + posBi) = f3i;
+          *(p0r) = f0r;
+          *(p0r + 1) = f0i;
+          *(p0r + 2) = f5r;
+          *(p0r + (2 + 1)) = f5i;
+          *(p0r + posA) = f2r;
+          *(p0r + posAi) = f2i;
+          *(p0r + posB) = f7r;
+          *(p0r + posBi) = f7i;
+
+          p0r -= Nrems2;
+          f0r = *(p0r);
+          f0i = *(p0r + 1);
+          f1r = *(p0r + posA);
+          f1i = *(p0r + posAi);
+          iCol -= 1;
+          p1r = IOP + BRLow[iCol] * 4;
+        }
+        f2r = *(p0r + 2);
+        f2i = *(p0r + (2 + 1));
+        f3r = *(p0r + posB);
+        f3i = *(p0r + posBi);
+
+        t0r = f0r + f1r;
+        t0i = f0i + f1i;
+        f1r = f0r - f1r;
+        f1i = f0i - f1i;
+        t1r = f2r + f3r;
+        t1i = f2i + f3i;
+        f3r = f2r - f3r;
+        f3i = f2i - f3i;
+
+        *(p0r) = t0r;
+        *(p0r + 1) = t0i;
+        *(p0r + 2) = f1r;
+        *(p0r + (2 + 1)) = f1i;
+        *(p0r + posA) = t1r;
+        *(p0r + posAi) = t1i;
+        *(p0r + posB) = f3r;
+        *(p0r + posBi) = f3i;
+      }
+    }
+}
+
+static void fft2pt(SPFLOAT *ioptr)
+{
+    /***   RADIX 2 fft      ***/
+    SPFLOAT f0r, f0i, f1r, f1i;
+    SPFLOAT t0r, t0i;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+    f1r = ioptr[2];
+    f1i = ioptr[3];
+
+    /* Butterflys           */
+    /*
+       f0   -       -       t0
+       f1   -  1 -  f1
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i + f1i;
+    f1r = f0r - f1r;
+    f1i = f0i - f1i;
+
+    /* store result */
+    ioptr[0] = t0r;
+    ioptr[1] = t0i;
+    ioptr[2] = f1r;
+    ioptr[3] = f1i;
+}
+
+static void fft4pt(SPFLOAT *ioptr)
+{
+    /***   RADIX 4 fft      ***/
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+    f1r = ioptr[4];
+    f1i = ioptr[5];
+    f2r = ioptr[2];
+    f2i = ioptr[3];
+    f3r = ioptr[6];
+    f3i = ioptr[7];
+
+    /* Butterflys           */
+    /*
+       f0   -       -       t0      -       -       f0
+       f1   -  1 -  f1      -       -       f1
+       f2   -       -       f2      -  1 -  f2
+       f3   -  1 -  t1      - -i -  f3
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i + f1i;
+    f1r = f0r - f1r;
+    f1i = f0i - f1i;
+
+    t1r = f2r - f3r;
+    t1i = f2i - f3i;
+    f2r = f2r + f3r;
+    f2i = f2i + f3i;
+
+    f0r = t0r + f2r;
+    f0i = t0i + f2i;
+    f2r = t0r - f2r;
+    f2i = t0i - f2i;
+
+    f3r = f1r - t1i;
+    f3i = f1i + t1r;
+    f1r = f1r + t1i;
+    f1i = f1i - t1r;
+
+    /* store result */
+    ioptr[0] = f0r;
+    ioptr[1] = f0i;
+    ioptr[2] = f1r;
+    ioptr[3] = f1i;
+    ioptr[4] = f2r;
+    ioptr[5] = f2i;
+    ioptr[6] = f3r;
+    ioptr[7] = f3i;
+}
+
+static void fft8pt(SPFLOAT *ioptr)
+{
+    /***   RADIX 8 fft      ***/
+    SPFLOAT w0r = (SPFLOAT)(1.0 / MYROOT2);    /* cos(pi/4)   */
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+    f1r = ioptr[8];
+    f1i = ioptr[9];
+    f2r = ioptr[4];
+    f2i = ioptr[5];
+    f3r = ioptr[12];
+    f3i = ioptr[13];
+    f4r = ioptr[2];
+    f4i = ioptr[3];
+    f5r = ioptr[10];
+    f5i = ioptr[11];
+    f6r = ioptr[6];
+    f6i = ioptr[7];
+    f7r = ioptr[14];
+    f7i = ioptr[15];
+    /* Butterflys           */
+    /*
+       f0   -       -       t0      -       -       f0      -       -       f0
+       f1   -  1 -  f1      -       -       f1      -       -       f1
+       f2   -       -       f2      -  1 -  f2      -       -       f2
+       f3   -  1 -  t1      - -i -  f3      -       -       f3
+       f4   -       -       t0      -       -       f4      -  1 -  t0
+       f5   -  1 -  f5      -       -       f5      - w3 -  f4
+       f6   -       -       f6      -  1 -  f6      - -i -  t1
+       f7   -  1 -  t1      - -i -  f7      - iw3-  f6
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i + f1i;
+    f1r = f0r - f1r;
+    f1i = f0i - f1i;
+
+    t1r = f2r - f3r;
+    t1i = f2i - f3i;
+    f2r = f2r + f3r;
+    f2i = f2i + f3i;
+
+    f0r = t0r + f2r;
+    f0i = t0i + f2i;
+    f2r = t0r - f2r;
+    f2i = t0i - f2i;
+
+    f3r = f1r - t1i;
+    f3i = f1i + t1r;
+    f1r = f1r + t1i;
+    f1i = f1i - t1r;
+
+    t0r = f4r + f5r;
+    t0i = f4i + f5i;
+    f5r = f4r - f5r;
+    f5i = f4i - f5i;
+
+    t1r = f6r - f7r;
+    t1i = f6i - f7i;
+    f6r = f6r + f7r;
+    f6i = f6i + f7i;
+
+    f4r = t0r + f6r;
+    f4i = t0i + f6i;
+    f6r = t0r - f6r;
+    f6i = t0i - f6i;
+
+    f7r = f5r - t1i;
+    f7i = f5i + t1r;
+    f5r = f5r + t1i;
+    f5i = f5i - t1r;
+
+    t0r = f0r - f4r;
+    t0i = f0i - f4i;
+    f0r = f0r + f4r;
+    f0i = f0i + f4i;
+
+    t1r = f2r - f6i;
+    t1i = f2i + f6r;
+    f2r = f2r + f6i;
+    f2i = f2i - f6r;
+
+    f4r = f1r - f5r * w0r - f5i * w0r;
+    f4i = f1i + f5r * w0r - f5i * w0r;
+    f1r = f1r * Two - f4r;
+    f1i = f1i * Two - f4i;
+
+    f6r = f3r + f7r * w0r - f7i * w0r;
+    f6i = f3i + f7r * w0r + f7i * w0r;
+    f3r = f3r * Two - f6r;
+    f3i = f3i * Two - f6i;
+
+    /* store result */
+    ioptr[0] = f0r;
+    ioptr[1] = f0i;
+    ioptr[2] = f1r;
+    ioptr[3] = f1i;
+    ioptr[4] = f2r;
+    ioptr[5] = f2i;
+    ioptr[6] = f3r;
+    ioptr[7] = f3i;
+    ioptr[8] = t0r;
+    ioptr[9] = t0i;
+    ioptr[10] = f4r;
+    ioptr[11] = f4i;
+    ioptr[12] = t1r;
+    ioptr[13] = t1i;
+    ioptr[14] = f6r;
+    ioptr[15] = f6i;
+}
+
+static void bfR2(SPFLOAT *ioptr, int M, int NDiffU)
+{
+    /*** 2nd radix 2 stage ***/
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int pinc;
+    unsigned int pnext;
+    unsigned int NSameU;
+    unsigned int SameUCnt;
+
+    SPFLOAT *pstrt;
+    SPFLOAT *p0r, *p1r, *p2r, *p3r;
+
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+
+    pinc = NDiffU * 2;            /* 2 floats per complex */
+    pnext = pinc * 4;
+    pos = 2;
+    posi = pos + 1;
+    NSameU = POW2(M) / 4 / NDiffU;        /* 4 Us at a time */
+    pstrt = ioptr;
+    p0r = pstrt;
+    p1r = pstrt + pinc;
+    p2r = p1r + pinc;
+    p3r = p2r + pinc;
+
+    /* Butterflys           */
+    /*
+       f0   -       -       f4
+       f1   -  1 -  f5
+       f2   -       -       f6
+       f3   -  1 -  f7
+     */
+    /* Butterflys           */
+    /*
+       f0   -       -       f4
+       f1   -  1 -  f5
+       f2   -       -       f6
+       f3   -  1 -  f7
+     */
+
+    for (SameUCnt = NSameU; SameUCnt > 0; SameUCnt--) {
+
+      f0r = *p0r;
+      f1r = *p1r;
+      f0i = *(p0r + 1);
+      f1i = *(p1r + 1);
+      f2r = *p2r;
+      f3r = *p3r;
+      f2i = *(p2r + 1);
+      f3i = *(p3r + 1);
+
+      f4r = f0r + f1r;
+      f4i = f0i + f1i;
+      f5r = f0r - f1r;
+      f5i = f0i - f1i;
+
+      f6r = f2r + f3r;
+      f6i = f2i + f3i;
+      f7r = f2r - f3r;
+      f7i = f2i - f3i;
+
+      *p0r = f4r;
+      *(p0r + 1) = f4i;
+      *p1r = f5r;
+      *(p1r + 1) = f5i;
+      *p2r = f6r;
+      *(p2r + 1) = f6i;
+      *p3r = f7r;
+      *(p3r + 1) = f7i;
+
+      f0r = *(p0r + pos);
+      f1i = *(p1r + posi);
+      f0i = *(p0r + posi);
+      f1r = *(p1r + pos);
+      f2r = *(p2r + pos);
+      f3i = *(p3r + posi);
+      f2i = *(p2r + posi);
+      f3r = *(p3r + pos);
+
+      f4r = f0r + f1i;
+      f4i = f0i - f1r;
+      f5r = f0r - f1i;
+      f5i = f0i + f1r;
+
+      f6r = f2r + f3i;
+      f6i = f2i - f3r;
+      f7r = f2r - f3i;
+      f7i = f2i + f3r;
+
+      *(p0r + pos) = f4r;
+      *(p0r + posi) = f4i;
+      *(p1r + pos) = f5r;
+      *(p1r + posi) = f5i;
+      *(p2r + pos) = f6r;
+      *(p2r + posi) = f6i;
+      *(p3r + pos) = f7r;
+      *(p3r + posi) = f7i;
+
+      p0r += pnext;
+      p1r += pnext;
+      p2r += pnext;
+      p3r += pnext;
+    }
+}
+
+static void bfR4(SPFLOAT *ioptr, int M, int NDiffU)
+{
+    /*** 1 radix 4 stage ***/
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int pinc;
+    unsigned int pnext;
+    unsigned int pnexti;
+    unsigned int NSameU;
+    unsigned int SameUCnt;
+
+    SPFLOAT *pstrt;
+    SPFLOAT *p0r, *p1r, *p2r, *p3r;
+
+    SPFLOAT w1r = 1.0 / MYROOT2;    /* cos(pi/4)   */
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+    SPFLOAT t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    pinc = NDiffU * 2;            /* 2 floats per complex */
+    pnext = pinc * 4;
+    pnexti = pnext + 1;
+    pos = 2;
+    posi = pos + 1;
+    NSameU = POW2(M) / 4 / NDiffU;        /* 4 pts per butterfly */
+    pstrt = ioptr;
+    p0r = pstrt;
+    p1r = pstrt + pinc;
+    p2r = p1r + pinc;
+    p3r = p2r + pinc;
+
+    /* Butterflys           */
+    /*
+       f0   -       -       f0      -       -       f4
+       f1   -  1 -  f5      -       -       f5
+       f2   -       -       f6      -  1 -  f6
+       f3   -  1 -  f3      - -i -  f7
+     */
+    /* Butterflys           */
+    /*
+       f0   -       -       f4      -       -       f4
+       f1   - -i -  t1      -       -       f5
+       f2   -       -       f2      - w1 -  f6
+       f3   - -i -  f7      - iw1-  f7
+     */
+
+    f0r = *p0r;
+    f1r = *p1r;
+    f2r = *p2r;
+    f3r = *p3r;
+    f0i = *(p0r + 1);
+    f1i = *(p1r + 1);
+    f2i = *(p2r + 1);
+    f3i = *(p3r + 1);
+
+    f5r = f0r - f1r;
+    f5i = f0i - f1i;
+    f0r = f0r + f1r;
+    f0i = f0i + f1i;
+
+    f6r = f2r + f3r;
+    f6i = f2i + f3i;
+    f3r = f2r - f3r;
+    f3i = f2i - f3i;
+
+    for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) {
+
+      f7r = f5r - f3i;
+      f7i = f5i + f3r;
+      f5r = f5r + f3i;
+      f5i = f5i - f3r;
+
+      f4r = f0r + f6r;
+      f4i = f0i + f6i;
+      f6r = f0r - f6r;
+      f6i = f0i - f6i;
+
+      f2r = *(p2r + pos);
+      f2i = *(p2r + posi);
+      f1r = *(p1r + pos);
+      f1i = *(p1r + posi);
+      f3i = *(p3r + posi);
+      f0r = *(p0r + pos);
+      f3r = *(p3r + pos);
+      f0i = *(p0r + posi);
+
+      *p3r = f7r;
+      *p0r = f4r;
+      *(p3r + 1) = f7i;
+      *(p0r + 1) = f4i;
+      *p1r = f5r;
+      *p2r = f6r;
+      *(p1r + 1) = f5i;
+      *(p2r + 1) = f6i;
+
+      f7r = f2r - f3i;
+      f7i = f2i + f3r;
+      f2r = f2r + f3i;
+      f2i = f2i - f3r;
+
+      f4r = f0r + f1i;
+      f4i = f0i - f1r;
+      t1r = f0r - f1i;
+      t1i = f0i + f1r;
+
+      f5r = t1r - f7r * w1r + f7i * w1r;
+      f5i = t1i - f7r * w1r - f7i * w1r;
+      f7r = t1r * Two - f5r;
+      f7i = t1i * Two - f5i;
+
+      f6r = f4r - f2r * w1r - f2i * w1r;
+      f6i = f4i + f2r * w1r - f2i * w1r;
+      f4r = f4r * Two - f6r;
+      f4i = f4i * Two - f6i;
+
+      f3r = *(p3r + pnext);
+      f0r = *(p0r + pnext);
+      f3i = *(p3r + pnexti);
+      f0i = *(p0r + pnexti);
+      f2r = *(p2r + pnext);
+      f2i = *(p2r + pnexti);
+      f1r = *(p1r + pnext);
+      f1i = *(p1r + pnexti);
+
+      *(p2r + pos) = f6r;
+      *(p1r + pos) = f5r;
+      *(p2r + posi) = f6i;
+      *(p1r + posi) = f5i;
+      *(p3r + pos) = f7r;
+      *(p0r + pos) = f4r;
+      *(p3r + posi) = f7i;
+      *(p0r + posi) = f4i;
+
+      f6r = f2r + f3r;
+      f6i = f2i + f3i;
+      f3r = f2r - f3r;
+      f3i = f2i - f3i;
+
+      f5r = f0r - f1r;
+      f5i = f0i - f1i;
+      f0r = f0r + f1r;
+      f0i = f0i + f1i;
+
+      p3r += pnext;
+      p0r += pnext;
+      p1r += pnext;
+      p2r += pnext;
+    }
+    f7r = f5r - f3i;
+    f7i = f5i + f3r;
+    f5r = f5r + f3i;
+    f5i = f5i - f3r;
+
+    f4r = f0r + f6r;
+    f4i = f0i + f6i;
+    f6r = f0r - f6r;
+    f6i = f0i - f6i;
+
+    f2r = *(p2r + pos);
+    f2i = *(p2r + posi);
+    f1r = *(p1r + pos);
+    f1i = *(p1r + posi);
+    f3i = *(p3r + posi);
+    f0r = *(p0r + pos);
+    f3r = *(p3r + pos);
+    f0i = *(p0r + posi);
+
+    *p3r = f7r;
+    *p0r = f4r;
+    *(p3r + 1) = f7i;
+    *(p0r + 1) = f4i;
+    *p1r = f5r;
+    *p2r = f6r;
+    *(p1r + 1) = f5i;
+    *(p2r + 1) = f6i;
+
+    f7r = f2r - f3i;
+    f7i = f2i + f3r;
+    f2r = f2r + f3i;
+    f2i = f2i - f3r;
+
+    f4r = f0r + f1i;
+    f4i = f0i - f1r;
+    t1r = f0r - f1i;
+    t1i = f0i + f1r;
+
+    f5r = t1r - f7r * w1r + f7i * w1r;
+    f5i = t1i - f7r * w1r - f7i * w1r;
+    f7r = t1r * Two - f5r;
+    f7i = t1i * Two - f5i;
+
+    f6r = f4r - f2r * w1r - f2i * w1r;
+    f6i = f4i + f2r * w1r - f2i * w1r;
+    f4r = f4r * Two - f6r;
+    f4i = f4i * Two - f6i;
+
+    *(p2r + pos) = f6r;
+    *(p1r + pos) = f5r;
+    *(p2r + posi) = f6i;
+    *(p1r + posi) = f5i;
+    *(p3r + pos) = f7r;
+    *(p0r + pos) = f4r;
+    *(p3r + posi) = f7i;
+    *(p0r + posi) = f4i;
+}
+
+static void bfstages(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int Ustride,
+                     int NDiffU, int StageCnt)
+{
+    /***   RADIX 8 Stages   ***/
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int pinc;
+    unsigned int pnext;
+    unsigned int NSameU;
+    int          Uinc;
+    int          Uinc2;
+    int          Uinc4;
+    unsigned int DiffUCnt;
+    unsigned int SameUCnt;
+    unsigned int U2toU3;
+
+    SPFLOAT *pstrt;
+    SPFLOAT *p0r, *p1r, *p2r, *p3r;
+    SPFLOAT *u0r, *u0i, *u1r, *u1i, *u2r, *u2i;
+
+    SPFLOAT w0r, w0i, w1r, w1i, w2r, w2i, w3r, w3i;
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    pinc = NDiffU * 2;            /* 2 floats per complex */
+    pnext = pinc * 8;
+    pos = pinc * 4;
+    posi = pos + 1;
+    NSameU = POW2(M) / 8 / NDiffU;        /* 8 pts per butterfly */
+    Uinc = (int) NSameU * Ustride;
+    Uinc2 = Uinc * 2;
+    Uinc4 = Uinc * 4;
+    U2toU3 = (POW2(M) / 8) * Ustride;
+    for (; StageCnt > 0; StageCnt--) {
+
+      u0r = &Utbl[0];
+      u0i = &Utbl[POW2(M - 2) * Ustride];
+      u1r = u0r;
+      u1i = u0i;
+      u2r = u0r;
+      u2i = u0i;
+
+      w0r = *u0r;
+      w0i = *u0i;
+      w1r = *u1r;
+      w1i = *u1i;
+      w2r = *u2r;
+      w2i = *u2i;
+      w3r = *(u2r + U2toU3);
+      w3i = *(u2i - U2toU3);
+
+      pstrt = ioptr;
+
+      p0r = pstrt;
+      p1r = pstrt + pinc;
+      p2r = p1r + pinc;
+      p3r = p2r + pinc;
+
+      /* Butterflys           */
+      /*
+         f0   -       -       t0      -       -       f0      -       -       f0
+         f1   - w0-   f1      -       -       f1      -       -       f1
+         f2   -       -       f2      - w1-   f2      -       -       f4
+         f3   - w0-   t1      - iw1-  f3      -       -       f5
+
+         f4   -       -       t0      -       -       f4      - w2-   t0
+         f5   - w0-   f5      -       -       f5      - w3-   t1
+         f6   -       -       f6      - w1-   f6      - iw2-  f6
+         f7   - w0-   t1      - iw1-  f7      - iw3-  f7
+       */
+
+      for (DiffUCnt = NDiffU; DiffUCnt > 0; DiffUCnt--) {
+        f0r = *p0r;
+        f0i = *(p0r + 1);
+        f1r = *p1r;
+        f1i = *(p1r + 1);
+        for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) {
+          f2r = *p2r;
+          f2i = *(p2r + 1);
+          f3r = *p3r;
+          f3i = *(p3r + 1);
+
+          t0r = f0r + f1r * w0r + f1i * w0i;
+          t0i = f0i - f1r * w0i + f1i * w0r;
+          f1r = f0r * Two - t0r;
+          f1i = f0i * Two - t0i;
+
+          f4r = *(p0r + pos);
+          f4i = *(p0r + posi);
+          f5r = *(p1r + pos);
+          f5i = *(p1r + posi);
+
+          f6r = *(p2r + pos);
+          f6i = *(p2r + posi);
+          f7r = *(p3r + pos);
+          f7i = *(p3r + posi);
+
+          t1r = f2r - f3r * w0r - f3i * w0i;
+          t1i = f2i + f3r * w0i - f3i * w0r;
+          f2r = f2r * Two - t1r;
+          f2i = f2i * Two - t1i;
+
+          f0r = t0r + f2r * w1r + f2i * w1i;
+          f0i = t0i - f2r * w1i + f2i * w1r;
+          f2r = t0r * Two - f0r;
+          f2i = t0i * Two - f0i;
+
+          f3r = f1r + t1r * w1i - t1i * w1r;
+          f3i = f1i + t1r * w1r + t1i * w1i;
+          f1r = f1r * Two - f3r;
+          f1i = f1i * Two - f3i;
+
+          t0r = f4r + f5r * w0r + f5i * w0i;
+          t0i = f4i - f5r * w0i + f5i * w0r;
+          f5r = f4r * Two - t0r;
+          f5i = f4i * Two - t0i;
+
+          t1r = f6r - f7r * w0r - f7i * w0i;
+          t1i = f6i + f7r * w0i - f7i * w0r;
+          f6r = f6r * Two - t1r;
+          f6i = f6i * Two - t1i;
+
+          f4r = t0r + f6r * w1r + f6i * w1i;
+          f4i = t0i - f6r * w1i + f6i * w1r;
+          f6r = t0r * Two - f4r;
+          f6i = t0i * Two - f4i;
+
+          f7r = f5r + t1r * w1i - t1i * w1r;
+          f7i = f5i + t1r * w1r + t1i * w1i;
+          f5r = f5r * Two - f7r;
+          f5i = f5i * Two - f7i;
+
+          t0r = f0r - f4r * w2r - f4i * w2i;
+          t0i = f0i + f4r * w2i - f4i * w2r;
+          f0r = f0r * Two - t0r;
+          f0i = f0i * Two - t0i;
+
+          t1r = f1r - f5r * w3r - f5i * w3i;
+          t1i = f1i + f5r * w3i - f5i * w3r;
+          f1r = f1r * Two - t1r;
+          f1i = f1i * Two - t1i;
+
+          *(p0r + pos) = t0r;
+          *(p1r + pos) = t1r;
+          *(p0r + posi) = t0i;
+          *(p1r + posi) = t1i;
+          *p0r = f0r;
+          *p1r = f1r;
+          *(p0r + 1) = f0i;
+          *(p1r + 1) = f1i;
+
+          p0r += pnext;
+          f0r = *p0r;
+          f0i = *(p0r + 1);
+
+          p1r += pnext;
+
+          f1r = *p1r;
+          f1i = *(p1r + 1);
+
+          f4r = f2r - f6r * w2i + f6i * w2r;
+          f4i = f2i - f6r * w2r - f6i * w2i;
+          f6r = f2r * Two - f4r;
+          f6i = f2i * Two - f4i;
+
+          f5r = f3r - f7r * w3i + f7i * w3r;
+          f5i = f3i - f7r * w3r - f7i * w3i;
+          f7r = f3r * Two - f5r;
+          f7i = f3i * Two - f5i;
+
+          *p2r = f4r;
+          *p3r = f5r;
+          *(p2r + 1) = f4i;
+          *(p3r + 1) = f5i;
+          *(p2r + pos) = f6r;
+          *(p3r + pos) = f7r;
+          *(p2r + posi) = f6i;
+          *(p3r + posi) = f7i;
+
+          p2r += pnext;
+          p3r += pnext;
+        }
+
+        f2r = *p2r;
+        f2i = *(p2r + 1);
+        f3r = *p3r;
+        f3i = *(p3r + 1);
+
+        t0r = f0r + f1r * w0r + f1i * w0i;
+        t0i = f0i - f1r * w0i + f1i * w0r;
+        f1r = f0r * Two - t0r;
+        f1i = f0i * Two - t0i;
+
+        f4r = *(p0r + pos);
+        f4i = *(p0r + posi);
+        f5r = *(p1r + pos);
+        f5i = *(p1r + posi);
+
+        f6r = *(p2r + pos);
+        f6i = *(p2r + posi);
+        f7r = *(p3r + pos);
+        f7i = *(p3r + posi);
+
+        t1r = f2r - f3r * w0r - f3i * w0i;
+        t1i = f2i + f3r * w0i - f3i * w0r;
+        f2r = f2r * Two - t1r;
+        f2i = f2i * Two - t1i;
+
+        f0r = t0r + f2r * w1r + f2i * w1i;
+        f0i = t0i - f2r * w1i + f2i * w1r;
+        f2r = t0r * Two - f0r;
+        f2i = t0i * Two - f0i;
+
+        f3r = f1r + t1r * w1i - t1i * w1r;
+        f3i = f1i + t1r * w1r + t1i * w1i;
+        f1r = f1r * Two - f3r;
+        f1i = f1i * Two - f3i;
+
+        if ((int) DiffUCnt == NDiffU / 2)
+          Uinc4 = -Uinc4;
+
+        u0r += Uinc4;
+        u0i -= Uinc4;
+        u1r += Uinc2;
+        u1i -= Uinc2;
+        u2r += Uinc;
+        u2i -= Uinc;
+
+        pstrt += 2;
+
+        t0r = f4r + f5r * w0r + f5i * w0i;
+        t0i = f4i - f5r * w0i + f5i * w0r;
+        f5r = f4r * Two - t0r;
+        f5i = f4i * Two - t0i;
+
+        t1r = f6r - f7r * w0r - f7i * w0i;
+        t1i = f6i + f7r * w0i - f7i * w0r;
+        f6r = f6r * Two - t1r;
+        f6i = f6i * Two - t1i;
+
+        f4r = t0r + f6r * w1r + f6i * w1i;
+        f4i = t0i - f6r * w1i + f6i * w1r;
+        f6r = t0r * Two - f4r;
+        f6i = t0i * Two - f4i;
+
+        f7r = f5r + t1r * w1i - t1i * w1r;
+        f7i = f5i + t1r * w1r + t1i * w1i;
+        f5r = f5r * Two - f7r;
+        f5i = f5i * Two - f7i;
+
+        w0r = *u0r;
+        w0i = *u0i;
+        w1r = *u1r;
+        w1i = *u1i;
+
+        if ((int) DiffUCnt <= NDiffU / 2)
+          w0r = -w0r;
+
+        t0r = f0r - f4r * w2r - f4i * w2i;
+        t0i = f0i + f4r * w2i - f4i * w2r;
+        f0r = f0r * Two - t0r;
+        f0i = f0i * Two - t0i;
+
+        f4r = f2r - f6r * w2i + f6i * w2r;
+        f4i = f2i - f6r * w2r - f6i * w2i;
+        f6r = f2r * Two - f4r;
+        f6i = f2i * Two - f4i;
+
+        *(p0r + pos) = t0r;
+        *p2r = f4r;
+        *(p0r + posi) = t0i;
+        *(p2r + 1) = f4i;
+        w2r = *u2r;
+        w2i = *u2i;
+        *p0r = f0r;
+        *(p2r + pos) = f6r;
+        *(p0r + 1) = f0i;
+        *(p2r + posi) = f6i;
+
+        p0r = pstrt;
+        p2r = pstrt + pinc + pinc;
+
+        t1r = f1r - f5r * w3r - f5i * w3i;
+        t1i = f1i + f5r * w3i - f5i * w3r;
+        f1r = f1r * Two - t1r;
+        f1i = f1i * Two - t1i;
+
+        f5r = f3r - f7r * w3i + f7i * w3r;
+        f5i = f3i - f7r * w3r - f7i * w3i;
+        f7r = f3r * Two - f5r;
+        f7i = f3i * Two - f5i;
+
+        *(p1r + pos) = t1r;
+        *p3r = f5r;
+        *(p1r + posi) = t1i;
+        *(p3r + 1) = f5i;
+        w3r = *(u2r + U2toU3);
+        w3i = *(u2i - U2toU3);
+        *p1r = f1r;
+        *(p3r + pos) = f7r;
+        *(p1r + 1) = f1i;
+        *(p3r + posi) = f7i;
+
+        p1r = pstrt + pinc;
+        p3r = p2r + pinc;
+      }
+      NSameU /= 8;
+      Uinc /= 8;
+      Uinc2 /= 8;
+      Uinc4 = Uinc * 4;
+      NDiffU *= 8;
+      pinc *= 8;
+      pnext *= 8;
+      pos *= 8;
+      posi = pos + 1;
+    }
+}
+
+static void fftrecurs(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int Ustride, int NDiffU,
+                      int StageCnt)
+{
+    /* recursive bfstages calls to maximize on chip cache efficiency */
+    int i1;
+
+    if (M <= (int) MCACHE)              /* fits on chip ? */
+      bfstages(ioptr, M, Utbl, Ustride, NDiffU, StageCnt); /* RADIX 8 Stages */
+    else {
+      for (i1 = 0; i1 < 8; i1++) {
+        fftrecurs(&ioptr[i1 * POW2(M - 3) * 2], M - 3, Utbl, 8 * Ustride,
+                  NDiffU, StageCnt - 1);  /*  RADIX 8 Stages      */
+      }
+      bfstages(ioptr, M, Utbl, Ustride, POW2(M - 3), 1);  /*  RADIX 8 Stage */
+    }
+}
+
+static void ffts1(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int16_t *BRLow)
+{
+    /* Compute in-place complex fft on the rows of the input array  */
+    /* INPUTS                                                       */
+    /*   *ioptr = input data array                                  */
+    /*   M = log2 of fft size (ex M=10 for 1024 point fft)          */
+    /*   *Utbl = cosine table                                       */
+    /*   *BRLow = bit reversed counter table                        */
+    /* OUTPUTS                                                      */
+    /*   *ioptr = output data array                                 */
+
+    int StageCnt;
+    int NDiffU;
+
+    switch (M) {
+    case 0:
+      break;
+    case 1:
+      fft2pt(ioptr);            /* a 2 pt fft */
+      break;
+    case 2:
+      fft4pt(ioptr);            /* a 4 pt fft */
+      break;
+    case 3:
+      fft8pt(ioptr);            /* an 8 pt fft */
+      break;
+    default:
+      bitrevR2(ioptr, M, BRLow);  /* bit reverse and first radix 2 stage */
+      StageCnt = (M - 1) / 3;     /* number of radix 8 stages           */
+      NDiffU = 2;                 /* one radix 2 stage already complete */
+      if ((M - 1 - (StageCnt * 3)) == 1) {
+        bfR2(ioptr, M, NDiffU); /* 1 radix 2 stage */
+        NDiffU *= 2;
+      }
+      if ((M - 1 - (StageCnt * 3)) == 2) {
+        bfR4(ioptr, M, NDiffU); /* 1 radix 4 stage */
+        NDiffU *= 4;
+      }
+      if (M <= (int) MCACHE)
+        bfstages(ioptr, M, Utbl, 1, NDiffU, StageCnt);  /* RADIX 8 Stages */
+      else
+        fftrecurs(ioptr, M, Utbl, 1, NDiffU, StageCnt); /* RADIX 8 Stages */
+    }
+}
+
+/******************
+* parts of iffts1 *
+******************/
+
+static void scbitrevR2(SPFLOAT *ioptr, int M, int16_t *BRLow, SPFLOAT scale)
+{
+    /*** scaled bit reverse and first radix 2 stage forward or inverse fft ***/
+    SPFLOAT f0r;
+    SPFLOAT f0i;
+    SPFLOAT f1r;
+    SPFLOAT f1i;
+    SPFLOAT f2r;
+    SPFLOAT f2i;
+    SPFLOAT f3r;
+    SPFLOAT f3i;
+    SPFLOAT f4r;
+    SPFLOAT f4i;
+    SPFLOAT f5r;
+    SPFLOAT f5i;
+    SPFLOAT f6r;
+    SPFLOAT f6i;
+    SPFLOAT f7r;
+    SPFLOAT f7i;
+    SPFLOAT t0r;
+    SPFLOAT t0i;
+    SPFLOAT t1r;
+    SPFLOAT t1i;
+    SPFLOAT *p0r;
+    SPFLOAT *p1r;
+    SPFLOAT *IOP;
+    SPFLOAT *iolimit;
+    int Colstart;
+    int iCol;
+    unsigned int posA;
+    unsigned int posAi;
+    unsigned int posB;
+    unsigned int posBi;
+
+    const unsigned int Nrems2 = POW2((M + 3) / 2);
+    const unsigned int Nroot_1_ColInc = POW2(M) - Nrems2;
+    const unsigned int Nroot_1 = POW2(M / 2 - 1) - 1;
+    const unsigned int ColstartShift = (M + 1) / 2 + 1;
+
+    posA = POW2(M);               /* 1/2 of POW2(M) complexes */
+    posAi = posA + 1;
+    posB = posA + 2;
+    posBi = posB + 1;
+
+    iolimit = ioptr + Nrems2;
+    for (; ioptr < iolimit; ioptr += POW2(M / 2 + 1)) {
+      for (Colstart = Nroot_1; Colstart >= 0; Colstart--) {
+        iCol = Nroot_1;
+        p0r = ioptr + Nroot_1_ColInc + BRLow[Colstart] * 4;
+        IOP = ioptr + (Colstart << ColstartShift);
+        p1r = IOP + BRLow[iCol] * 4;
+        f0r = *(p0r);
+        f0i = *(p0r + 1);
+        f1r = *(p0r + posA);
+        f1i = *(p0r + posAi);
+        for (; iCol > Colstart;) {
+          f2r = *(p0r + 2);
+          f2i = *(p0r + (2 + 1));
+          f3r = *(p0r + posB);
+          f3i = *(p0r + posBi);
+          f4r = *(p1r);
+          f4i = *(p1r + 1);
+          f5r = *(p1r + posA);
+          f5i = *(p1r + posAi);
+          f6r = *(p1r + 2);
+          f6i = *(p1r + (2 + 1));
+          f7r = *(p1r + posB);
+          f7i = *(p1r + posBi);
+
+          t0r = f0r + f1r;
+          t0i = f0i + f1i;
+          f1r = f0r - f1r;
+          f1i = f0i - f1i;
+          t1r = f2r + f3r;
+          t1i = f2i + f3i;
+          f3r = f2r - f3r;
+          f3i = f2i - f3i;
+          f0r = f4r + f5r;
+          f0i = f4i + f5i;
+          f5r = f4r - f5r;
+          f5i = f4i - f5i;
+          f2r = f6r + f7r;
+          f2i = f6i + f7i;
+          f7r = f6r - f7r;
+          f7i = f6i - f7i;
+
+          *(p1r) = scale * t0r;
+          *(p1r + 1) = scale * t0i;
+          *(p1r + 2) = scale * f1r;
+          *(p1r + (2 + 1)) = scale * f1i;
+          *(p1r + posA) = scale * t1r;
+          *(p1r + posAi) = scale * t1i;
+          *(p1r + posB) = scale * f3r;
+          *(p1r + posBi) = scale * f3i;
+          *(p0r) = scale * f0r;
+          *(p0r + 1) = scale * f0i;
+          *(p0r + 2) = scale * f5r;
+          *(p0r + (2 + 1)) = scale * f5i;
+          *(p0r + posA) = scale * f2r;
+          *(p0r + posAi) = scale * f2i;
+          *(p0r + posB) = scale * f7r;
+          *(p0r + posBi) = scale * f7i;
+
+          p0r -= Nrems2;
+          f0r = *(p0r);
+          f0i = *(p0r + 1);
+          f1r = *(p0r + posA);
+          f1i = *(p0r + posAi);
+          iCol -= 1;
+          p1r = IOP + BRLow[iCol] * 4;
+        }
+        f2r = *(p0r + 2);
+        f2i = *(p0r + (2 + 1));
+        f3r = *(p0r + posB);
+        f3i = *(p0r + posBi);
+
+        t0r = f0r + f1r;
+        t0i = f0i + f1i;
+        f1r = f0r - f1r;
+        f1i = f0i - f1i;
+        t1r = f2r + f3r;
+        t1i = f2i + f3i;
+        f3r = f2r - f3r;
+        f3i = f2i - f3i;
+
+        *(p0r) = scale * t0r;
+        *(p0r + 1) = scale * t0i;
+        *(p0r + 2) = scale * f1r;
+        *(p0r + (2 + 1)) = scale * f1i;
+        *(p0r + posA) = scale * t1r;
+        *(p0r + posAi) = scale * t1i;
+        *(p0r + posB) = scale * f3r;
+        *(p0r + posBi) = scale * f3i;
+      }
+    }
+}
+
+/* static void ifft2pt(SPFLOAT *ioptr, SPFLOAT scale) */
+/* { */
+/*     /\***   RADIX 2 ifft     ***\/ */
+/*     SPFLOAT f0r, f0i, f1r, f1i; */
+/*     SPFLOAT t0r, t0i; */
+
+/*     /\* bit reversed load *\/ */
+/*     f0r = ioptr[0]; */
+/*     f0i = ioptr[1]; */
+/*     f1r = ioptr[2]; */
+/*     f1i = ioptr[3]; */
+
+/*     /\* Butterflys           *\/ */
+/*     /\* */
+/*        f0   -       -       t0 */
+/*        f1   -  1 -  f1 */
+/*      *\/ */
+
+/*     t0r = f0r + f1r; */
+/*     t0i = f0i + f1i; */
+/*     f1r = f0r - f1r; */
+/*     f1i = f0i - f1i; */
+
+/*     /\* store result *\/ */
+/*     ioptr[0] = scale * t0r; */
+/*     ioptr[1] = scale * t0i; */
+/*     ioptr[2] = scale * f1r; */
+/*     ioptr[3] = scale * f1i; */
+/* } */
+
+/* static void ifft4pt(SPFLOAT *ioptr, SPFLOAT scale) */
+/* { */
+/*     /\***   RADIX 4 ifft     ***\/ */
+/*     SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; */
+/*     SPFLOAT t0r, t0i, t1r, t1i; */
+
+/*     /\* bit reversed load *\/ */
+/*     f0r = ioptr[0]; */
+/*     f0i = ioptr[1]; */
+/*     f1r = ioptr[4]; */
+/*     f1i = ioptr[5]; */
+/*     f2r = ioptr[2]; */
+/*     f2i = ioptr[3]; */
+/*     f3r = ioptr[6]; */
+/*     f3i = ioptr[7]; */
+
+/*     /\* Butterflys           *\/ */
+/*     /\* */
+/*        f0   -       -       t0      -       -       f0 */
+/*        f1   -  1 -  f1      -       -       f1 */
+/*        f2   -       -       f2      -  1 -  f2 */
+/*        f3   -  1 -  t1      -  i -  f3 */
+/*      *\/ */
+
+/*     t0r = f0r + f1r; */
+/*     t0i = f0i + f1i; */
+/*     f1r = f0r - f1r; */
+/*     f1i = f0i - f1i; */
+
+/*     t1r = f2r - f3r; */
+/*     t1i = f2i - f3i; */
+/*     f2r = f2r + f3r; */
+/*     f2i = f2i + f3i; */
+
+/*     f0r = t0r + f2r; */
+/*     f0i = t0i + f2i; */
+/*     f2r = t0r - f2r; */
+/*     f2i = t0i - f2i; */
+
+/*     f3r = f1r + t1i; */
+/*     f3i = f1i - t1r; */
+/*     f1r = f1r - t1i; */
+/*     f1i = f1i + t1r; */
+
+/*     /\* store result *\/ */
+/*     ioptr[0] = scale * f0r; */
+/*     ioptr[1] = scale * f0i; */
+/*     ioptr[2] = scale * f1r; */
+/*     ioptr[3] = scale * f1i; */
+/*     ioptr[4] = scale * f2r; */
+/*     ioptr[5] = scale * f2i; */
+/*     ioptr[6] = scale * f3r; */
+/*     ioptr[7] = scale * f3i; */
+/* } */
+
+/* static void ifft8pt(SPFLOAT *ioptr, SPFLOAT scale) */
+/* { */
+/*     /\***   RADIX 8 ifft     ***\/ */
+/*     SPFLOAT w0r = 1.0 / MYROOT2;    /\* cos(pi/4)   *\/ */
+/*     SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i; */
+/*     SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i; */
+/*     SPFLOAT t0r, t0i, t1r, t1i; */
+/*     const SPFLOAT Two = 2.0; */
+
+/*     /\* bit reversed load *\/ */
+/*     f0r = ioptr[0]; */
+/*     f0i = ioptr[1]; */
+/*     f1r = ioptr[8]; */
+/*     f1i = ioptr[9]; */
+/*     f2r = ioptr[4]; */
+/*     f2i = ioptr[5]; */
+/*     f3r = ioptr[12]; */
+/*     f3i = ioptr[13]; */
+/*     f4r = ioptr[2]; */
+/*     f4i = ioptr[3]; */
+/*     f5r = ioptr[10]; */
+/*     f5i = ioptr[11]; */
+/*     f6r = ioptr[6]; */
+/*     f6i = ioptr[7]; */
+/*     f7r = ioptr[14]; */
+/*     f7i = ioptr[15]; */
+
+/*     /\* Butterflys           *\/ */
+/*     /\* */
+/*        f0   -       -       t0      -       -       f0      -       -       f0 */
+/*        f1   -  1 -  f1      -       -       f1      -       -       f1 */
+/*        f2   -       -       f2      -  1 -  f2      -       -       f2 */
+/*        f3   -  1 -  t1      -  i -  f3      -       -       f3 */
+/*        f4   -       -       t0      -       -       f4      -  1 -  t0 */
+/*        f5   -  1 -  f5      -       -       f5      - w3 -  f4 */
+/*        f6   -       -       f6      -  1 -  f6      -  i -  t1 */
+/*        f7   -  1 -  t1      -  i -  f7      - iw3-  f6 */
+/*      *\/ */
+
+/*     t0r = f0r + f1r; */
+/*     t0i = f0i + f1i; */
+/*     f1r = f0r - f1r; */
+/*     f1i = f0i - f1i; */
+
+/*     t1r = f2r - f3r; */
+/*     t1i = f2i - f3i; */
+/*     f2r = f2r + f3r; */
+/*     f2i = f2i + f3i; */
+
+/*     f0r = t0r + f2r; */
+/*     f0i = t0i + f2i; */
+/*     f2r = t0r - f2r; */
+/*     f2i = t0i - f2i; */
+
+/*     f3r = f1r + t1i; */
+/*     f3i = f1i - t1r; */
+/*     f1r = f1r - t1i; */
+/*     f1i = f1i + t1r; */
+
+/*     t0r = f4r + f5r; */
+/*     t0i = f4i + f5i; */
+/*     f5r = f4r - f5r; */
+/*     f5i = f4i - f5i; */
+
+/*     t1r = f6r - f7r; */
+/*     t1i = f6i - f7i; */
+/*     f6r = f6r + f7r; */
+/*     f6i = f6i + f7i; */
+
+/*     f4r = t0r + f6r; */
+/*     f4i = t0i + f6i; */
+/*     f6r = t0r - f6r; */
+/*     f6i = t0i - f6i; */
+
+/*     f7r = f5r + t1i; */
+/*     f7i = f5i - t1r; */
+/*     f5r = f5r - t1i; */
+/*     f5i = f5i + t1r; */
+
+/*     t0r = f0r - f4r; */
+/*     t0i = f0i - f4i; */
+/*     f0r = f0r + f4r; */
+/*     f0i = f0i + f4i; */
+
+/*     t1r = f2r + f6i; */
+/*     t1i = f2i - f6r; */
+/*     f2r = f2r - f6i; */
+/*     f2i = f2i + f6r; */
+
+/*     f4r = f1r - f5r * w0r + f5i * w0r; */
+/*     f4i = f1i - f5r * w0r - f5i * w0r; */
+/*     f1r = f1r * Two - f4r; */
+/*     f1i = f1i * Two - f4i; */
+
+/*     f6r = f3r + f7r * w0r + f7i * w0r; */
+/*     f6i = f3i - f7r * w0r + f7i * w0r; */
+/*     f3r = f3r * Two - f6r; */
+/*     f3i = f3i * Two - f6i; */
+
+/*     /\* store result *\/ */
+/*     ioptr[0] = scale * f0r; */
+/*     ioptr[1] = scale * f0i; */
+/*     ioptr[2] = scale * f1r; */
+/*     ioptr[3] = scale * f1i; */
+/*     ioptr[4] = scale * f2r; */
+/*     ioptr[5] = scale * f2i; */
+/*     ioptr[6] = scale * f3r; */
+/*     ioptr[7] = scale * f3i; */
+/*     ioptr[8] = scale * t0r; */
+/*     ioptr[9] = scale * t0i; */
+/*     ioptr[10] = scale * f4r; */
+/*     ioptr[11] = scale * f4i; */
+/*     ioptr[12] = scale * t1r; */
+/*     ioptr[13] = scale * t1i; */
+/*     ioptr[14] = scale * f6r; */
+/*     ioptr[15] = scale * f6i; */
+/* } */
+
+static void ibfR2(SPFLOAT *ioptr, int M, int NDiffU)
+{
+    /*** 2nd radix 2 stage ***/
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int pinc;
+    unsigned int pnext;
+    unsigned int NSameU;
+    unsigned int SameUCnt;
+
+    SPFLOAT *pstrt;
+    SPFLOAT *p0r, *p1r, *p2r, *p3r;
+
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+
+    pinc = NDiffU * 2;            /* 2 floats per complex */
+    pnext = pinc * 4;
+    pos = 2;
+    posi = pos + 1;
+    NSameU = POW2(M) / 4 / NDiffU;        /* 4 Us at a time */
+    pstrt = ioptr;
+    p0r = pstrt;
+    p1r = pstrt + pinc;
+    p2r = p1r + pinc;
+    p3r = p2r + pinc;
+
+    /* Butterflys           */
+    /*
+       f0   -       -       f4
+       f1   -  1 -  f5
+       f2   -       -       f6
+       f3   -  1 -  f7
+     */
+    /* Butterflys           */
+    /*
+       f0   -       -       f4
+       f1   -  1 -  f5
+       f2   -       -       f6
+       f3   -  1 -  f7
+     */
+
+    for (SameUCnt = NSameU; SameUCnt > 0; SameUCnt--) {
+
+      f0r = *p0r;
+      f1r = *p1r;
+      f0i = *(p0r + 1);
+      f1i = *(p1r + 1);
+      f2r = *p2r;
+      f3r = *p3r;
+      f2i = *(p2r + 1);
+      f3i = *(p3r + 1);
+
+      f4r = f0r + f1r;
+      f4i = f0i + f1i;
+      f5r = f0r - f1r;
+      f5i = f0i - f1i;
+
+      f6r = f2r + f3r;
+      f6i = f2i + f3i;
+      f7r = f2r - f3r;
+      f7i = f2i - f3i;
+
+      *p0r = f4r;
+      *(p0r + 1) = f4i;
+      *p1r = f5r;
+      *(p1r + 1) = f5i;
+      *p2r = f6r;
+      *(p2r + 1) = f6i;
+      *p3r = f7r;
+      *(p3r + 1) = f7i;
+
+      f0r = *(p0r + pos);
+      f1i = *(p1r + posi);
+      f0i = *(p0r + posi);
+      f1r = *(p1r + pos);
+      f2r = *(p2r + pos);
+      f3i = *(p3r + posi);
+      f2i = *(p2r + posi);
+      f3r = *(p3r + pos);
+
+      f4r = f0r - f1i;
+      f4i = f0i + f1r;
+      f5r = f0r + f1i;
+      f5i = f0i - f1r;
+
+      f6r = f2r - f3i;
+      f6i = f2i + f3r;
+      f7r = f2r + f3i;
+      f7i = f2i - f3r;
+
+      *(p0r + pos) = f4r;
+      *(p0r + posi) = f4i;
+      *(p1r + pos) = f5r;
+      *(p1r + posi) = f5i;
+      *(p2r + pos) = f6r;
+      *(p2r + posi) = f6i;
+      *(p3r + pos) = f7r;
+      *(p3r + posi) = f7i;
+
+      p0r += pnext;
+      p1r += pnext;
+      p2r += pnext;
+      p3r += pnext;
+    }
+}
+
+static void ibfR4(SPFLOAT *ioptr, int M, int NDiffU)
+{
+    /*** 1 radix 4 stage ***/
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int pinc;
+    unsigned int pnext;
+    unsigned int pnexti;
+    unsigned int NSameU;
+    unsigned int SameUCnt;
+
+    SPFLOAT *pstrt;
+    SPFLOAT *p0r, *p1r, *p2r, *p3r;
+
+    SPFLOAT w1r = 1.0 / MYROOT2;    /* cos(pi/4)   */
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+    SPFLOAT t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    pinc = NDiffU * 2;            /* 2 floats per complex */
+    pnext = pinc * 4;
+    pnexti = pnext + 1;
+    pos = 2;
+    posi = pos + 1;
+    NSameU = POW2(M) / 4 / NDiffU;        /* 4 pts per butterfly */
+    pstrt = ioptr;
+    p0r = pstrt;
+    p1r = pstrt + pinc;
+    p2r = p1r + pinc;
+    p3r = p2r + pinc;
+
+    /* Butterflys           */
+    /*
+       f0   -       -       f0      -       -       f4
+       f1   -  1 -  f5      -       -       f5
+       f2   -       -       f6      -  1 -  f6
+       f3   -  1 -  f3      - -i -  f7
+     */
+    /* Butterflys           */
+    /*
+       f0   -       -       f4      -       -       f4
+       f1   - -i -  t1      -       -       f5
+       f2   -       -       f2      - w1 -  f6
+       f3   - -i -  f7      - iw1-  f7
+     */
+
+    f0r = *p0r;
+    f1r = *p1r;
+    f2r = *p2r;
+    f3r = *p3r;
+    f0i = *(p0r + 1);
+    f1i = *(p1r + 1);
+    f2i = *(p2r + 1);
+    f3i = *(p3r + 1);
+
+    f5r = f0r - f1r;
+    f5i = f0i - f1i;
+    f0r = f0r + f1r;
+    f0i = f0i + f1i;
+
+    f6r = f2r + f3r;
+    f6i = f2i + f3i;
+    f3r = f2r - f3r;
+    f3i = f2i - f3i;
+
+    for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) {
+
+      f7r = f5r + f3i;
+      f7i = f5i - f3r;
+      f5r = f5r - f3i;
+      f5i = f5i + f3r;
+
+      f4r = f0r + f6r;
+      f4i = f0i + f6i;
+      f6r = f0r - f6r;
+      f6i = f0i - f6i;
+
+      f2r = *(p2r + pos);
+      f2i = *(p2r + posi);
+      f1r = *(p1r + pos);
+      f1i = *(p1r + posi);
+      f3i = *(p3r + posi);
+      f0r = *(p0r + pos);
+      f3r = *(p3r + pos);
+      f0i = *(p0r + posi);
+
+      *p3r = f7r;
+      *p0r = f4r;
+      *(p3r + 1) = f7i;
+      *(p0r + 1) = f4i;
+      *p1r = f5r;
+      *p2r = f6r;
+      *(p1r + 1) = f5i;
+      *(p2r + 1) = f6i;
+
+      f7r = f2r + f3i;
+      f7i = f2i - f3r;
+      f2r = f2r - f3i;
+      f2i = f2i + f3r;
+
+      f4r = f0r - f1i;
+      f4i = f0i + f1r;
+      t1r = f0r + f1i;
+      t1i = f0i - f1r;
+
+      f5r = t1r - f7r * w1r - f7i * w1r;
+      f5i = t1i + f7r * w1r - f7i * w1r;
+      f7r = t1r * Two - f5r;
+      f7i = t1i * Two - f5i;
+
+      f6r = f4r - f2r * w1r + f2i * w1r;
+      f6i = f4i - f2r * w1r - f2i * w1r;
+      f4r = f4r * Two - f6r;
+      f4i = f4i * Two - f6i;
+
+      f3r = *(p3r + pnext);
+      f0r = *(p0r + pnext);
+      f3i = *(p3r + pnexti);
+      f0i = *(p0r + pnexti);
+      f2r = *(p2r + pnext);
+      f2i = *(p2r + pnexti);
+      f1r = *(p1r + pnext);
+      f1i = *(p1r + pnexti);
+
+      *(p2r + pos) = f6r;
+      *(p1r + pos) = f5r;
+      *(p2r + posi) = f6i;
+      *(p1r + posi) = f5i;
+      *(p3r + pos) = f7r;
+      *(p0r + pos) = f4r;
+      *(p3r + posi) = f7i;
+      *(p0r + posi) = f4i;
+
+      f6r = f2r + f3r;
+      f6i = f2i + f3i;
+      f3r = f2r - f3r;
+      f3i = f2i - f3i;
+
+      f5r = f0r - f1r;
+      f5i = f0i - f1i;
+      f0r = f0r + f1r;
+      f0i = f0i + f1i;
+
+      p3r += pnext;
+      p0r += pnext;
+      p1r += pnext;
+      p2r += pnext;
+    }
+    f7r = f5r + f3i;
+    f7i = f5i - f3r;
+    f5r = f5r - f3i;
+    f5i = f5i + f3r;
+
+    f4r = f0r + f6r;
+    f4i = f0i + f6i;
+    f6r = f0r - f6r;
+    f6i = f0i - f6i;
+
+    f2r = *(p2r + pos);
+    f2i = *(p2r + posi);
+    f1r = *(p1r + pos);
+    f1i = *(p1r + posi);
+    f3i = *(p3r + posi);
+    f0r = *(p0r + pos);
+    f3r = *(p3r + pos);
+    f0i = *(p0r + posi);
+
+    *p3r = f7r;
+    *p0r = f4r;
+    *(p3r + 1) = f7i;
+    *(p0r + 1) = f4i;
+    *p1r = f5r;
+    *p2r = f6r;
+    *(p1r + 1) = f5i;
+    *(p2r + 1) = f6i;
+
+    f7r = f2r + f3i;
+    f7i = f2i - f3r;
+    f2r = f2r - f3i;
+    f2i = f2i + f3r;
+
+    f4r = f0r - f1i;
+    f4i = f0i + f1r;
+    t1r = f0r + f1i;
+    t1i = f0i - f1r;
+
+    f5r = t1r - f7r * w1r - f7i * w1r;
+    f5i = t1i + f7r * w1r - f7i * w1r;
+    f7r = t1r * Two - f5r;
+    f7i = t1i * Two - f5i;
+
+    f6r = f4r - f2r * w1r + f2i * w1r;
+    f6i = f4i - f2r * w1r - f2i * w1r;
+    f4r = f4r * Two - f6r;
+    f4i = f4i * Two - f6i;
+
+    *(p2r + pos) = f6r;
+    *(p1r + pos) = f5r;
+    *(p2r + posi) = f6i;
+    *(p1r + posi) = f5i;
+    *(p3r + pos) = f7r;
+    *(p0r + pos) = f4r;
+    *(p3r + posi) = f7i;
+    *(p0r + posi) = f4i;
+}
+
+static void ibfstages(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int Ustride,
+                      int NDiffU, int StageCnt)
+{
+    /***   RADIX 8 Stages   ***/
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int pinc;
+    unsigned int pnext;
+    unsigned int NSameU;
+    int          Uinc;
+    int          Uinc2;
+    int          Uinc4;
+    unsigned int DiffUCnt;
+    unsigned int SameUCnt;
+    unsigned int U2toU3;
+
+    SPFLOAT *pstrt;
+    SPFLOAT *p0r, *p1r, *p2r, *p3r;
+    SPFLOAT *u0r, *u0i, *u1r, *u1i, *u2r, *u2i;
+
+    SPFLOAT w0r, w0i, w1r, w1i, w2r, w2i, w3r, w3i;
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    pinc = NDiffU * 2;            /* 2 floats per complex */
+    pnext = pinc * 8;
+    pos = pinc * 4;
+    posi = pos + 1;
+    NSameU = POW2(M) / 8 / NDiffU;        /* 8 pts per butterfly */
+    Uinc = (int) NSameU * Ustride;
+    Uinc2 = Uinc * 2;
+    Uinc4 = Uinc * 4;
+    U2toU3 = (POW2(M) / 8) * Ustride;
+    for (; StageCnt > 0; StageCnt--) {
+
+      u0r = &Utbl[0];
+      u0i = &Utbl[POW2(M - 2) * Ustride];
+      u1r = u0r;
+      u1i = u0i;
+      u2r = u0r;
+      u2i = u0i;
+
+      w0r = *u0r;
+      w0i = *u0i;
+      w1r = *u1r;
+      w1i = *u1i;
+      w2r = *u2r;
+      w2i = *u2i;
+      w3r = *(u2r + U2toU3);
+      w3i = *(u2i - U2toU3);
+
+      pstrt = ioptr;
+
+      p0r = pstrt;
+      p1r = pstrt + pinc;
+      p2r = p1r + pinc;
+      p3r = p2r + pinc;
+
+      /* Butterflys           */
+      /*
+         f0   -       -       t0      -       -       f0      -       -       f0
+         f1   - w0-   f1      -       -       f1      -       -       f1
+         f2   -       -       f2      - w1-   f2      -       -       f4
+         f3   - w0-   t1      - iw1-  f3      -       -       f5
+
+         f4   -       -       t0      -       -       f4      - w2-   t0
+         f5   - w0-   f5      -       -       f5      - w3-   t1
+         f6   -       -       f6      - w1-   f6      - iw2-  f6
+         f7   - w0-   t1      - iw1-  f7      - iw3-  f7
+       */
+
+      for (DiffUCnt = NDiffU; DiffUCnt > 0; DiffUCnt--) {
+        f0r = *p0r;
+        f0i = *(p0r + 1);
+        f1r = *p1r;
+        f1i = *(p1r + 1);
+        for (SameUCnt = NSameU - 1; SameUCnt > 0; SameUCnt--) {
+          f2r = *p2r;
+          f2i = *(p2r + 1);
+          f3r = *p3r;
+          f3i = *(p3r + 1);
+
+          t0r = f0r + f1r * w0r - f1i * w0i;
+          t0i = f0i + f1r * w0i + f1i * w0r;
+          f1r = f0r * Two - t0r;
+          f1i = f0i * Two - t0i;
+
+          f4r = *(p0r + pos);
+          f4i = *(p0r + posi);
+          f5r = *(p1r + pos);
+          f5i = *(p1r + posi);
+
+          f6r = *(p2r + pos);
+          f6i = *(p2r + posi);
+          f7r = *(p3r + pos);
+          f7i = *(p3r + posi);
+
+          t1r = f2r - f3r * w0r + f3i * w0i;
+          t1i = f2i - f3r * w0i - f3i * w0r;
+          f2r = f2r * Two - t1r;
+          f2i = f2i * Two - t1i;
+
+          f0r = t0r + f2r * w1r - f2i * w1i;
+          f0i = t0i + f2r * w1i + f2i * w1r;
+          f2r = t0r * Two - f0r;
+          f2i = t0i * Two - f0i;
+
+          f3r = f1r + t1r * w1i + t1i * w1r;
+          f3i = f1i - t1r * w1r + t1i * w1i;
+          f1r = f1r * Two - f3r;
+          f1i = f1i * Two - f3i;
+
+          t0r = f4r + f5r * w0r - f5i * w0i;
+          t0i = f4i + f5r * w0i + f5i * w0r;
+          f5r = f4r * Two - t0r;
+          f5i = f4i * Two - t0i;
+
+          t1r = f6r - f7r * w0r + f7i * w0i;
+          t1i = f6i - f7r * w0i - f7i * w0r;
+          f6r = f6r * Two - t1r;
+          f6i = f6i * Two - t1i;
+
+          f4r = t0r + f6r * w1r - f6i * w1i;
+          f4i = t0i + f6r * w1i + f6i * w1r;
+          f6r = t0r * Two - f4r;
+          f6i = t0i * Two - f4i;
+
+          f7r = f5r + t1r * w1i + t1i * w1r;
+          f7i = f5i - t1r * w1r + t1i * w1i;
+          f5r = f5r * Two - f7r;
+          f5i = f5i * Two - f7i;
+
+          t0r = f0r - f4r * w2r + f4i * w2i;
+          t0i = f0i - f4r * w2i - f4i * w2r;
+          f0r = f0r * Two - t0r;
+          f0i = f0i * Two - t0i;
+
+          t1r = f1r - f5r * w3r + f5i * w3i;
+          t1i = f1i - f5r * w3i - f5i * w3r;
+          f1r = f1r * Two - t1r;
+          f1i = f1i * Two - t1i;
+
+          *(p0r + pos) = t0r;
+          *(p0r + posi) = t0i;
+          *p0r = f0r;
+          *(p0r + 1) = f0i;
+
+          p0r += pnext;
+          f0r = *p0r;
+          f0i = *(p0r + 1);
+
+          *(p1r + pos) = t1r;
+          *(p1r + posi) = t1i;
+          *p1r = f1r;
+          *(p1r + 1) = f1i;
+
+          p1r += pnext;
+
+          f1r = *p1r;
+          f1i = *(p1r + 1);
+
+          f4r = f2r - f6r * w2i - f6i * w2r;
+          f4i = f2i + f6r * w2r - f6i * w2i;
+          f6r = f2r * Two - f4r;
+          f6i = f2i * Two - f4i;
+
+          f5r = f3r - f7r * w3i - f7i * w3r;
+          f5i = f3i + f7r * w3r - f7i * w3i;
+          f7r = f3r * Two - f5r;
+          f7i = f3i * Two - f5i;
+
+          *p2r = f4r;
+          *(p2r + 1) = f4i;
+          *(p2r + pos) = f6r;
+          *(p2r + posi) = f6i;
+
+          p2r += pnext;
+
+          *p3r = f5r;
+          *(p3r + 1) = f5i;
+          *(p3r + pos) = f7r;
+          *(p3r + posi) = f7i;
+
+          p3r += pnext;
+        }
+
+        f2r = *p2r;
+        f2i = *(p2r + 1);
+        f3r = *p3r;
+        f3i = *(p3r + 1);
+
+        t0r = f0r + f1r * w0r - f1i * w0i;
+        t0i = f0i + f1r * w0i + f1i * w0r;
+        f1r = f0r * Two - t0r;
+        f1i = f0i * Two - t0i;
+
+        f4r = *(p0r + pos);
+        f4i = *(p0r + posi);
+        f5r = *(p1r + pos);
+        f5i = *(p1r + posi);
+
+        f6r = *(p2r + pos);
+        f6i = *(p2r + posi);
+        f7r = *(p3r + pos);
+        f7i = *(p3r + posi);
+
+        t1r = f2r - f3r * w0r + f3i * w0i;
+        t1i = f2i - f3r * w0i - f3i * w0r;
+        f2r = f2r * Two - t1r;
+        f2i = f2i * Two - t1i;
+
+        f0r = t0r + f2r * w1r - f2i * w1i;
+        f0i = t0i + f2r * w1i + f2i * w1r;
+        f2r = t0r * Two - f0r;
+        f2i = t0i * Two - f0i;
+
+        f3r = f1r + t1r * w1i + t1i * w1r;
+        f3i = f1i - t1r * w1r + t1i * w1i;
+        f1r = f1r * Two - f3r;
+        f1i = f1i * Two - f3i;
+
+        if ((int) DiffUCnt == NDiffU / 2)
+          Uinc4 = -Uinc4;
+
+        u0r += Uinc4;
+        u0i -= Uinc4;
+        u1r += Uinc2;
+        u1i -= Uinc2;
+        u2r += Uinc;
+        u2i -= Uinc;
+
+        pstrt += 2;
+
+        t0r = f4r + f5r * w0r - f5i * w0i;
+        t0i = f4i + f5r * w0i + f5i * w0r;
+        f5r = f4r * Two - t0r;
+        f5i = f4i * Two - t0i;
+
+        t1r = f6r - f7r * w0r + f7i * w0i;
+        t1i = f6i - f7r * w0i - f7i * w0r;
+        f6r = f6r * Two - t1r;
+        f6i = f6i * Two - t1i;
+
+        f4r = t0r + f6r * w1r - f6i * w1i;
+        f4i = t0i + f6r * w1i + f6i * w1r;
+        f6r = t0r * Two - f4r;
+        f6i = t0i * Two - f4i;
+
+        f7r = f5r + t1r * w1i + t1i * w1r;
+        f7i = f5i - t1r * w1r + t1i * w1i;
+        f5r = f5r * Two - f7r;
+        f5i = f5i * Two - f7i;
+
+        w0r = *u0r;
+        w0i = *u0i;
+        w1r = *u1r;
+        w1i = *u1i;
+
+        if ((int) DiffUCnt <= NDiffU / 2)
+          w0r = -w0r;
+
+        t0r = f0r - f4r * w2r + f4i * w2i;
+        t0i = f0i - f4r * w2i - f4i * w2r;
+        f0r = f0r * Two - t0r;
+        f0i = f0i * Two - t0i;
+
+        f4r = f2r - f6r * w2i - f6i * w2r;
+        f4i = f2i + f6r * w2r - f6i * w2i;
+        f6r = f2r * Two - f4r;
+        f6i = f2i * Two - f4i;
+
+        *(p0r + pos) = t0r;
+        *p2r = f4r;
+        *(p0r + posi) = t0i;
+        *(p2r + 1) = f4i;
+        w2r = *u2r;
+        w2i = *u2i;
+        *p0r = f0r;
+        *(p2r + pos) = f6r;
+        *(p0r + 1) = f0i;
+        *(p2r + posi) = f6i;
+
+        p0r = pstrt;
+        p2r = pstrt + pinc + pinc;
+
+        t1r = f1r - f5r * w3r + f5i * w3i;
+        t1i = f1i - f5r * w3i - f5i * w3r;
+        f1r = f1r * Two - t1r;
+        f1i = f1i * Two - t1i;
+
+        f5r = f3r - f7r * w3i - f7i * w3r;
+        f5i = f3i + f7r * w3r - f7i * w3i;
+        f7r = f3r * Two - f5r;
+        f7i = f3i * Two - f5i;
+
+        *(p1r + pos) = t1r;
+        *p3r = f5r;
+        *(p1r + posi) = t1i;
+        *(p3r + 1) = f5i;
+        w3r = *(u2r + U2toU3);
+        w3i = *(u2i - U2toU3);
+        *p1r = f1r;
+        *(p3r + pos) = f7r;
+        *(p1r + 1) = f1i;
+        *(p3r + posi) = f7i;
+
+        p1r = pstrt + pinc;
+        p3r = p2r + pinc;
+      }
+      NSameU /= 8;
+      Uinc /= 8;
+      Uinc2 /= 8;
+      Uinc4 = Uinc * 4;
+      NDiffU *= 8;
+      pinc *= 8;
+      pnext *= 8;
+      pos *= 8;
+      posi = pos + 1;
+    }
+}
+
+static void ifftrecurs(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int Ustride,
+                       int NDiffU, int StageCnt)
+{
+    /* recursive bfstages calls to maximize on chip cache efficiency */
+    int i1;
+
+    if (M <= (int) MCACHE)
+      ibfstages(ioptr, M, Utbl, Ustride, NDiffU, StageCnt); /* RADIX 8 Stages */
+    else {
+      for (i1 = 0; i1 < 8; i1++) {
+        ifftrecurs(&ioptr[i1 * POW2(M - 3) * 2], M - 3, Utbl, 8 * Ustride,
+                   NDiffU, StageCnt - 1);           /*  RADIX 8 Stages       */
+      }
+      ibfstages(ioptr, M, Utbl, Ustride, POW2(M - 3), 1);   /* RADIX 8 Stage */
+    }
+}
+
+/* Paul: not currently used, so commented out */
+
+/* static void iffts1(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int16_t *BRLow) */
+/* { */
+/*     /\* Compute in-place inverse complex fft on the rows of the input array  *\/ */
+/*     /\* INPUTS                                                               *\/ */
+/*     /\*   *ioptr = input data array                                          *\/ */
+/*     /\*   M = log2 of fft size                                               *\/ */
+/*     /\*   *Utbl = cosine table                                               *\/ */
+/*     /\*   *BRLow = bit reversed counter table                                *\/ */
+/*     /\* OUTPUTS                                                              *\/ */
+/*     /\*   *ioptr = output data array                                         *\/ */
+
+/*     int StageCnt; */
+/*     int NDiffU; */
+/*     const SPFLOAT scale = 1.0 / POW2(M); */
+
+/*     switch (M) { */
+/*     case 0: */
+/*       break; */
+/*     case 1: */
+/*       ifft2pt(ioptr, scale);    /\* a 2 pt fft *\/ */
+/*       break; */
+/*     case 2: */
+/*       ifft4pt(ioptr, scale);    /\* a 4 pt fft *\/ */
+/*       break; */
+/*     case 3: */
+/*       ifft8pt(ioptr, scale);    /\* an 8 pt fft *\/ */
+/*       break; */
+/*     default: */
+/*       /\* bit reverse and first radix 2 stage *\/ */
+/*       scbitrevR2(ioptr, M, BRLow, scale); */
+/*       StageCnt = (M - 1) / 3;   /\* number of radix 8 stages *\/ */
+/*       NDiffU = 2;               /\* one radix 2 stage already complete *\/ */
+/*       if ((M - 1 - (StageCnt * 3)) == 1) { */
+/*         ibfR2(ioptr, M, NDiffU);        /\* 1 radix 2 stage *\/ */
+/*         NDiffU *= 2; */
+/*       } */
+/*       if ((M - 1 - (StageCnt * 3)) == 2) { */
+/*         ibfR4(ioptr, M, NDiffU);        /\* 1 radix 4 stage *\/ */
+/*         NDiffU *= 4; */
+/*       } */
+/*       if (M <= (int) MCACHE) */
+/*         ibfstages(ioptr, M, Utbl, 1, NDiffU, StageCnt);  /\* RADIX 8 Stages *\/ */
+/*       else */
+/*         ifftrecurs(ioptr, M, Utbl, 1, NDiffU, StageCnt); /\* RADIX 8 Stages *\/ */
+/*     } */
+/* } */
+
+/******************
+* parts of rffts1 *
+******************/
+
+static void rfft1pt(SPFLOAT *ioptr)
+{
+    /***   RADIX 2 rfft     ***/
+    SPFLOAT f0r, f0i;
+    SPFLOAT t0r, t0i;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+
+    /* finish rfft */
+    t0r = f0r + f0i;
+    t0i = f0r - f0i;
+
+    /* store result */
+    ioptr[0] = t0r;
+    ioptr[1] = t0i;
+}
+
+static void rfft2pt(SPFLOAT *ioptr)
+{
+    /***   RADIX 4 rfft     ***/
+    SPFLOAT f0r, f0i, f1r, f1i;
+    SPFLOAT t0r, t0i;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+    f1r = ioptr[2];
+    f1i = ioptr[3];
+
+    /* Butterflys           */
+    /*
+       f0   -       -       t0
+       f1   -  1 -  f1
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i + f1i;
+    f1r = f0r - f1r;
+    f1i = f1i - f0i;
+    /* finish rfft */
+    f0r = t0r + t0i;
+    f0i = t0r - t0i;
+
+    /* store result */
+    ioptr[0] = f0r;
+    ioptr[1] = f0i;
+    ioptr[2] = f1r;
+    ioptr[3] = f1i;
+}
+
+static void rfft4pt(SPFLOAT *ioptr)
+{
+    /***   RADIX 8 rfft     ***/
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    SPFLOAT w0r = 1.0 / MYROOT2;    /* cos(pi/4)   */
+    const SPFLOAT Two = 2.0;
+    const SPFLOAT scale = 0.5;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+    f1r = ioptr[4];
+    f1i = ioptr[5];
+    f2r = ioptr[2];
+    f2i = ioptr[3];
+    f3r = ioptr[6];
+    f3i = ioptr[7];
+
+    /* Butterflys           */
+    /*
+       f0   -       -       t0      -       -       f0
+       f1   -  1 -  f1      -       -       f1
+       f2   -       -       f2      -  1 -  f2
+       f3   -  1 -  t1      - -i -  f3
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i + f1i;
+    f1r = f0r - f1r;
+    f1i = f0i - f1i;
+
+    t1r = f2r - f3r;
+    t1i = f2i - f3i;
+    f2r = f2r + f3r;
+    f2i = f2i + f3i;
+
+    f0r = t0r + f2r;
+    f0i = t0i + f2i;
+    f2r = t0r - f2r;
+    f2i = f2i - t0i;              /* neg for rfft */
+
+    f3r = f1r - t1i;
+    f3i = f1i + t1r;
+    f1r = f1r + t1i;
+    f1i = f1i - t1r;
+
+    /* finish rfft */
+    t0r = f0r + f0i;              /* compute Re(x[0]) */
+    t0i = f0r - f0i;              /* compute Re(x[N/2]) */
+
+    t1r = f1r + f3r;
+    t1i = f1i - f3i;
+    f0r = f1i + f3i;
+    f0i = f3r - f1r;
+
+    f1r = t1r + w0r * f0r + w0r * f0i;
+    f1i = t1i - w0r * f0r + w0r * f0i;
+    f3r = Two * t1r - f1r;
+    f3i = f1i - Two * t1i;
+
+    /* store result */
+    ioptr[4] = f2r;
+    ioptr[5] = f2i;
+    ioptr[0] = t0r;
+    ioptr[1] = t0i;
+
+    ioptr[2] = scale * f1r;
+    ioptr[3] = scale * f1i;
+    ioptr[6] = scale * f3r;
+    ioptr[7] = scale * f3i;
+}
+
+static void rfft8pt(SPFLOAT *ioptr)
+{
+    /***   RADIX 16 rfft    ***/
+    SPFLOAT w0r = 1.0 / MYROOT2;    /* cos(pi/4)   */
+    SPFLOAT w1r = MYCOSPID8;        /* cos(pi/8)     */
+    SPFLOAT w1i = MYSINPID8;        /* sin(pi/8)     */
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    const SPFLOAT Two = 2.0;
+    const SPFLOAT scale = 0.5;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+    f1r = ioptr[8];
+    f1i = ioptr[9];
+    f2r = ioptr[4];
+    f2i = ioptr[5];
+    f3r = ioptr[12];
+    f3i = ioptr[13];
+    f4r = ioptr[2];
+    f4i = ioptr[3];
+    f5r = ioptr[10];
+    f5i = ioptr[11];
+    f6r = ioptr[6];
+    f6i = ioptr[7];
+    f7r = ioptr[14];
+    f7i = ioptr[15];
+    /* Butterflys           */
+    /*
+       f0   -       -       t0      -       -       f0      -       -       f0
+       f1   -  1 -  f1      -       -       f1      -       -       f1
+       f2   -       -       f2      -  1 -  f2      -       -       f2
+       f3   -  1 -  t1      - -i -  f3      -       -       f3
+       f4   -       -       t0      -       -       f4      -  1 -  t0
+       f5   -  1 -  f5      -       -       f5      - w3 -  f4
+       f6   -       -       f6      -  1 -  f6      - -i -  t1
+       f7   -  1 -  t1      - -i -  f7      - iw3-  f6
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i + f1i;
+    f1r = f0r - f1r;
+    f1i = f0i - f1i;
+
+    t1r = f2r - f3r;
+    t1i = f2i - f3i;
+    f2r = f2r + f3r;
+    f2i = f2i + f3i;
+
+    f0r = t0r + f2r;
+    f0i = t0i + f2i;
+    f2r = t0r - f2r;
+    f2i = t0i - f2i;
+
+    f3r = f1r - t1i;
+    f3i = f1i + t1r;
+    f1r = f1r + t1i;
+    f1i = f1i - t1r;
+
+    t0r = f4r + f5r;
+    t0i = f4i + f5i;
+    f5r = f4r - f5r;
+    f5i = f4i - f5i;
+
+    t1r = f6r - f7r;
+    t1i = f6i - f7i;
+    f6r = f6r + f7r;
+    f6i = f6i + f7i;
+
+    f4r = t0r + f6r;
+    f4i = t0i + f6i;
+    f6r = t0r - f6r;
+    f6i = t0i - f6i;
+
+    f7r = f5r - t1i;
+    f7i = f5i + t1r;
+    f5r = f5r + t1i;
+    f5i = f5i - t1r;
+
+    t0r = f0r - f4r;
+    t0i = f4i - f0i;              /* neg for rfft */
+    f0r = f0r + f4r;
+    f0i = f0i + f4i;
+
+    t1r = f2r - f6i;
+    t1i = f2i + f6r;
+    f2r = f2r + f6i;
+    f2i = f2i - f6r;
+
+    f4r = f1r - f5r * w0r - f5i * w0r;
+    f4i = f1i + f5r * w0r - f5i * w0r;
+    f1r = f1r * Two - f4r;
+    f1i = f1i * Two - f4i;
+
+    f6r = f3r + f7r * w0r - f7i * w0r;
+    f6i = f3i + f7r * w0r + f7i * w0r;
+    f3r = f3r * Two - f6r;
+    f3i = f3i * Two - f6i;
+
+    /* finish rfft */
+    f5r = f0r + f0i;              /* compute Re(x[0]) */
+    f5i = f0r - f0i;              /* compute Re(x[N/2]) */
+
+    f0r = f2r + t1r;
+    f0i = f2i - t1i;
+    f7r = f2i + t1i;
+    f7i = t1r - f2r;
+
+    f2r = f0r + w0r * f7r + w0r * f7i;
+    f2i = f0i - w0r * f7r + w0r * f7i;
+    t1r = Two * f0r - f2r;
+    t1i = f2i - Two * f0i;
+
+    f0r = f1r + f6r;
+    f0i = f1i - f6i;
+    f7r = f1i + f6i;
+    f7i = f6r - f1r;
+
+    f1r = f0r + w1r * f7r + w1i * f7i;
+    f1i = f0i - w1i * f7r + w1r * f7i;
+    f6r = Two * f0r - f1r;
+    f6i = f1i - Two * f0i;
+
+    f0r = f3r + f4r;
+    f0i = f3i - f4i;
+    f7r = f3i + f4i;
+    f7i = f4r - f3r;
+
+    f3r = f0r + w1i * f7r + w1r * f7i;
+    f3i = f0i - w1r * f7r + w1i * f7i;
+    f4r = Two * f0r - f3r;
+    f4i = f3i - Two * f0i;
+
+    /* store result */
+    ioptr[8] = t0r;
+    ioptr[9] = t0i;
+    ioptr[0] = f5r;
+    ioptr[1] = f5i;
+
+    ioptr[4] = scale * f2r;
+    ioptr[5] = scale * f2i;
+    ioptr[12] = scale * t1r;
+    ioptr[13] = scale * t1i;
+
+    ioptr[2] = scale * f1r;
+    ioptr[3] = scale * f1i;
+    ioptr[6] = scale * f3r;
+    ioptr[7] = scale * f3i;
+    ioptr[10] = scale * f4r;
+    ioptr[11] = scale * f4i;
+    ioptr[14] = scale * f6r;
+    ioptr[15] = scale * f6i;
+}
+
+static void frstage(SPFLOAT *ioptr, int M, SPFLOAT *Utbl)
+{
+    /*      Finish RFFT             */
+
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int diffUcnt;
+
+    SPFLOAT *p0r, *p1r;
+    SPFLOAT *u0r, *u0i;
+
+    SPFLOAT w0r, w0i;
+    SPFLOAT f0r, f0i, f1r, f1i, f4r, f4i, f5r, f5i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    pos = POW2(M - 1);
+    posi = pos + 1;
+
+    p0r = ioptr;
+    p1r = ioptr + pos / 2;
+
+    u0r = Utbl + POW2(M - 3);
+
+    w0r = *u0r; f0r = *(p0r);
+    f0i = *(p0r + 1);
+    f4r = *(p0r + pos);
+    f4i = *(p0r + posi);
+    f1r = *(p1r);
+    f1i = *(p1r + 1);
+    f5r = *(p1r + pos);
+    f5i = *(p1r + posi);
+
+    t0r = Two * f0r + Two * f0i;  /* compute Re(x[0]) */
+    t0i = Two * f0r - Two * f0i;  /* compute Re(x[N/2]) */
+    t1r = f4r + f4r;
+    t1i = -f4i - f4i;
+
+    f0r = f1r + f5r;
+    f0i = f1i - f5i;
+    f4r = f1i + f5i;
+    f4i = f5r - f1r;
+
+    f1r = f0r + w0r * f4r + w0r * f4i;
+    f1i = f0i - w0r * f4r + w0r * f4i;
+    f5r = Two * f0r - f1r;
+    f5i = f1i - Two * f0i;
+
+    *(p0r) = t0r;
+    *(p0r + 1) = t0i;
+    *(p0r + pos) = t1r;
+    *(p0r + posi) = t1i;
+    *(p1r) = f1r;
+    *(p1r + 1) = f1i;
+    *(p1r + pos) = f5r;
+    *(p1r + posi) = f5i;
+
+    u0r = Utbl + 1;
+    u0i = Utbl + (POW2(M - 2) - 1);
+
+    w0r = *u0r; w0i = *u0i;
+
+    p0r = (ioptr + 2);
+    p1r = (ioptr + (POW2(M - 2) - 1) * 2);
+
+    /* Butterflys */
+    /*
+       f0   -       t0      -       -       f0
+       f5   -       t1      - w0    -       f5
+
+       f1   -       t0      -       -       f1
+       f4   -       t1      -iw0 -  f4
+     */
+
+    for (diffUcnt = POW2(M - 3) - 1; diffUcnt > 0; diffUcnt--) {
+
+      f0r = *(p0r);
+      f0i = *(p0r + 1);
+      f5r = *(p1r + pos);
+      f5i = *(p1r + posi);
+      f1r = *(p1r);
+      f1i = *(p1r + 1);
+      f4r = *(p0r + pos);
+      f4i = *(p0r + posi);
+
+      t0r = f0r + f5r;
+      t0i = f0i - f5i;
+      t1r = f0i + f5i;
+      t1i = f5r - f0r;
+
+      f0r = t0r + w0r * t1r + w0i * t1i;
+      f0i = t0i - w0i * t1r + w0r * t1i;
+      f5r = Two * t0r - f0r;
+      f5i = f0i - Two * t0i;
+
+      t0r = f1r + f4r;
+      t0i = f1i - f4i;
+      t1r = f1i + f4i;
+      t1i = f4r - f1r;
+
+      f1r = t0r + w0i * t1r + w0r * t1i;
+      f1i = t0i - w0r * t1r + w0i * t1i;
+      f4r = Two * t0r - f1r;
+      f4i = f1i - Two * t0i;
+
+      *(p0r) = f0r;
+      *(p0r + 1) = f0i;
+      *(p1r + pos) = f5r;
+      *(p1r + posi) = f5i;
+
+      w0r = *++u0r;
+      w0i = *--u0i;
+
+      *(p1r) = f1r;
+      *(p1r + 1) = f1i;
+      *(p0r + pos) = f4r;
+      *(p0r + posi) = f4i;
+
+      p0r += 2;
+      p1r -= 2;
+    }
+}
+
+static void rffts1(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int16_t *BRLow)
+{
+    /* Compute in-place real fft on the rows of the input array           */
+    /* The result is the complex spectra of the positive frequencies      */
+    /* except the location for the first complex number contains the real */
+    /* values for DC and Nyquest                                          */
+    /* INPUTS                                                             */
+    /*   *ioptr = real input data array                                   */
+    /*   M = log2 of fft size                                             */
+    /*   *Utbl = cosine table                                             */
+    /*   *BRLow = bit reversed counter table                              */
+    /* OUTPUTS                                                            */
+    /*   *ioptr = output data array   in the following order              */
+    /*     Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]), Re(x[2]), Im(x[2]),  */
+    /*     ... Re(x[N/2-1]), Im(x[N/2-1]).                                */
+
+    SPFLOAT scale;
+    int StageCnt;
+    int NDiffU;
+
+    M = M - 1;
+    switch (M) {
+    case -1:
+      break;
+    case 0:
+      rfft1pt(ioptr);           /* a 2 pt fft */
+      break;
+    case 1:
+      rfft2pt(ioptr);           /* a 4 pt fft */
+      break;
+    case 2:
+      rfft4pt(ioptr);           /* an 8 pt fft */
+      break;
+    case 3:
+      rfft8pt(ioptr);           /* a 16 pt fft */
+      break;
+    default:
+      scale = 0.5;
+      /* bit reverse and first radix 2 stage */
+      scbitrevR2(ioptr, M, BRLow, scale);
+      StageCnt = (M - 1) / 3;   /* number of radix 8 stages           */
+      NDiffU = 2;               /* one radix 2 stage already complete */
+      if ((M - 1 - (StageCnt * 3)) == 1) {
+        bfR2(ioptr, M, NDiffU); /* 1 radix 2 stage */
+        NDiffU *= 2;
+      }
+      if ((M - 1 - (StageCnt * 3)) == 2) {
+        bfR4(ioptr, M, NDiffU); /* 1 radix 4 stage */
+        NDiffU *= 4;
+      }
+      if (M <= (int) MCACHE)
+        bfstages(ioptr, M, Utbl, 2, NDiffU, StageCnt);  /* RADIX 8 Stages */
+      else
+        fftrecurs(ioptr, M, Utbl, 2, NDiffU, StageCnt); /* RADIX 8 Stages */
+      frstage(ioptr, M + 1, Utbl);
+    }
+}
+
+/*******************
+* parts of riffts1 *
+*******************/
+
+static void rifft1pt(SPFLOAT *ioptr, SPFLOAT scale)
+{
+    /***   RADIX 2 rifft    ***/
+    SPFLOAT f0r, f0i;
+    SPFLOAT t0r, t0i;
+
+    /* bit reversed load */
+    f0r = ioptr[0];
+    f0i = ioptr[1];
+
+    /* finish rfft */
+    t0r = f0r + f0i;
+    t0i = f0r - f0i;
+
+    /* store result */
+    ioptr[0] = scale * t0r;
+    ioptr[1] = scale * t0i;
+}
+
+static void rifft2pt(SPFLOAT *ioptr, SPFLOAT scale)
+{
+    /***   RADIX 4 rifft    ***/
+    SPFLOAT f0r, f0i, f1r, f1i;
+    SPFLOAT t0r, t0i;
+    const SPFLOAT Two = 2.0;
+
+    /* bit reversed load */
+    t0r = ioptr[0];
+    t0i = ioptr[1];
+    f1r = Two * ioptr[2];
+    f1i = Two * ioptr[3];
+
+    /* start rifft */
+    f0r = t0r + t0i;
+    f0i = t0r - t0i;
+    /* Butterflys           */
+    /*
+       f0   -       -       t0
+       f1   -  1 -  f1
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i - f1i;
+    f1r = f0r - f1r;
+    f1i = f0i + f1i;
+
+    /* store result */
+    ioptr[0] = scale * t0r;
+    ioptr[1] = scale * t0i;
+    ioptr[2] = scale * f1r;
+    ioptr[3] = scale * f1i;
+}
+
+static void rifft4pt(SPFLOAT *ioptr, SPFLOAT scale)
+{
+    /***   RADIX 8 rifft    ***/
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    SPFLOAT w0r = 1.0 / MYROOT2;    /* cos(pi/4)   */
+    const SPFLOAT Two = 2.0;
+
+    /* bit reversed load */
+    t0r = ioptr[0];
+    t0i = ioptr[1];
+    f2r = ioptr[2];
+    f2i = ioptr[3];
+    f1r = Two * ioptr[4];
+    f1i = Two * ioptr[5];
+    f3r = ioptr[6];
+    f3i = ioptr[7];
+
+    /* start rfft */
+    f0r = t0r + t0i;              /* compute Re(x[0]) */
+    f0i = t0r - t0i;              /* compute Re(x[N/2]) */
+
+    t1r = f2r + f3r;
+    t1i = f2i - f3i;
+    t0r = f2r - f3r;
+    t0i = f2i + f3i;
+
+    f2r = t1r - w0r * t0r - w0r * t0i;
+    f2i = t1i + w0r * t0r - w0r * t0i;
+    f3r = Two * t1r - f2r;
+    f3i = f2i - Two * t1i;
+
+    /* Butterflys           */
+    /*
+       f0   -       -       t0      -       -       f0
+       f1   -  1 -  f1      -       -       f1
+       f2   -       -       f2      -  1 -  f2
+       f3   -  1 -  t1      -  i -  f3
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i - f1i;
+    f1r = f0r - f1r;
+    f1i = f0i + f1i;
+
+    t1r = f2r - f3r;
+    t1i = f2i - f3i;
+    f2r = f2r + f3r;
+    f2i = f2i + f3i;
+
+    f0r = t0r + f2r;
+    f0i = t0i + f2i;
+    f2r = t0r - f2r;
+    f2i = t0i - f2i;
+
+    f3r = f1r + t1i;
+    f3i = f1i - t1r;
+    f1r = f1r - t1i;
+    f1i = f1i + t1r;
+
+    /* store result */
+    ioptr[0] = scale * f0r;
+    ioptr[1] = scale * f0i;
+    ioptr[2] = scale * f1r;
+    ioptr[3] = scale * f1i;
+    ioptr[4] = scale * f2r;
+    ioptr[5] = scale * f2i;
+    ioptr[6] = scale * f3r;
+    ioptr[7] = scale * f3i;
+}
+
+static void rifft8pt(SPFLOAT *ioptr, SPFLOAT scale)
+{
+    /***   RADIX 16 rifft   ***/
+    SPFLOAT w0r = (SPFLOAT) (1.0 / MYROOT2);    /* cos(pi/4)    */
+    SPFLOAT w1r = MYCOSPID8;                  /* cos(pi/8)    */
+    SPFLOAT w1i = MYSINPID8;                  /* sin(pi/8)    */
+    SPFLOAT f0r, f0i, f1r, f1i, f2r, f2i, f3r, f3i;
+    SPFLOAT f4r, f4i, f5r, f5i, f6r, f6i, f7r, f7i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    /* bit reversed load */
+    t0r = ioptr[0];
+    t0i = ioptr[1];
+    f4r = ioptr[2];
+    f4i = ioptr[3];
+    f2r = ioptr[4];
+    f2i = ioptr[5];
+    f6r = ioptr[6];
+    f6i = ioptr[7];
+    f1r = Two * ioptr[8];
+    f1i = Two * ioptr[9];
+    f5r = ioptr[10];
+    f5i = ioptr[11];
+    f3r = ioptr[12];
+    f3i = ioptr[13];
+    f7r = ioptr[14];
+    f7i = ioptr[15];
+
+    /* start rfft */
+    f0r = t0r + t0i;              /* compute Re(x[0]) */
+    f0i = t0r - t0i;              /* compute Re(x[N/2]) */
+
+    t0r = f2r + f3r;
+    t0i = f2i - f3i;
+    t1r = f2r - f3r;
+    t1i = f2i + f3i;
+
+    f2r = t0r - w0r * t1r - w0r * t1i;
+    f2i = t0i + w0r * t1r - w0r * t1i;
+    f3r = Two * t0r - f2r;
+    f3i = f2i - Two * t0i;
+
+    t0r = f4r + f7r;
+    t0i = f4i - f7i;
+    t1r = f4r - f7r;
+    t1i = f4i + f7i;
+
+    f4r = t0r - w1i * t1r - w1r * t1i;
+    f4i = t0i + w1r * t1r - w1i * t1i;
+    f7r = Two * t0r - f4r;
+    f7i = f4i - Two * t0i;
+
+    t0r = f6r + f5r;
+    t0i = f6i - f5i;
+    t1r = f6r - f5r;
+    t1i = f6i + f5i;
+
+    f6r = t0r - w1r * t1r - w1i * t1i;
+    f6i = t0i + w1i * t1r - w1r * t1i;
+    f5r = Two * t0r - f6r;
+    f5i = f6i - Two * t0i;
+
+    /* Butterflys           */
+    /*
+       f0   -       -       t0      -       -       f0      -       -       f0
+       f1*  -  1 -  f1      -       -       f1      -       -       f1
+       f2   -       -       f2      -  1 -  f2      -       -       f2
+       f3   -  1 -  t1      -  i -  f3      -       -       f3
+       f4   -       -       t0      -       -       f4      -  1 -  t0
+       f5   -  1 -  f5      -       -       f5      - w3 -  f4
+       f6   -       -       f6      -  1 -  f6      -  i -  t1
+       f7   -  1 -  t1      -  i -  f7      - iw3-  f6
+     */
+
+    t0r = f0r + f1r;
+    t0i = f0i - f1i;
+    f1r = f0r - f1r;
+    f1i = f0i + f1i;
+
+    t1r = f2r - f3r;
+    t1i = f2i - f3i;
+    f2r = f2r + f3r;
+    f2i = f2i + f3i;
+
+    f0r = t0r + f2r;
+    f0i = t0i + f2i;
+    f2r = t0r - f2r;
+    f2i = t0i - f2i;
+
+    f3r = f1r + t1i;
+    f3i = f1i - t1r;
+    f1r = f1r - t1i;
+    f1i = f1i + t1r;
+
+    t0r = f4r + f5r;
+    t0i = f4i + f5i;
+    f5r = f4r - f5r;
+    f5i = f4i - f5i;
+
+    t1r = f6r - f7r;
+    t1i = f6i - f7i;
+    f6r = f6r + f7r;
+    f6i = f6i + f7i;
+
+    f4r = t0r + f6r;
+    f4i = t0i + f6i;
+    f6r = t0r - f6r;
+    f6i = t0i - f6i;
+
+    f7r = f5r + t1i;
+    f7i = f5i - t1r;
+    f5r = f5r - t1i;
+    f5i = f5i + t1r;
+
+    t0r = f0r - f4r;
+    t0i = f0i - f4i;
+    f0r = f0r + f4r;
+    f0i = f0i + f4i;
+
+    t1r = f2r + f6i;
+    t1i = f2i - f6r;
+    f2r = f2r - f6i;
+    f2i = f2i + f6r;
+
+    f4r = f1r - f5r * w0r + f5i * w0r;
+    f4i = f1i - f5r * w0r - f5i * w0r;
+    f1r = f1r * Two - f4r;
+    f1i = f1i * Two - f4i;
+
+    f6r = f3r + f7r * w0r + f7i * w0r;
+    f6i = f3i - f7r * w0r + f7i * w0r;
+    f3r = f3r * Two - f6r;
+    f3i = f3i * Two - f6i;
+
+    /* store result */
+    ioptr[0] = scale * f0r;
+    ioptr[1] = scale * f0i;
+    ioptr[2] = scale * f1r;
+    ioptr[3] = scale * f1i;
+    ioptr[4] = scale * f2r;
+    ioptr[5] = scale * f2i;
+    ioptr[6] = scale * f3r;
+    ioptr[7] = scale * f3i;
+    ioptr[8] = scale * t0r;
+    ioptr[9] = scale * t0i;
+    ioptr[10] = scale * f4r;
+    ioptr[11] = scale * f4i;
+    ioptr[12] = scale * t1r;
+    ioptr[13] = scale * t1i;
+    ioptr[14] = scale * f6r;
+    ioptr[15] = scale * f6i;
+}
+
+static void ifrstage(SPFLOAT *ioptr, int M, SPFLOAT *Utbl)
+{
+    /*      Start RIFFT             */
+
+    unsigned int pos;
+    unsigned int posi;
+    unsigned int diffUcnt;
+
+    SPFLOAT *p0r, *p1r;
+    SPFLOAT *u0r, *u0i;
+
+    SPFLOAT w0r, w0i;
+    SPFLOAT f0r, f0i, f1r, f1i, f4r, f4i, f5r, f5i;
+    SPFLOAT t0r, t0i, t1r, t1i;
+    const SPFLOAT Two = 2.0;
+
+    pos = POW2(M - 1);
+    posi = pos + 1;
+
+    p0r = ioptr;
+    p1r = ioptr + pos / 2;
+
+    u0r = Utbl + POW2(M - 3);
+
+    w0r = *u0r; f0r = *(p0r);
+    f0i = *(p0r + 1);
+    f4r = *(p0r + pos);
+    f4i = *(p0r + posi);
+    f1r = *(p1r);
+    f1i = *(p1r + 1);
+    f5r = *(p1r + pos);
+    f5i = *(p1r + posi);
+
+    t0r = f0r + f0i;
+    t0i = f0r - f0i;
+    t1r = f4r + f4r;
+    t1i = -f4i - f4i;
+
+    f0r = f1r + f5r;
+    f0i = f1i - f5i;
+    f4r = f1r - f5r;
+    f4i = f1i + f5i;
+
+    f1r = f0r - w0r * f4r - w0r * f4i;
+    f1i = f0i + w0r * f4r - w0r * f4i;
+    f5r = Two * f0r - f1r;
+    f5i = f1i - Two * f0i;
+
+    *(p0r) = t0r;
+    *(p0r + 1) = t0i;
+    *(p0r + pos) = t1r;
+    *(p0r + posi) = t1i;
+    *(p1r) = f1r;
+    *(p1r + 1) = f1i;
+    *(p1r + pos) = f5r;
+    *(p1r + posi) = f5i;
+
+    u0r = Utbl + 1;
+    u0i = Utbl + (POW2(M - 2) - 1);
+
+    w0r = *u0r; w0i = *u0i;
+
+    p0r = (ioptr + 2);
+    p1r = (ioptr + (POW2(M - 2) - 1) * 2);
+
+    /* Butterflys */
+    /*
+       f0   -        t0             -       f0
+       f1   -     t1     -w0-   f1
+
+       f2   -        t0             -       f2
+       f3   -     t1           -iw0-  f3
+     */
+
+    for (diffUcnt = POW2(M - 3) - 1; diffUcnt > 0; diffUcnt--) {
+
+      f0r = *(p0r);
+      f0i = *(p0r + 1);
+      f5r = *(p1r + pos);
+      f5i = *(p1r + posi);
+      f1r = *(p1r);
+      f1i = *(p1r + 1);
+      f4r = *(p0r + pos);
+      f4i = *(p0r + posi);
+
+      t0r = f0r + f5r;
+      t0i = f0i - f5i;
+      t1r = f0r - f5r;
+      t1i = f0i + f5i;
+
+      f0r = t0r - w0i * t1r - w0r * t1i;
+      f0i = t0i + w0r * t1r - w0i * t1i;
+      f5r = Two * t0r - f0r;
+      f5i = f0i - Two * t0i;
+
+      t0r = f1r + f4r;
+      t0i = f1i - f4i;
+      t1r = f1r - f4r;
+      t1i = f1i + f4i;
+
+      f1r = t0r - w0r * t1r - w0i * t1i;
+      f1i = t0i + w0i * t1r - w0r * t1i;
+      f4r = Two * t0r - f1r;
+      f4i = f1i - Two * t0i;
+
+      *(p0r) = f0r;
+      *(p0r + 1) = f0i;
+      *(p1r + pos) = f5r;
+      *(p1r + posi) = f5i;
+
+      w0r = *++u0r;
+      w0i = *--u0i;
+
+      *(p1r) = f1r;
+      *(p1r + 1) = f1i;
+      *(p0r + pos) = f4r;
+      *(p0r + posi) = f4i;
+
+      p0r += 2;
+      p1r -= 2;
+    }
+}
+
+static void riffts1(SPFLOAT *ioptr, int M, SPFLOAT *Utbl, int16_t *BRLow)
+{
+    /* Compute in-place real ifft on the rows of the input array    */
+    /* data order as from rffts1                                    */
+    /* INPUTS                                                       */
+    /*   *ioptr = input data array in the following order           */
+    /*   M = log2 of fft size                                       */
+    /*   Re(x[0]), Re(x[N/2]), Re(x[1]), Im(x[1]),                  */
+    /*   Re(x[2]), Im(x[2]), ... Re(x[N/2-1]), Im(x[N/2-1]).        */
+    /*   *Utbl = cosine table                                       */
+    /*   *BRLow = bit reversed counter table                        */
+    /* OUTPUTS                                                      */
+    /*   *ioptr = real output data array                            */
+
+    SPFLOAT scale;
+    int StageCnt;
+    int NDiffU;
+
+    scale = (SPFLOAT)(1.0 / (double)((int)POW2(M)));
+    M = M - 1;
+    switch (M) {
+    case -1:
+      break;
+    case 0:
+      rifft1pt(ioptr, scale);   /* a 2 pt fft */
+      break;
+    case 1:
+      rifft2pt(ioptr, scale);   /* a 4 pt fft */
+      break;
+    case 2:
+      rifft4pt(ioptr, scale);   /* an 8 pt fft */
+      break;
+    case 3:
+      rifft8pt(ioptr, scale);   /* a 16 pt fft */
+      break;
+    default:
+      ifrstage(ioptr, M + 1, Utbl);
+      /* bit reverse and first radix 2 stage */
+      scbitrevR2(ioptr, M, BRLow, scale);
+      StageCnt = (M - 1) / 3;   /* number of radix 8 stages           */
+      NDiffU = 2;               /* one radix 2 stage already complete */
+      if ((M - 1 - (StageCnt * 3)) == 1) {
+        ibfR2(ioptr, M, NDiffU);        /* 1 radix 2 stage */
+        NDiffU *= 2;
+      }
+      if ((M - 1 - (StageCnt * 3)) == 2) {
+        ibfR4(ioptr, M, NDiffU);        /* 1 radix 4 stage */
+        NDiffU *= 4;
+      }
+      if (M <= (int) MCACHE)
+        ibfstages(ioptr, M, Utbl, 2, NDiffU, StageCnt); /*  RADIX 8 Stages */
+      else
+        ifftrecurs(ioptr, M, Utbl, 2, NDiffU, StageCnt); /* RADIX 8 Stages */
+    }
+}
--- /dev/null
+++ b/lib/fft/sp_fft.c
@@ -1,0 +1,52 @@
+/* this file is placed in the public domain */
+
+void sp_fft_init(sp_fft *fft, int M)
+{
+    SPFLOAT *utbl;
+    int16_t *BRLow;
+    int16_t *BRLowCpx;
+
+    /* init cos table */
+    utbl = (SPFLOAT*) malloc((POW2(M) / 4 + 1) * sizeof(SPFLOAT));
+    fftCosInit(M, utbl);
+
+    BRLowCpx =
+      (int16_t*) malloc(POW2(M / 2 - 1) * sizeof(int16_t));
+    fftBRInit(M, BRLowCpx);
+
+    /* init bit reversed table for real FFT */
+     BRLow =
+      (int16_t*) malloc(POW2((M - 1) / 2 - 1) * sizeof(int16_t));
+    fftBRInit(M - 1, BRLow);
+
+    fft->BRLow = BRLow;
+    fft->BRLowCpx = BRLowCpx;
+    fft->utbl = utbl;
+}
+
+void sp_fftr(sp_fft *fft, SPFLOAT *buf, int FFTsize)
+{
+    int M = log2(FFTsize);
+    rffts1(buf, M, fft->utbl, fft->BRLow);
+}
+
+void sp_fft_cpx(sp_fft *fft, SPFLOAT *buf, int FFTsize)
+{
+    int M = log2(FFTsize);
+    ffts1(buf, M, fft->utbl, fft->BRLowCpx);
+}
+
+
+
+void sp_ifftr(sp_fft *fft, SPFLOAT *buf, int FFTsize)
+{
+    int M = log2(FFTsize);
+    riffts1(buf, M, fft->utbl, fft->BRLow);
+}
+
+void sp_fft_destroy(sp_fft *fft)
+{
+    free(fft->utbl);
+    free(fft->BRLow);
+    free(fft->BRLowCpx);
+}
--- /dev/null
+++ b/lib/inih/LICENSE.txt
@@ -1,0 +1,27 @@
+
+The "inih" library is distributed under the New BSD license:
+
+Copyright (c) 2009, Ben Hoyt
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of Ben Hoyt nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY BEN HOYT ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL BEN HOYT BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+++ b/lib/inih/Makefile
@@ -1,0 +1,5 @@
+LPATHS += lib/inih/ini.o
+CFLAGS += -Ilib/inih/
+
+inih/ini.o: lib/inih/ini.c
+	$(CC) $(CFLAGS) $< -c -o $@
--- /dev/null
+++ b/lib/inih/ini.c
@@ -1,0 +1,185 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+https://github.com/benhoyt/inih
+
+*/
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ini.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#endif
+
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s)
+{
+    char* p = s + strlen(s);
+    while (p > s && isspace((unsigned char)(*--p)))
+        *p = '\0';
+    return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s)
+{
+    while (*s && isspace((unsigned char)(*s)))
+        s++;
+    return (char*)s;
+}
+
+/* Return pointer to first char c or ';' comment in given string, or pointer to
+   null at end of string if neither found. ';' must be prefixed by a whitespace
+   character to register as a comment. */
+static char* find_char_or_comment(const char* s, char c)
+{
+    int was_whitespace = 0;
+    while (*s && *s != c && !(was_whitespace && *s == ';')) {
+        was_whitespace = isspace((unsigned char)(*s));
+        s++;
+    }
+    return (char*)s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size)
+{
+    strncpy(dest, src, size);
+    dest[size - 1] = '\0';
+    return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse_file(FILE* file,
+                   int (*handler)(void*, const char*, const char*,
+                                  const char*),
+                   void* user)
+{
+    /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+    char line[INI_MAX_LINE];
+#else
+    char* line;
+#endif
+    char section[MAX_SECTION] = "";
+    char prev_name[MAX_NAME] = "";
+
+    char* start;
+    char* end;
+    char* name;
+    char* value;
+    int lineno = 0;
+    int error = 0;
+
+#if !INI_USE_STACK
+    line = (char*)malloc(INI_MAX_LINE);
+    if (!line) {
+        return -2;
+    }
+#endif
+
+    /* Scan through file line by line */
+    while (fgets(line, INI_MAX_LINE, file) != NULL) {
+        lineno++;
+
+        start = line;
+#if INI_ALLOW_BOM
+        if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+                           (unsigned char)start[1] == 0xBB &&
+                           (unsigned char)start[2] == 0xBF) {
+            start += 3;
+        }
+#endif
+        start = lskip(rstrip(start));
+
+        if (*start == ';' || *start == '#') {
+            /* Per Python ConfigParser, allow '#' comments at start of line */
+        }
+#if INI_ALLOW_MULTILINE
+        else if (*prev_name && *start && start > line) {
+            /* Non-black line with leading whitespace, treat as continuation
+               of previous name's value (as per Python ConfigParser). */
+            if (!handler(user, section, prev_name, start) && !error)
+                error = lineno;
+        }
+#endif
+        else if (*start == '[') {
+            /* A "[section]" line */
+            end = find_char_or_comment(start + 1, ']');
+            if (*end == ']') {
+                *end = '\0';
+                strncpy0(section, start + 1, sizeof(section));
+                *prev_name = '\0';
+            }
+            else if (!error) {
+                /* No ']' found on section line */
+                error = lineno;
+            }
+        }
+        else if (*start && *start != ';') {
+            /* Not a comment, must be a name[=:]value pair */
+            end = find_char_or_comment(start, '=');
+            if (*end != '=') {
+                end = find_char_or_comment(start, ':');
+            }
+            if (*end == '=' || *end == ':') {
+                *end = '\0';
+                name = rstrip(start);
+                value = lskip(end + 1);
+                end = find_char_or_comment(value, '\0');
+                if (*end == ';')
+                    *end = '\0';
+                rstrip(value);
+
+                /* Valid name[=:]value pair found, call handler */
+                strncpy0(prev_name, name, sizeof(prev_name));
+                if (!handler(user, section, name, value) && !error)
+                    error = lineno;
+            }
+            else if (!error) {
+                /* No '=' or ':' found on name[=:]value line */
+                error = lineno;
+            }
+        }
+
+#if INI_STOP_ON_FIRST_ERROR
+        if (error)
+            break;
+#endif
+    }
+
+#if !INI_USE_STACK
+    free(line);
+#endif
+
+    return error;
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename,
+              int (*handler)(void*, const char*, const char*, const char*),
+              void* user)
+{
+    FILE* file;
+    int error;
+
+    file = fopen(filename, "r");
+    if (!file)
+        return -1;
+    error = ini_parse_file(file, handler, user);
+    fclose(file);
+    return error;
+}
--- /dev/null
+++ b/lib/inih/ini.h
@@ -1,0 +1,77 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+https://github.com/benhoyt/inih
+
+*/
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+   (whitespace stripped), and comments starting with ';' (semicolon). Section
+   is "" if name=value pair parsed before any section heading. name:value
+   pairs are also supported as a concession to Python's ConfigParser.
+
+   For each name=value pair parsed, call handler function with given user
+   pointer as well as section, name, and value (data only valid for duration
+   of handler call). Handler should return nonzero on success, zero on error.
+
+   Returns 0 on success, line number of first error on parse error (doesn't
+   stop on first error), -1 on file open error, or -2 on memory allocation
+   error (only when INI_USE_STACK is zero).
+*/
+int ini_parse(const char* filename,
+              int (*handler)(void* user, const char* section,
+                             const char* name, const char* value),
+              void* user);
+
+/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
+   close the file when it's finished -- the caller must do that. */
+int ini_parse_file(FILE* file,
+                   int (*handler)(void* user, const char* section,
+                                  const char* name, const char* value),
+                   void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+   ConfigParser. If allowed, ini_parse() will call the handler with the same
+   name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
+   the file. See http://code.google.com/p/inih/issues/detail?id=21 */
+#ifndef INI_ALLOW_BOM
+#define INI_ALLOW_BOM 1
+#endif
+
+/* Nonzero to use stack, zero to use heap (malloc/free). */
+#ifndef INI_USE_STACK
+#define INI_USE_STACK 1
+#endif
+
+/* Stop parsing on first error (default is to keep parsing). */
+#ifndef INI_STOP_ON_FIRST_ERROR
+#define INI_STOP_ON_FIRST_ERROR 0
+#endif
+
+/* Maximum line length for any line in INI file. */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 200
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
--- /dev/null
+++ b/lib/kissfft/COPYING
@@ -1,0 +1,11 @@
+Copyright (c) 2003-2010 Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+++ b/lib/kissfft/Makefile
@@ -1,0 +1,8 @@
+LPATHS += lib/kissfft/kiss_fft.o lib/kissfft/kiss_fftr.o
+CFLAGS += -Ilib/kissfft/ -Dkiss_fft_scalar=$(SPFLOAT)
+
+lib/kissfft/kiss_fft.o: lib/kissfft/kiss_fft.c
+	$(C89) $< -c $(CFLAGS) -o $@
+
+lib/kissfft/kiss_fftr.o: lib/kissfft/kiss_fftr.c
+	$(C89) $< -c $(CFLAGS) -o $@
--- /dev/null
+++ b/lib/kissfft/README
@@ -1,0 +1,134 @@
+KISS FFT - A mixed-radix Fast Fourier Transform based up on the principle, 
+"Keep It Simple, Stupid."
+
+    There are many great fft libraries already around.  Kiss FFT is not trying
+to be better than any of them.  It only attempts to be a reasonably efficient, 
+moderately useful FFT that can use fixed or floating data types and can be 
+incorporated into someone's C program in a few minutes with trivial licensing.
+
+USAGE:
+
+    The basic usage for 1-d complex FFT is:
+
+        #include "kiss_fft.h"
+
+        kiss_fft_cfg cfg = kiss_fft_alloc( nfft ,is_inverse_fft ,0,0 );
+
+        while ...
+        
+            ... // put kth sample in cx_in[k].r and cx_in[k].i
+            
+            kiss_fft( cfg , cx_in , cx_out );
+            
+            ... // transformed. DC is in cx_out[0].r and cx_out[0].i 
+            
+        free(cfg);
+
+    Note: frequency-domain data is stored from dc up to 2pi.
+    so cx_out[0] is the dc bin of the FFT
+    and cx_out[nfft/2] is the Nyquist bin (if exists)
+
+    Declarations are in "kiss_fft.h", along with a brief description of the 
+functions you'll need to use. 
+
+Code definitions for 1d complex FFTs are in kiss_fft.c.
+
+You can do other cool stuff with the extras you'll find in tools/
+
+    * multi-dimensional FFTs 
+    * real-optimized FFTs  (returns the positive half-spectrum: (nfft/2+1) complex frequency bins)
+    * fast convolution FIR filtering (not available for fixed point)
+    * spectrum image creation
+
+The core fft and most tools/ code can be compiled to use float, double 
+or Q15 short samples. The default is float.
+
+
+BACKGROUND:
+
+    I started coding this because I couldn't find a fixed point FFT that didn't 
+use assembly code.  I started with floating point numbers so I could get the 
+theory straight before working on fixed point issues.  In the end, I had a 
+little bit of code that could be recompiled easily to do ffts with short, float
+or double (other types should be easy too).  
+
+    Once I got my FFT working, I was curious about the speed compared to
+a well respected and highly optimized fft library.  I don't want to criticize 
+this great library, so let's call it FFT_BRANDX.
+During this process, I learned:
+
+    1. FFT_BRANDX has more than 100K lines of code. The core of kiss_fft is about 500 lines (cpx 1-d).
+    2. It took me an embarrassingly long time to get FFT_BRANDX working.
+    3. A simple program using FFT_BRANDX is 522KB. A similar program using kiss_fft is 18KB (without optimizing for size).
+    4. FFT_BRANDX is roughly twice as fast as KISS FFT in default mode.
+
+    It is wonderful that free, highly optimized libraries like FFT_BRANDX exist.
+But such libraries carry a huge burden of complexity necessary to extract every 
+last bit of performance.
+
+    Sometimes simpler is better, even if it's not better.
+
+FREQUENTLY ASKED QUESTIONS:
+	Q: Can I use kissfft in a project with a ___ license?
+	A: Yes.  See LICENSE below.
+
+	Q: Why don't I get the output I expect?
+	A: The two most common causes of this are 
+		1) scaling : is there a constant multiplier between what you got and what you want?
+		2) mixed build environment -- all code must be compiled with same preprocessor 
+		definitions for FIXED_POINT and kiss_fft_scalar
+
+	Q: Will you write/debug my code for me?
+	A: Probably not unless you pay me.  I am happy to answer pointed and topical questions, but 
+	I may refer you to a book, a forum, or some other resource.
+
+
+PERFORMANCE:
+    (on Athlon XP 2100+, with gcc 2.96, float data type)
+
+    Kiss performed 10000 1024-pt cpx ffts in .63 s of cpu time.
+    For comparison, it took md5sum twice as long to process the same amount of data.
+
+    Transforming 5 minutes of CD quality audio takes less than a second (nfft=1024). 
+
+DO NOT:
+    ... use Kiss if you need the Fastest Fourier Transform in the World
+    ... ask me to add features that will bloat the code
+
+UNDER THE HOOD:
+
+    Kiss FFT uses a time decimation, mixed-radix, out-of-place FFT. If you give it an input buffer  
+    and output buffer that are the same, a temporary buffer will be created to hold the data.
+
+    No static data is used.  The core routines of kiss_fft are thread-safe (but not all of the tools directory).
+
+    No scaling is done for the floating point version (for speed).  
+    Scaling is done both ways for the fixed-point version (for overflow prevention).
+
+    Optimized butterflies are used for factors 2,3,4, and 5. 
+
+    The real (i.e. not complex) optimization code only works for even length ffts.  It does two half-length
+    FFTs in parallel (packed into real&imag), and then combines them via twiddling.  The result is 
+    nfft/2+1 complex frequency bins from DC to Nyquist.  If you don't know what this means, search the web.
+
+    The fast convolution filtering uses the overlap-scrap method, slightly 
+    modified to put the scrap at the tail.
+
+LICENSE:
+    Revised BSD License, see COPYING for verbiage. 
+    Basically, "free to use&change, give credit where due, no guarantees"
+    Note this license is compatible with GPL at one end of the spectrum and closed, commercial software at 
+    the other end.  See http://www.fsf.org/licensing/licenses
+
+    A commercial license is available which removes the requirement for attribution.  Contact me for details.
+
+  
+TODO:
+    *) Add real optimization for odd length FFTs 
+    *) Document/revisit the input/output fft scaling
+    *) Make doc describing the overlap (tail) scrap fast convolution filtering in kiss_fastfir.c
+    *) Test all the ./tools/ code with fixed point (kiss_fastfir.c doesn't work, maybe others)
+
+AUTHOR:
+    Mark Borgerding
+    Mark@Borgerding.net
--- /dev/null
+++ b/lib/kissfft/_kiss_fft_guts.h
@@ -1,0 +1,168 @@
+/*
+Copyright (c) 2003-2010, Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* kiss_fft.h
+   defines kiss_fft_scalar as either short or a float type
+   and defines
+   typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
+#include "kiss_fft.h"
+#include <limits.h>
+
+#define MAXFACTORS 32
+/* e.g. an fft of length 128 has 4 factors
+ as far as kissfft is concerned
+ 4*4*4*2
+ */
+
+#ifndef SOUNDPIPE_H
+
+struct kiss_fft_state{
+    int nfft;
+    int inverse;
+    int factors[2*MAXFACTORS];
+    kiss_fft_cpx twiddles[1];
+};
+
+#endif
+
+/*
+  Explanation of macros dealing with complex math:
+
+   C_MUL(m,a,b)         : m = a*b
+   C_FIXDIV( c , div )  : if a fixed point impl., c /= div. noop otherwise
+   C_SUB( res, a,b)     : res = a - b
+   C_SUBFROM( res , a)  : res -= a
+   C_ADDTO( res , a)    : res += a
+ * */
+#ifdef FIXED_POINT
+#if (FIXED_POINT==32)
+# define FRACBITS 31
+# define SAMPPROD int64_t
+#define SAMP_MAX 2147483647
+#else
+# define FRACBITS 15
+# define SAMPPROD int32_t
+#define SAMP_MAX 32767
+#endif
+
+#define SAMP_MIN -SAMP_MAX
+
+#if defined(CHECK_OVERFLOW)
+#  define CHECK_OVERFLOW_OP(a,op,b)  \
+	if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \
+		fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) );  }
+#endif
+
+
+#   define smul(a,b) ( (SAMPPROD)(a)*(b) )
+#   define sround( x )  (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS )
+
+#   define S_MUL(a,b) sround( smul(a,b) )
+
+#   define C_MUL(m,a,b) \
+      do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \
+          (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0)
+
+#   define DIVSCALAR(x,k) \
+	(x) = sround( smul(  x, SAMP_MAX/k ) )
+
+#   define C_FIXDIV(c,div) \
+	do {    DIVSCALAR( (c).r , div);  \
+		DIVSCALAR( (c).i  , div); }while (0)
+
+#   define C_MULBYSCALAR( c, s ) \
+    do{ (c).r =  sround( smul( (c).r , s ) ) ;\
+        (c).i =  sround( smul( (c).i , s ) ) ; }while(0)
+
+#else  /* not FIXED_POINT*/
+
+#   define S_MUL(a,b) ( (a)*(b) )
+#define C_MUL(m,a,b) \
+    do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
+        (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
+#   define C_FIXDIV(c,div) /* NOOP */
+#   define C_MULBYSCALAR( c, s ) \
+    do{ (c).r *= (s);\
+        (c).i *= (s); }while(0)
+#endif
+
+#ifndef CHECK_OVERFLOW_OP
+#  define CHECK_OVERFLOW_OP(a,op,b) /* noop */
+#endif
+
+#define  C_ADD( res, a,b)\
+    do { \
+	    CHECK_OVERFLOW_OP((a).r,+,(b).r)\
+	    CHECK_OVERFLOW_OP((a).i,+,(b).i)\
+	    (res).r=(a).r+(b).r;  (res).i=(a).i+(b).i; \
+    }while(0)
+#define  C_SUB( res, a,b)\
+    do { \
+	    CHECK_OVERFLOW_OP((a).r,-,(b).r)\
+	    CHECK_OVERFLOW_OP((a).i,-,(b).i)\
+	    (res).r=(a).r-(b).r;  (res).i=(a).i-(b).i; \
+    }while(0)
+#define C_ADDTO( res , a)\
+    do { \
+	    CHECK_OVERFLOW_OP((res).r,+,(a).r)\
+	    CHECK_OVERFLOW_OP((res).i,+,(a).i)\
+	    (res).r += (a).r;  (res).i += (a).i;\
+    }while(0)
+
+#define C_SUBFROM( res , a)\
+    do {\
+	    CHECK_OVERFLOW_OP((res).r,-,(a).r)\
+	    CHECK_OVERFLOW_OP((res).i,-,(a).i)\
+	    (res).r -= (a).r;  (res).i -= (a).i; \
+    }while(0)
+
+
+#ifdef FIXED_POINT
+#  define KISS_FFT_COS(phase)  floor(.5+SAMP_MAX * cos (phase))
+#  define KISS_FFT_SIN(phase)  floor(.5+SAMP_MAX * sin (phase))
+#  define HALF_OF(x) ((x)>>1)
+#elif defined(USE_SIMD)
+#  define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
+#  define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
+#  define HALF_OF(x) ((x)*_mm_set1_ps(.5))
+#else
+#  define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
+#  define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
+#  define HALF_OF(x) ((x)*.5)
+#endif
+
+#define  kf_cexp(x,phase) \
+	do{ \
+		(x)->r = KISS_FFT_COS(phase);\
+		(x)->i = KISS_FFT_SIN(phase);\
+	}while(0)
+
+
+/* a debugging function */
+#define pcpx(c)\
+    fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) )
+
+
+#ifdef KISS_FFT_USE_ALLOCA
+// define this to allow use of alloca instead of malloc for temporary buffers
+// Temporary buffers are used in two case:
+// 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5
+// 2. "in-place" FFTs.  Notice the quotes, since kissfft does not really do an in-place transform.
+#include <alloca.h>
+#define  KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes)
+#define  KISS_FFT_TMP_FREE(ptr)
+#else
+#define  KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes)
+#define  KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr)
+#endif
--- /dev/null
+++ b/lib/kissfft/kiss_fft.c
@@ -1,0 +1,409 @@
+/*
+Copyright (c) 2003-2010, Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "_kiss_fft_guts.h"
+/* The guts header contains all the multiplication and addition macros that are defined for
+ fixed or floating point complex numbers.  It also delares the kf_ internal functions.
+ */
+
+static void kf_bfly2(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        int m
+        )
+{
+    kiss_fft_cpx * Fout2;
+    kiss_fft_cpx * tw1 = st->twiddles;
+    kiss_fft_cpx t;
+    Fout2 = Fout + m;
+    do{
+        C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2);
+
+        C_MUL (t,  *Fout2 , *tw1);
+        tw1 += fstride;
+        C_SUB( *Fout2 ,  *Fout , t );
+        C_ADDTO( *Fout ,  t );
+        ++Fout2;
+        ++Fout;
+    }while (--m);
+}
+
+static void kf_bfly4(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        const size_t m
+        )
+{
+    kiss_fft_cpx *tw1,*tw2,*tw3;
+    kiss_fft_cpx scratch[6];
+    size_t k=m;
+    const size_t m2=2*m;
+    const size_t m3=3*m;
+
+
+    tw3 = tw2 = tw1 = st->twiddles;
+
+    do {
+        C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4);
+
+        C_MUL(scratch[0],Fout[m] , *tw1 );
+        C_MUL(scratch[1],Fout[m2] , *tw2 );
+        C_MUL(scratch[2],Fout[m3] , *tw3 );
+
+        C_SUB( scratch[5] , *Fout, scratch[1] );
+        C_ADDTO(*Fout, scratch[1]);
+        C_ADD( scratch[3] , scratch[0] , scratch[2] );
+        C_SUB( scratch[4] , scratch[0] , scratch[2] );
+        C_SUB( Fout[m2], *Fout, scratch[3] );
+        tw1 += fstride;
+        tw2 += fstride*2;
+        tw3 += fstride*3;
+        C_ADDTO( *Fout , scratch[3] );
+
+        if(st->inverse) {
+            Fout[m].r = scratch[5].r - scratch[4].i;
+            Fout[m].i = scratch[5].i + scratch[4].r;
+            Fout[m3].r = scratch[5].r + scratch[4].i;
+            Fout[m3].i = scratch[5].i - scratch[4].r;
+        }else{
+            Fout[m].r = scratch[5].r + scratch[4].i;
+            Fout[m].i = scratch[5].i - scratch[4].r;
+            Fout[m3].r = scratch[5].r - scratch[4].i;
+            Fout[m3].i = scratch[5].i + scratch[4].r;
+        }
+        ++Fout;
+    }while(--k);
+}
+
+static void kf_bfly3(
+         kiss_fft_cpx * Fout,
+         const size_t fstride,
+         const kiss_fft_cfg st,
+         size_t m
+         )
+{
+     size_t k=m;
+     const size_t m2 = 2*m;
+     kiss_fft_cpx *tw1,*tw2;
+     kiss_fft_cpx scratch[5];
+     kiss_fft_cpx epi3;
+     epi3 = st->twiddles[fstride*m];
+
+     tw1=tw2=st->twiddles;
+
+     do{
+         C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
+
+         C_MUL(scratch[1],Fout[m] , *tw1);
+         C_MUL(scratch[2],Fout[m2] , *tw2);
+
+         C_ADD(scratch[3],scratch[1],scratch[2]);
+         C_SUB(scratch[0],scratch[1],scratch[2]);
+         tw1 += fstride;
+         tw2 += fstride*2;
+
+         Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
+         Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
+
+         C_MULBYSCALAR( scratch[0] , epi3.i );
+
+         C_ADDTO(*Fout,scratch[3]);
+
+         Fout[m2].r = Fout[m].r + scratch[0].i;
+         Fout[m2].i = Fout[m].i - scratch[0].r;
+
+         Fout[m].r -= scratch[0].i;
+         Fout[m].i += scratch[0].r;
+
+         ++Fout;
+     }while(--k);
+}
+
+static void kf_bfly5(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        int m
+        )
+{
+    kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+    int u;
+    kiss_fft_cpx scratch[13];
+    kiss_fft_cpx * twiddles = st->twiddles;
+    kiss_fft_cpx *tw;
+    kiss_fft_cpx ya,yb;
+    ya = twiddles[fstride*m];
+    yb = twiddles[fstride*2*m];
+
+    Fout0=Fout;
+    Fout1=Fout0+m;
+    Fout2=Fout0+2*m;
+    Fout3=Fout0+3*m;
+    Fout4=Fout0+4*m;
+
+    tw=st->twiddles;
+    for ( u=0; u<m; ++u ) {
+        C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
+        scratch[0] = *Fout0;
+
+        C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+        C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+        C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+        C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+        C_ADD( scratch[7],scratch[1],scratch[4]);
+        C_SUB( scratch[10],scratch[1],scratch[4]);
+        C_ADD( scratch[8],scratch[2],scratch[3]);
+        C_SUB( scratch[9],scratch[2],scratch[3]);
+
+        Fout0->r += scratch[7].r + scratch[8].r;
+        Fout0->i += scratch[7].i + scratch[8].i;
+
+        scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
+        scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
+
+        scratch[6].r =  S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
+        scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
+
+        C_SUB(*Fout1,scratch[5],scratch[6]);
+        C_ADD(*Fout4,scratch[5],scratch[6]);
+
+        scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
+        scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
+        scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
+        scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
+
+        C_ADD(*Fout2,scratch[11],scratch[12]);
+        C_SUB(*Fout3,scratch[11],scratch[12]);
+
+        ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+    }
+}
+
+/* perform the butterfly for one stage of a mixed radix FFT */
+static void kf_bfly_generic(
+        kiss_fft_cpx * Fout,
+        const size_t fstride,
+        const kiss_fft_cfg st,
+        int m,
+        int p
+        )
+{
+    int u,k,q1,q;
+    kiss_fft_cpx * twiddles = st->twiddles;
+    kiss_fft_cpx t;
+    int Norig = st->nfft;
+
+    kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p);
+
+    for ( u=0; u<m; ++u ) {
+        k=u;
+        for ( q1=0 ; q1<p ; ++q1 ) {
+            scratch[q1] = Fout[ k  ];
+            C_FIXDIV(scratch[q1],p);
+            k += m;
+        }
+
+        k=u;
+        for ( q1=0 ; q1<p ; ++q1 ) {
+            int twidx=0;
+            Fout[ k ] = scratch[0];
+            for (q=1;q<p;++q ) {
+                twidx += fstride * k;
+                if (twidx>=Norig) twidx-=Norig;
+                C_MUL(t,scratch[q] , twiddles[twidx] );
+                C_ADDTO( Fout[ k ] ,t);
+            }
+            k += m;
+        }
+    }
+    KISS_FFT_TMP_FREE(scratch);
+}
+
+static
+void kf_work(
+        kiss_fft_cpx * Fout,
+        const kiss_fft_cpx * f,
+        const size_t fstride,
+        int in_stride,
+        int * factors,
+        const kiss_fft_cfg st
+        )
+{
+    kiss_fft_cpx * Fout_beg=Fout;
+    const int p=*factors++; /* the radix  */
+    const int m=*factors++; /* stage's fft length/p */
+    const kiss_fft_cpx * Fout_end = Fout + p*m;
+
+#ifdef _OPENMP
+    /* use openmp extensions at the */
+    /* top-level (not recursive) */
+    if (fstride==1 && p<=5)
+    {
+        int k;
+
+        /* execute the p different work units in different threads */
+#       pragma omp parallel for
+        for (k=0;k<p;++k)
+            kf_work( Fout +k*m, f+ fstride*in_stride*k,fstride*p,in_stride,factors,st);
+        // all threads have joined by this point
+
+        switch (p) {
+            case 2: kf_bfly2(Fout,fstride,st,m); break;
+            case 3: kf_bfly3(Fout,fstride,st,m); break;
+            case 4: kf_bfly4(Fout,fstride,st,m); break;
+            case 5: kf_bfly5(Fout,fstride,st,m); break;
+            default: kf_bfly_generic(Fout,fstride,st,m,p); break;
+        }
+        return;
+    }
+#endif
+
+    if (m==1) {
+        do{
+            *Fout = *f;
+            f += fstride*in_stride;
+        }while(++Fout != Fout_end );
+    }else{
+        do{
+            /* recursive call:
+             * DFT of size m*p performed by doing
+             * p instances of smaller DFTs of size m,
+             * each one takes a decimated version of the input
+             */
+            kf_work( Fout , f, fstride*p, in_stride, factors,st);
+            f += fstride*in_stride;
+        }while( (Fout += m) != Fout_end );
+    }
+
+    Fout=Fout_beg;
+
+    /* recombine the p smaller DFTs  */
+    switch (p) {
+        case 2: kf_bfly2(Fout,fstride,st,m); break;
+        case 3: kf_bfly3(Fout,fstride,st,m); break;
+        case 4: kf_bfly4(Fout,fstride,st,m); break;
+        case 5: kf_bfly5(Fout,fstride,st,m); break;
+        default: kf_bfly_generic(Fout,fstride,st,m,p); break;
+    }
+}
+
+/*  facbuf is populated by p1,m1,p2,m2, ...
+    where
+    p[i] * m[i] = m[i-1]
+    m0 = n                  */
+static
+void kf_factor(int n,int * facbuf)
+{
+    int p=4;
+    double floor_sqrt;
+    floor_sqrt = floor( sqrt((double)n) );
+
+    /*factor out powers of 4, powers of 2, then any remaining primes */
+    do {
+        while (n % p) {
+            switch (p) {
+                case 4: p = 2; break;
+                case 2: p = 3; break;
+                default: p += 2; break;
+            }
+            if (p > floor_sqrt)
+                p = n;          /* no more factors, skip to end */
+        }
+        n /= p;
+        *facbuf++ = p;
+        *facbuf++ = n;
+    } while (n > 1);
+}
+
+/*
+ *
+ * User-callable function to allocate all necessary storage space for the fft.
+ *
+ * The return value is a contiguous block of memory, allocated with malloc.  As such,
+ * It can be freed with free(), rather than a kiss_fft-specific function.
+ * */
+kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem )
+{
+    kiss_fft_cfg st=NULL;
+    size_t memneeded = sizeof(struct kiss_fft_state)
+        + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/
+
+    if ( lenmem==NULL ) {
+        st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded );
+    }else{
+        if (mem != NULL && *lenmem >= memneeded)
+            st = (kiss_fft_cfg)mem;
+        *lenmem = memneeded;
+    }
+    if (st) {
+        int i;
+        st->nfft=nfft;
+        st->inverse = inverse_fft;
+
+        for (i=0;i<nfft;++i) {
+            const double pi=3.141592653589793238462643383279502884197169399375105820974944;
+            double phase = -2*pi*i / nfft;
+            if (st->inverse)
+                phase *= -1;
+            kf_cexp(st->twiddles+i, phase );
+        }
+
+        kf_factor(nfft,st->factors);
+    }
+    return st;
+}
+
+
+void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride)
+{
+    if (fin == fout) {
+        /* NOTE: this is not really an in-place FFT algorithm. */
+        /* It just performs an out-of-place FFT into a temp buffer */
+        kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft);
+        kf_work(tmpbuf,fin,1,in_stride, st->factors,st);
+        memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft);
+        KISS_FFT_TMP_FREE(tmpbuf);
+    }else{
+        kf_work( fout, fin, 1,in_stride, st->factors,st );
+    }
+}
+
+void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+    kiss_fft_stride(cfg,fin,fout,1);
+}
+
+
+void kiss_fft_cleanup(void)
+{
+    /* nothing needed any more */
+}
+
+int kiss_fft_next_fast_size(int n)
+{
+    while(1) {
+        int m=n;
+        while ( (m%2) == 0 ) m/=2;
+        while ( (m%3) == 0 ) m/=3;
+        while ( (m%5) == 0 ) m/=5;
+        if (m<=1)
+            break; /* n is completely factorable by twos, threes, and fives */
+        n++;
+    }
+    return n;
+}
--- /dev/null
+++ b/lib/kissfft/kiss_fft.h
@@ -1,0 +1,128 @@
+#ifndef KISS_FFT_H
+#define KISS_FFT_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ATTENTION!
+ If you would like a :
+ -- a utility that will handle the caching of fft objects
+ -- real-only (no imaginary time component ) FFT
+ -- a multi-dimensional FFT
+ -- a command-line utility to perform ffts
+ -- a command-line utility to perform fast-convolution filtering
+
+ Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c
+  in the tools/ directory.
+*/
+
+#ifdef USE_SIMD
+# include <xmmintrin.h>
+# define kiss_fft_scalar __m128
+#define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16)
+#define KISS_FFT_FREE _mm_free
+#else
+#define KISS_FFT_MALLOC malloc
+#define KISS_FFT_FREE free
+#endif
+
+
+#ifdef FIXED_POINT
+#include <sys/types.h>
+# if (FIXED_POINT == 32)
+#  define kiss_fft_scalar int32_t
+# else
+#  define kiss_fft_scalar int16_t
+# endif
+#else
+# ifndef kiss_fft_scalar
+/*  default is float */
+#   define kiss_fft_scalar float
+# endif
+#endif
+
+#ifndef SOUNDPIPE_H
+
+typedef struct {
+    kiss_fft_scalar r;
+    kiss_fft_scalar i;
+}kiss_fft_cpx;
+
+typedef struct kiss_fft_state* kiss_fft_cfg;
+
+#endif
+
+/*
+ *  kiss_fft_alloc
+ *
+ *  Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
+ *
+ *  typical usage:      kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL);
+ *
+ *  The return value from fft_alloc is a cfg buffer used internally
+ *  by the fft routine or NULL.
+ *
+ *  If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc.
+ *  The returned value should be free()d when done to avoid memory leaks.
+ *
+ *  The state can be placed in a user supplied buffer 'mem':
+ *  If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
+ *      then the function places the cfg in mem and the size used in *lenmem
+ *      and returns mem.
+ *
+ *  If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
+ *      then the function returns NULL and places the minimum cfg
+ *      buffer size in *lenmem.
+ * */
+
+kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem);
+
+/*
+ * kiss_fft(cfg,in_out_buf)
+ *
+ * Perform an FFT on a complex input buffer.
+ * for a forward FFT,
+ * fin should be  f[0] , f[1] , ... ,f[nfft-1]
+ * fout will be   F[0] , F[1] , ... ,F[nfft-1]
+ * Note that each element is complex and can be accessed like
+    f[k].r and f[k].i
+ * */
+void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+
+/*
+ A more generic version of the above function. It reads its input from every Nth sample.
+ * */
+void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride);
+
+/* If kiss_fft_alloc allocated a buffer, it is one contiguous
+   buffer and can be simply free()d when no longer needed*/
+#define kiss_fft_free free
+
+/*
+ Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up
+ your compiler output to call this before you exit.
+*/
+void kiss_fft_cleanup(void);
+
+
+/*
+ * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5)
+ */
+int kiss_fft_next_fast_size(int n);
+
+/* for real ffts, we need an even size */
+#define kiss_fftr_next_fast_size_real(n) \
+        (kiss_fft_next_fast_size( ((n)+1)>>1)<<1)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/lib/kissfft/kiss_fftr.c
@@ -1,0 +1,159 @@
+/*
+Copyright (c) 2003-2004, Mark Borgerding
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "kiss_fftr.h"
+#include "_kiss_fft_guts.h"
+
+struct kiss_fftr_state{
+    kiss_fft_cfg substate;
+    kiss_fft_cpx * tmpbuf;
+    kiss_fft_cpx * super_twiddles;
+#ifdef USE_SIMD
+    void * pad;
+#endif
+};
+
+kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem)
+{
+    int i;
+    kiss_fftr_cfg st = NULL;
+    size_t subsize, memneeded;
+
+    if (nfft & 1) {
+        fprintf(stderr,"Real FFT optimization must be even.\n");
+        return NULL;
+    }
+    nfft >>= 1;
+
+    kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize);
+    memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2);
+
+    if (lenmem == NULL) {
+        st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded);
+    } else {
+        if (*lenmem >= memneeded)
+            st = (kiss_fftr_cfg) mem;
+        *lenmem = memneeded;
+    }
+    if (!st)
+        return NULL;
+
+    st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */
+    st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize);
+    st->super_twiddles = st->tmpbuf + nfft;
+    kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
+
+    for (i = 0; i < nfft/2; ++i) {
+        double phase =
+            -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5);
+        if (inverse_fft)
+            phase *= -1;
+        kf_cexp (st->super_twiddles+i,phase);
+    }
+    return st;
+}
+
+void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata)
+{
+    /* input buffer timedata is stored row-wise */
+    int k,ncfft;
+    kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
+
+    if ( st->substate->inverse) {
+        fprintf(stderr,"kiss fft usage error: improper alloc\n");
+        exit(1);
+    }
+
+    ncfft = st->substate->nfft;
+
+    /*perform the parallel fft of two real signals packed in real,imag*/
+    kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf );
+    /* The real part of the DC element of the frequency spectrum in st->tmpbuf
+     * contains the sum of the even-numbered elements of the input time sequence
+     * The imag part is the sum of the odd-numbered elements
+     *
+     * The sum of tdc.r and tdc.i is the sum of the input time sequence.
+     *      yielding DC of input time sequence
+     * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
+     *      yielding Nyquist bin of input time sequence
+     */
+
+    tdc.r = st->tmpbuf[0].r;
+    tdc.i = st->tmpbuf[0].i;
+    C_FIXDIV(tdc,2);
+    CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i);
+    CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i);
+    freqdata[0].r = tdc.r + tdc.i;
+    freqdata[ncfft].r = tdc.r - tdc.i;
+#ifdef USE_SIMD
+    freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0);
+#else
+    freqdata[ncfft].i = freqdata[0].i = 0;
+#endif
+
+    for ( k=1;k <= ncfft/2 ; ++k ) {
+        fpk    = st->tmpbuf[k];
+        fpnk.r =   st->tmpbuf[ncfft-k].r;
+        fpnk.i = - st->tmpbuf[ncfft-k].i;
+        C_FIXDIV(fpk,2);
+        C_FIXDIV(fpnk,2);
+
+        C_ADD( f1k, fpk , fpnk );
+        C_SUB( f2k, fpk , fpnk );
+        C_MUL( tw , f2k , st->super_twiddles[k-1]);
+
+        freqdata[k].r = HALF_OF(f1k.r + tw.r);
+        freqdata[k].i = HALF_OF(f1k.i + tw.i);
+        freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r);
+        freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i);
+    }
+}
+
+void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata)
+{
+    /* input buffer timedata is stored row-wise */
+    int k, ncfft;
+
+    if (st->substate->inverse == 0) {
+        fprintf (stderr, "kiss fft usage error: improper alloc\n");
+        exit (1);
+    }
+
+    ncfft = st->substate->nfft;
+
+    st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r;
+    st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r;
+    C_FIXDIV(st->tmpbuf[0],2);
+
+    for (k = 1; k <= ncfft / 2; ++k) {
+        kiss_fft_cpx fk, fnkc, fek, fok, tmp;
+        fk = freqdata[k];
+        fnkc.r = freqdata[ncfft - k].r;
+        fnkc.i = -freqdata[ncfft - k].i;
+        C_FIXDIV( fk , 2 );
+        C_FIXDIV( fnkc , 2 );
+
+        C_ADD (fek, fk, fnkc);
+        C_SUB (tmp, fk, fnkc);
+        C_MUL (fok, tmp, st->super_twiddles[k-1]);
+        C_ADD (st->tmpbuf[k],     fek, fok);
+        C_SUB (st->tmpbuf[ncfft - k], fek, fok);
+#ifdef USE_SIMD
+        st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0);
+#else
+        st->tmpbuf[ncfft - k].i *= -1;
+#endif
+    }
+    kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata);
+}
--- /dev/null
+++ b/lib/kissfft/kiss_fftr.h
@@ -1,0 +1,49 @@
+#ifndef KISS_FTR_H
+#define KISS_FTR_H
+
+#include "kiss_fft.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+
+ Real optimized version can save about 45% cpu time vs. complex fft of a real seq.
+
+
+
+ */
+
+#ifndef SOUNDPIPE_H
+
+typedef struct kiss_fftr_state *kiss_fftr_cfg;
+
+#endif
+
+kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem);
+/*
+ nfft must be even
+
+ If you don't care to allocate space, use mem = lenmem = NULL
+*/
+
+
+void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata);
+/*
+ input timedata has nfft scalar points
+ output freqdata has nfft/2+1 complex points
+*/
+
+void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata);
+/*
+ input freqdata has  nfft/2+1 complex points
+ output timedata has nfft scalar points
+*/
+
+#define kiss_fftr_free free
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+++ b/lib/openlpc/COPYRIGHT.txt
@@ -1,0 +1,30 @@
+                                                               Copyright NOTICE
+                                    NOTICE
+                                       
+COPYRIGHT 1998 BY: Enzo Michelangeli and Future Dynamics
+
+   This software is being provided by the copyright holders under the
+   following license. By obtaining, using and/or copying this software, you
+   agree that you have read, understood, and will comply with the following
+   terms and conditions:
+   
+   Permission to use, copy, modify, and distribute this software and its
+   documentation for any purpose and without fee or royalty is hereby granted,
+   provided that the full text of this NOTICE appears on ALL copies of the
+   software and documentation or portions thereof, including modifications,
+   that you make. Any application making use of this code shall prominently
+   display the notice: "Portions of this software are based in part on code
+   developed by Future Dynamics".
+   
+   THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
+   REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT
+   NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES OF
+   MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE
+   SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT HOLDERS WILL BEAR NO
+   LIABILITY FOR ANY USE OF THIS SOFTWARE OR DOCUMENTATION.
+   
+   The name and trademarks of copyright holders may NOT be used in advertising
+   or publicity pertaining to the software without specific, written prior
+   permission. Title to copyright in this software and any associated
+   documentation will at all times remain with copyright holders.
--- /dev/null
+++ b/lib/openlpc/Makefile
@@ -1,0 +1,5 @@
+LPATHS += lib/openlpc/openlpc.o
+CFLAGS += -Ilib/openlpc/
+
+lib/openlpc/openlpc.o: lib/openlpc/openlpc.c
+	$(C99) $< -c $(CFLAGS) -o $@
--- /dev/null
+++ b/lib/openlpc/ftol.h
@@ -1,0 +1,31 @@
+#ifdef _MSC_VER
+
+__inline int lrintf(float flt)
+{
+    int intgr;
+
+    _asm
+    {
+        fld flt
+        fistp intgr
+    };
+
+    return intgr ;
+}
+#else
+#ifdef __GNUC__
+/* must define _GNU_SOURCE here or in the makefile */
+#include <math.h>
+#else
+
+#define FP_BITS(fp) (*(int *)&(fp))
+#define FIST_FLOAT_MAGIC_S (float)(7.0f * 2097152.0f)
+
+static int lrintf(float inval)
+{
+    float tmp = FIST_FLOAT_MAGIC_S + inval;
+    int res = ((FP_BITS(tmp)<<10)-0x80000000);
+    return res>>10;
+}
+#endif
+#endif
--- /dev/null
+++ b/lib/openlpc/openlpc.c
@@ -1,0 +1,766 @@
+/************************************************************************\
+
+  Low bitrate LPC CODEC derived from the public domain implementation
+  of Ron Frederick.
+
+  The basic design is preserved, except for several bug fixes and
+  the following modifications:
+
+  1. The pitch detector operates on the (downsampled) signal, not on
+  the residue. This appears to yield better performances, and it
+  lowers the processing load.
+  2. Each frame is elongated by 50% prefixing it with the last half
+  of the previous frame. This design, inherited from the original
+  code for windowing purposes, is exploited in order to provide
+  two independent pitch analyses: on the first 2/3, and on the
+  second 2/3 of the elongated frame (of course, they overlap by
+  half):
+
+  last half old frame	            new frame
+  --------------------========================================
+  <--------- first pitch region --------->
+                      <--------- second pitch region  ------->
+
+  Two voiced/unvoiced flags define the voicing status of each
+  region; only one value for the period is retained (if both
+  halves are voiced, the average is used).
+  The two flags are used by the synthesizer for the halves of
+  each frame to play back. Of course, this is non optimal but
+  is good enough (a half-frame would be too short for measuring
+  low pitches)
+  3. The parameters (one float for the period (pitch), one for the
+  gain, and ten for the LPC-10 filter) are quantized according
+  this procedure:
+  - the period is logarithmically compressed, then quantized
+  as 8-bit unsigned int (6 would actually suffice)
+  - the gain is logarithmically compressed (using a different
+  formula), then quantized at 6-bit unsigned int. The two
+  remaining bits are used for the voicing flags.
+  - the first two LPC parameters (k[1] and k[2]) are multiplied
+  by PI/2, and the arcsine of the result is quantized as
+  6 and 5 bit signed integers. This has proved more effective
+  than the log-area compression used by LPC-10.
+  - the remaining eight LPC parameters (k[3]...k[10]) are
+  quantized as, respectively, 5,4,4,3,3,3,3 and 2 bit signed
+  integers.
+  Finally, period and gain plus voicing flags are stored in the
+  first two bytes of the 7-byte parameters block, and the quantized
+  LPC parameters are packed into the remaining 5 bytes. Two bits
+  remain unassigned, and can be used for error detection or other
+  purposes.
+
+  The frame lenght is actually variable, and is simply passed as
+  initialization parameter to lpc_init(): this allows to experiment
+  with various frame lengths. Long frames reduce the bitrate, but
+  exceeding 320 samples (i.e. 40 ms, at 8000 samples/s) tend to
+  deteriorate the speech, that sounds like spoken by a person
+  affected by a stroke: the LPC parameters (modeling the vocal
+  tract) can't change fast enough for a natural-sounding synthesis.
+  25 ms per frame already yields a quite tight compression, corresponding
+  to 1000/40 * 7 * 8 = 1400 bps. The quality improves little with
+  frames shorter than 250 samples (32 frames/s), so this is a recommended
+  compromise. The bitrate is 32 * 7 * 8 = 1792 bps.
+
+  The synthesizer has been modified as well. For voiced subframes it
+  now uses a sawtooth excitation, instead of the original pulse train.
+  This idea, copied from MELP, reduces the buzzing-noise artifacts.
+  In order to compensate the non-white spectrum of the sawtooth, a
+  pre-emphasis is applied to the signal before the Durbin calculation.
+  The filter has (in s-space) two zeroes at (640, 0) Hz and two poles
+  at (3200, 0) Hz. These filters have been handoded, and may not be
+  optimal. Two other filters (anti-hum high-pass with corner at 100 Hz,
+  and pre-downsampling lowpass with corner at 300 Hz) are Butterworth
+  designs produced by the MkFilter package by A.J. Fisher
+  (http://www.cs.york.ac.uk/~fisher/mkfilter/).
+
+  The C style has been ANSI-fied.
+
+  Complexity: As any LPC CODEC, also this one is not very demanding:
+  for real-time use analysis and synthesis takes each about 6 - 8%
+  of the CPU cycles on a Cy686/166, when the code is compiled with
+  MSVC++ 4.2 with /Ox or gcc with -O3.
+  However, a floating point unit is absolutely required.
+
+
+\************************************************************************/
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "soundpipe.h"
+#include "openlpc.h"
+#include "ftol.h"
+
+#define PREEMPH
+
+#define bcopy(a, b, n)	  memmove(b, a, n)
+
+#ifndef M_PI
+#define M_PI (3.1415926535897932384626433832795)
+#endif
+
+static float my_fs = 11025.0;
+#define LPC_FILTORDER		10
+#define FS		my_fs /* Sampling rate */
+#define MAXWINDOW	1000	/* Max analysis window length */
+
+typedef struct openlpc_e_state{
+	float   s[MAXWINDOW], y[MAXWINDOW], h[MAXWINDOW];
+    int     framelen, buflen;
+    float   xv1[3], yv1[3],
+            xv2[2], yv2[2],
+			xv3[1], yv3[3],
+			xv4[2], yv4[2];
+    float   w[MAXWINDOW], r[LPC_FILTORDER+1];
+} openlpc_e_state_t;
+
+typedef struct openlpc_d_state{
+		float Oldper, OldG, Oldk[LPC_FILTORDER + 1];
+        float bp[LPC_FILTORDER+1];
+        float exc;
+		int pitchctr, framelen, buflen;
+} openlpc_d_state_t;
+
+#define FC		200.0	/* Pitch analyzer filter cutoff */
+#define DOWN		5	/* Decimation for pitch analyzer */
+#define MINPIT		40.0	/* Minimum pitch (observed: 74) */
+#define MAXPIT		320.0	/* Maximum pitch (observed: 250) */
+
+#define MINPER		(int)(FS/(DOWN*MAXPIT)+.5)	/* Minimum period  */
+#define MAXPER		(int)(FS/(DOWN*MINPIT)+.5)	/* Maximum period  */
+
+#define REAL_MINPER	 (DOWN*MINPER) /* converted to samples units */
+
+#define WSCALE		1.5863	/* Energy loss due to windowing */
+
+#define BITS_FOR_LPC 38
+
+#define ARCSIN_Q /* provides better quantization of first two k[] at low bitrates */
+
+#if BITS_FOR_LPC == 38
+/* (38 bit LPC-10, 2.7 Kbit/s @ 20ms, 2.4 Kbit/s @ 22.5 ms */
+static int parambits[LPC_FILTORDER] = {6,5,5,4,4,3,3,3,3,2};
+#elif BITS_FOR_LPC == 32
+/* (32 bit LPC-10, 2.4 Kbit/s, not so good */
+static int parambits[LPC_FILTORDER] = {5,5,5,4,3,3,2,2,2,1};
+#else /* BITS_FOR_LPC == 80	*/
+/* 80-bit LPC10, 4.8 Kbit/s */
+static int parambits[LPC_FILTORDER] = {8,8,8,8,8,8,8,8,8,8};
+#endif
+
+static float logmaxminper;
+static int sizeofparm;	/* computed by lpc_init */
+
+static void auto_correl1(float *w, int n, float *r)
+{
+    int i, k;
+
+    for (k=0; k <= MAXPER; k++, n--) {
+        r[k] = 0.0;
+        for (i=0; i < n; i++) {
+            r[k] += (w[i] *  w[i+k]);
+        }
+    }
+}
+
+static void auto_correl2(float *w, int n, float *r)
+{
+    int i, k;
+
+    for (k=0; k <= LPC_FILTORDER; k++, n--) {
+        r[k] = 0.0;
+        for (i=0; i < n; i++) {
+            r[k] += (w[i] *  w[i+k]);
+        }
+    }
+}
+
+static void durbin(float r[], int p, float k[], float *g)
+{
+    int i, j;
+    float a[LPC_FILTORDER+1], at[LPC_FILTORDER+1], e;
+
+    for (i=0; i <= p; i++) a[i] = at[i] = 0.0;
+
+    e = r[0];
+    for (i=1; i <= p; i++) {
+        k[i] = -r[i];
+        for (j=1; j < i; j++) {
+            at[j] = a[j];
+            k[i] -= a[j] * r[i-j];
+        }
+        if (e == 0) {  /* fix by John Walker */
+            *g = 0;
+            return;
+        }
+        k[i] /= e;
+        a[i] = k[i];
+        for (j=1; j < i; j++) a[j] = at[j] + k[i] * at[i-j];
+        e *= 1.0f - k[i]*k[i];
+    }
+    if (e < 0) {
+        e = 0; /* fix by John Walker */
+    }
+    *g = (float)sqrt(e);
+}
+
+/* Enzo's streamlined pitch extractor - on the signal, not the residue */
+
+static void calc_pitch(float *w, int len, float *per)
+{
+    int i, j, rpos;
+    float d[MAXWINDOW/DOWN], r[MAXPER+1], rmax;
+    float rval, rm, rp;
+    float x, y;
+    float vthresh;
+
+    /* decimation */
+    for (i=0, j=0; i < len; i+=DOWN)
+        d[j++] = w[i];
+
+    auto_correl1(d, len/DOWN, r);
+
+    /* find peak between MINPER and MAXPER */
+    x = 1;
+    rpos = 0;
+    rmax = 0.0;
+    y = 0;
+    rm = 0;
+    rp = 0;
+
+    vthresh = 0.;
+
+    for (i = 1; i < MAXPER; i++) {
+        rm = r[i-1];
+        rp = r[i+1];
+        y = rm+r[i]+rp; /* find max of integral from i-1 to i+1 */
+
+        if ((y > rmax) && (r[i] > rm) && (r[i] > rp) && (i > MINPER)) {
+            rmax = y;
+            rpos = i;
+        }
+    }
+
+    /* consider adjacent values */
+    rm = r[rpos-1];
+    rp = r[rpos+1];
+
+#if 0
+    {
+        float a, b, c, x, y;
+        /* parabolic interpolation */
+        a = 0.5f * rm - rmax + 0.5f * rp;
+        b = -0.5f*rm*(2.0f*rpos+1.0f) + 2.0f*rpos*rmax + 0.5f*rp*(1.0f-2.0f*rpos);
+        c = 0.5f*rm*(rpos*rpos+rpos) + rmax*(1.0f-rpos*rpos) + 0.5f*rp*(rpos*rpos-rpos);
+
+        /* find max of interpolating parabole */
+        x = -b / (2.0f * a);
+        y = a*x*x + b*x + c;
+
+        rmax = y;
+        /* normalize, so that 0. < rval < 1. */
+        rval = (r[0] == 0 ? 1.0f : rmax / r[0]);
+    }
+#else
+    if(rpos > 0) {
+        x = ((rpos-1)*rm + rpos*r[rpos] + (rpos+1)*rp)/(rm+r[rpos]+rp);
+    }
+    /* normalize, so that 0. < rval < 1. */
+    rval = (r[0] == 0 ? 0 : r[rpos] / r[0]);
+#endif
+
+    /* periods near the low boundary and at low volumes
+    are usually spurious and
+    manifest themselves as annoying mosquito buzzes */
+
+    *per = 0;	/* default: unvoiced */
+    if ( x > MINPER &&  /* x could be < MINPER or even < 0 if pos == MINPER */
+        x < (MAXPER+1) /* same story */
+        ) {
+
+        vthresh = 0.6f;
+        if(r[0] > 0.002)	   /* at low volumes (< 0.002), prefer unvoiced */
+            vthresh = 0.25;       /* drop threshold at high volumes */
+
+        if(rval > vthresh)
+            *per = x * DOWN;
+    }
+}
+
+/* Initialization of various parameters */
+
+openlpc_encoder_state *create_openlpc_encoder_state(void)
+{
+    openlpc_encoder_state *state;
+
+    state = (openlpc_encoder_state *)calloc(1, sizeof(openlpc_encoder_state));
+
+    return state;
+}
+
+
+void init_openlpc_encoder_state(openlpc_encoder_state *st, int framelen)
+{
+    int i, j;
+
+    st->framelen = framelen;
+
+    st->buflen = framelen*3/2;
+    /*  (st->buflen > MAXWINDOW) return -1;*/
+
+    for(i=0, j=0; i<sizeof(parambits)/sizeof(parambits[0]); i++) {
+        j += parambits[i];
+    }
+    sizeofparm = (j+7)/8 + 2;
+    for (i = 0; i < st->buflen; i++) {
+        st->s[i] = 0.0;
+        st->h[i] = (float)(WSCALE*(0.54 - 0.46 * cos(2 * M_PI * i / (st->buflen-1.0))));
+    }
+    /* init the filters */
+    st->xv1[0] = st->xv1[1] = st->xv1[2] = st->yv1[0] = st->yv1[1] = st->yv1[2] = 0.0f;
+    st->xv2[0] = st->xv2[1] = st->yv2[0] = st->yv2[1] = 0.0f;
+    st->xv3[0] = st->yv3[0] = st->yv3[1] = st->yv3[2] = 0.0f;
+    st->xv4[0] = st->xv4[1] = st->yv4[0] = st->yv4[1] = 0.0f;
+
+    logmaxminper = (float)log((float)MAXPER/MINPER);
+
+}
+
+void destroy_openlpc_encoder_state(openlpc_encoder_state *st)
+{
+    if(st != NULL)
+    {
+        free(st);
+        st = NULL;
+    }
+}
+
+/* LPC Analysis (compression) */
+
+int openlpc_encode(const short *buf, unsigned char *parm, openlpc_encoder_state *st)
+{
+    int i, j;
+    float per, gain, k[LPC_FILTORDER+1];
+    float per1, per2;
+    float xv10, xv11, xv12, yv10, yv11, yv12,
+        xv20, xv21, yv20, yv21,
+        xv30, yv30, yv31, yv32,
+        xv40, xv41, yv40, yv41;
+
+    xv10 = st->xv1[0];
+    xv11 = st->xv1[1];
+    xv12 = st->xv1[2];
+    yv10 = st->yv1[0];
+    yv11 = st->yv1[1];
+    yv12 = st->yv1[2];
+    xv30 = st->xv3[0];
+    yv30 = st->yv3[0];
+    yv31 = st->yv3[1];
+    yv32 = st->yv3[2];
+    for(i = 0; i < LPC_FILTORDER + 1; i++) k[i] = 0;
+    /* convert short data in buf[] to signed lin. data in s[] and prefilter */
+    for (i=0, j=st->buflen - st->framelen; i < st->framelen; i++, j++) {
+
+        float u = (float)(buf[i]/32768.0f);
+
+        /* Anti-hum 2nd order Butterworth high-pass, 100 Hz corner frequency */
+        /* Digital filter designed by mkfilter/mkshape/gencode   A.J. Fisher
+        mkfilter -Bu -Hp -o 2 -a 0.0125 -l -z */
+
+        xv10 = xv11;
+        xv11 = xv12;
+        xv12 = (float)(u * 0.94597831f); /* /GAIN */
+
+        yv10 = yv11;
+        yv11 = yv12;
+        yv12 = (float)((xv10 + xv12) - 2 * xv11
+            + ( -0.8948742499f * yv10) + ( 1.8890389823f * yv11));
+
+        u = st->s[j] = yv12;	/* also affects input of next stage, to the LPC filter synth */
+
+        /* low-pass filter s[] -> y[] before computing pitch */
+        /* second-order Butterworth low-pass filter, corner at 300 Hz */
+        /* Digital filter designed by mkfilter/mkshape/gencode   A.J. Fisher
+        MKFILTER.EXE -Bu -Lp -o 2 -a 0.0375 -l -z */
+
+        /*st->xv3[0] = (float)(u / 2.127814584e+001);*/ /* GAIN */
+        xv30 = (float)(u * 0.04699658f); /* GAIN */
+        yv30 = yv31;
+        yv31 = yv32;
+        yv32 = xv30 + (float)(( -0.7166152306f * yv30) + (1.6696186545f * yv31));
+        st->y[j] = yv32;
+    }
+    st->xv1[0] = xv10;
+    st->xv1[1] = xv11;
+    st->xv1[2] = xv12;
+    st->yv1[0] = yv10;
+    st->yv1[1] = yv11;
+    st->yv1[2] = yv12;
+    st->xv3[0] = xv30;
+    st->yv3[0] = yv30;
+    st->yv3[1] = yv31;
+    st->yv3[2] = yv32;
+#ifdef PREEMPH
+    /* operate optional preemphasis s[] -> s[] on the newly arrived frame */
+    xv20 = st->xv2[0];
+    xv21 = st->xv2[1];
+    yv20 = st->yv2[0];
+    yv21 = st->yv2[1];
+    xv40 = st->xv4[0];
+    xv41 = st->xv4[1];
+    yv40 = st->yv4[0];
+    yv41 = st->yv4[1];
+    for (j=st->buflen - st->framelen; j < st->buflen; j++) {
+        float u = st->s[j];
+
+        /* handcoded filter: 1 zero at 640 Hz, 1 pole at 3200 */
+#define TAU (FS/3200.f)
+#define RHO (0.1f)
+        xv20 = xv21; 	/* e(n-1) */
+        xv21 = (float)(u * 1.584f);		/* e(n)	, add 4 dB to compensate attenuation */
+        yv20 = yv21;
+        yv21 = (float)(TAU/(1.f+RHO+TAU) * yv20 	 /* u(n) */
+            + (RHO+TAU)/(1.f+RHO+TAU) * xv21
+            - TAU/(1.f+RHO+TAU) * xv20);
+        u = yv21;
+
+        /* cascaded copy of handcoded filter: 1 zero at 640 Hz, 1 pole at 3200 */
+        xv40 = xv41;
+        xv41 = (float)(u * 1.584f);
+        yv40 = yv41;
+        yv41 = (float)(TAU/(1.f+RHO+TAU) * yv40
+            + (RHO+TAU)/(1.f+RHO+TAU) * xv41
+            - TAU/(1.f+RHO+TAU) * xv40);
+        u = yv41;
+
+        st->s[j] = u;
+    }
+    st->xv2[0] = xv20;
+    st->xv2[1] = xv21;
+    st->yv2[0] = yv20;
+    st->yv2[1] = yv21;
+    st->xv4[0] = xv40;
+    st->xv4[1] = xv41;
+    st->yv4[0] = yv40;
+    st->yv4[1] = yv41;
+#endif
+
+    /* operate windowing s[] -> w[] */
+
+    for (i=0; i < st->buflen; i++)
+        st->w[i] = st->s[i] * st->h[i];
+
+    /* compute LPC coeff. from autocorrelation (first 11 values) of windowed data */
+    auto_correl2(st->w, st->buflen, st->r);
+    durbin(st->r, LPC_FILTORDER, k, &gain);
+
+    /* calculate pitch */
+    calc_pitch(st->y, st->framelen, &per1);                 /* first 2/3 of buffer */
+    calc_pitch(st->y + st->buflen - st->framelen, st->framelen, &per2); /* last 2/3 of buffer */
+    if(per1 > 0 && per2 >0)
+        per = (per1+per2)/2;
+    else if(per1 > 0)
+        per = per1;
+    else if(per2 > 0)
+        per = per2;
+    else
+        per = 0;
+
+    /* logarithmic q.: 0 = MINPER, 256 = MAXPER */
+    parm[0] = (unsigned char)(per == 0? 0 : (unsigned char)(log(per/(REAL_MINPER)) / logmaxminper * (1<<8)));
+
+#ifdef LINEAR_G_Q
+    i = gain * (1<<7);
+    if(i > 255) 	/* bug fix by EM */
+        i = 255;
+#else
+    i = (int)(float)(256.0f * log(1 + (2.718-1.f)/10.f*gain)); /* deriv = 5.82 allowing to reserve 2 bits */
+    if(i > 255) i = 255;	 /* reached when gain = 10 */
+    i = (i+2) & 0xfc;
+#endif
+
+    parm[1] = (unsigned char)i;
+
+    if(per1 > 0)
+        parm[1] |= 1;
+    if(per2 > 0)
+        parm[1] |= 2;
+
+    for(j=2; j < sizeofparm; j++)
+        parm[j] = 0;
+
+    for (i=0; i < LPC_FILTORDER; i++) {
+        int bitamount = parambits[i];
+        int bitc8 = 8-bitamount;
+        int q = (1 << bitc8);  /* quantum: 1, 2, 4... */
+        float u = k[i+1];
+        int iu;
+#ifdef ARCSIN_Q
+        if(i < 2) u = (float)(asin(u)*2.f/M_PI);
+#endif
+        u *= 127;
+        if(u < 0)
+            u += (0.6f * q);
+        else
+            u += (0.4f * q); /* highly empirical! */
+
+        iu = lrintf(u);
+        iu = iu & 0xff; /* keep only 8 bits */
+
+        /* make room at the left of parm array shifting left */
+        for(j=sizeofparm-1; j >= 3; j--) {
+            parm[j] = (unsigned char)((parm[j] << bitamount) | (parm[j-1] >> bitc8));
+        }
+        parm[2] = (unsigned char)((parm[2] << bitamount) | (iu >> bitc8)); /* parm[2] */
+    }
+
+    bcopy(st->s + st->framelen, st->s, (st->buflen - st->framelen)*sizeof(st->s[0]));
+    bcopy(st->y + st->framelen, st->y, (st->buflen - st->framelen)*sizeof(st->y[0]));
+
+    return sizeofparm;
+}
+
+openlpc_decoder_state *create_openlpc_decoder_state(void)
+{
+    openlpc_decoder_state *state;
+
+    state = (openlpc_decoder_state *)calloc(1, sizeof(openlpc_decoder_state));
+
+    return state;
+}
+
+void init_openlpc_decoder_state(openlpc_decoder_state *st, int framelen)
+{
+    int i, j;
+
+    st->Oldper = 0.0f;
+    st->OldG = 0.0f;
+    for (i = 0; i <= LPC_FILTORDER; i++) {
+        st->Oldk[i] = 0.0f;
+        st->bp[i] = 0.0f;
+    }
+    st->pitchctr = 0;
+    st->exc = 0.0f;
+    logmaxminper = (float)log((float)MAXPER/MINPER);
+
+    for(i=0, j=0; i<sizeof(parambits)/sizeof(parambits[0]); i++) {
+        j += parambits[i];
+    }
+    sizeofparm = (j+7)/8 + 2;
+
+    /* test for a valid frame len? */
+    st->framelen = framelen;
+    st->buflen = framelen*3/2;
+}
+
+/* LPC Synthesis (decoding) */
+
+int openlpc_decode(sp_data *sp, unsigned char *parm, short *buf, openlpc_decoder_state *st)
+{
+    int i, j, flen=st->framelen;
+    float per, gain, k[LPC_FILTORDER+1];
+    float f, u, newgain, Ginc, Newper, perinc;
+    float Newk[LPC_FILTORDER+1], kinc[LPC_FILTORDER+1];
+    float gainadj;
+    int hframe;
+    float hper[2];
+    int ii;
+    float bp0, bp1, bp2, bp3, bp4, bp5, bp6, bp7, bp8, bp9, bp10;
+            float kj;
+
+    bp0 = st->bp[0];
+    bp1 = st->bp[1];
+    bp2 = st->bp[2];
+    bp3 = st->bp[3];
+    bp4 = st->bp[4];
+    bp5 = st->bp[5];
+    bp6 = st->bp[6];
+    bp7 = st->bp[7];
+    bp8 = st->bp[8];
+    bp9 = st->bp[9];
+    bp10 = st->bp[10];
+
+    per = (float)(parm[0]);
+
+    per = (float)(per == 0? 0: REAL_MINPER * exp(per/(1<<8) * logmaxminper));
+
+    hper[0] = hper[1] = per;
+
+    if((parm[1] & 0x1) == 0) hper[0] = 0;
+    if((parm[1] & 0x2) == 0) hper[1] = 0;
+
+#ifdef LINEAR_G_Q
+    gain = (float)parm[1] / (1<<7);
+#else
+    gain = (float)parm[1] / 256.f;
+    gain = (float)((exp(gain) - 1)/((2.718-1.f)/10));
+#endif
+
+    k[0] = 0.0;
+
+    for (i=LPC_FILTORDER-1; i >= 0; i--) {
+        int bitamount = parambits[i];
+        int bitc8 = 8-bitamount;
+        /* casting to char should set the sign properly */
+        char c = (char)(parm[2] << bitc8);
+
+        for(j=2; j<sizeofparm; j++)
+            parm[j] = (unsigned char)((parm[j] >> bitamount) | (parm[j+1] << bitc8));
+
+        k[i+1] = ((float)c / (1<<7));
+#ifdef ARCSIN_Q
+        if(i<2) k[i+1] = (float)sin(M_PI/2*k[i+1]);
+#endif
+    }
+
+    /* k[] are the same in the two subframes */
+    for (i=1; i <= LPC_FILTORDER; i++) {
+        Newk[i] = st->Oldk[i];
+        kinc[i] = (k[i] - st->Oldk[i]) / flen;
+    }
+
+    /* Loop on two half frames */
+
+    for(hframe=0, ii=0; hframe<2; hframe++) {
+
+        Newper = st->Oldper;
+        newgain = st->OldG;
+
+        Ginc = (gain - st->OldG) / (flen/2);
+        per = hper[hframe];
+
+        if (per == 0.0) {			 /* if unvoiced */
+            gainadj = /* 1.5874 * */ (float)sqrt(3.0f/st->buflen);
+        } else {
+            gainadj = (float)sqrt(per/st->buflen);
+        }
+
+        /* Interpolate period ONLY if both old and new subframes are voiced, gain and K always */
+
+        if (st->Oldper != 0 && per != 0) {
+            perinc = (per - st->Oldper) / (flen/2);
+        } else {
+            perinc = 0.0f;
+            Newper = per;
+        }
+
+        if (Newper == 0.f) st->pitchctr = 0;
+
+        for (i=0; i < flen/2; i++, ii++) {
+            if (Newper == 0.f) {
+                u = (float)(((sp_rand(sp)*(1/(1.0f+RAND_MAX))) - 0.5f ) * newgain * gainadj);
+            } else {			/* voiced: send a delta every per samples */
+                /* triangular excitation */
+                if (st->pitchctr == 0) {
+                    st->exc = newgain * 0.25f * gainadj;
+                    st->pitchctr = (int) Newper;
+                } else {
+                    st->exc -= newgain/Newper * 0.5f * gainadj;
+                    st->pitchctr--;
+                }
+                u = st->exc;
+            }
+            f = u;
+	        /* excitation */
+            kj = Newk[10];
+            f -= kj * bp9;
+            bp10 = bp9 + kj * f;
+
+            kj = Newk[9];
+            f -= kj * bp8;
+            bp9 = bp8 + kj * f;
+
+            kj = Newk[8];
+            f -= kj * bp7;
+            bp8 = bp7 + kj * f;
+
+            kj = Newk[7];
+            f -= kj * bp6;
+            bp7 = bp6 + kj * f;
+
+            kj = Newk[6];
+            f -= kj * bp5;
+            bp6 = bp5 + kj * f;
+
+            kj = Newk[5];
+            f -= kj * bp4;
+            bp5 = bp4 + kj * f;
+
+            kj = Newk[4];
+            f -= kj * bp3;
+            bp4 = bp3 + kj * f;
+
+            kj = Newk[3];
+            f -= kj * bp2;
+            bp3 = bp2 + kj * f;
+
+            kj = Newk[2];
+            f -= kj * bp1;
+            bp2 = bp1 + kj * f;
+
+            kj = Newk[1];
+            f -= kj * bp0;
+            bp1 = bp0 + kj * f;
+
+            bp0 = f;
+            u = f;
+
+            if (u  < -0.9999f) {
+                u = -0.9999f;
+            } else if (u > 0.9999f) {
+                u = 0.9999f;
+            }
+
+            buf[ii] = (short)lrintf(u * 32767.0f);
+
+            Newper += perinc;
+            newgain += Ginc;
+            for (j=1; j <= LPC_FILTORDER; j++) Newk[j] += kinc[j];
+
+        }
+
+        st->Oldper = per;
+        st->OldG = gain;
+    }
+    st->bp[0] = bp0;
+    st->bp[1] = bp1;
+    st->bp[2] = bp2;
+    st->bp[3] = bp3;
+    st->bp[4] = bp4;
+    st->bp[5] = bp5;
+    st->bp[6] = bp6;
+    st->bp[7] = bp7;
+    st->bp[8] = bp8;
+    st->bp[9] = bp9;
+    st->bp[10] = bp10;
+
+    for (j=1; j <= LPC_FILTORDER; j++) st->Oldk[j] = k[j];
+
+    return flen;
+}
+
+void destroy_openlpc_decoder_state(openlpc_decoder_state *st)
+{
+    if(st != NULL)
+    {
+        free(st);
+        st = NULL;
+    }
+}
+
+void openlpc_sr(float sr)
+{
+    my_fs = sr;
+}
+
+size_t openlpc_get_encoder_state_size(void)
+{
+    return sizeof(openlpc_encoder_state);
+}
+
+size_t openlpc_get_decoder_state_size(void)
+{
+    return sizeof(openlpc_decoder_state);
+}
--- /dev/null
+++ b/lib/openlpc/openlpc.h
@@ -1,0 +1,38 @@
+/*
+ * LPC subroutine declarations
+ */
+
+#ifndef OPENLPC_H
+#define OPENLPC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OPENLPC_FRAMESIZE_1_8	    250
+#define OPENLPC_FRAMESIZE_1_4	    320
+#define OPENLPC_ENCODED_FRAME_SIZE  7
+
+typedef struct openlpc_e_state openlpc_encoder_state;
+typedef struct openlpc_d_state openlpc_decoder_state;
+
+openlpc_encoder_state *create_openlpc_encoder_state(void);
+void init_openlpc_encoder_state(openlpc_encoder_state *st, int framelen);
+int  openlpc_encode(const short *in, unsigned char *out, openlpc_encoder_state *st);
+void destroy_openlpc_encoder_state(openlpc_encoder_state *st);
+
+openlpc_decoder_state *create_openlpc_decoder_state(void);
+void init_openlpc_decoder_state(openlpc_decoder_state *st, int framelen);
+int  openlpc_decode(sp_data *sp, unsigned char *in, short *out, openlpc_decoder_state *st);
+void destroy_openlpc_decoder_state(openlpc_decoder_state *st);
+
+void openlpc_sr(float sr);
+
+size_t openlpc_get_encoder_state_size(void);
+size_t openlpc_get_decoder_state_size(void);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif /* OPENLPC_H */
--- /dev/null
+++ b/lib/spa/Makefile
@@ -1,0 +1,6 @@
+LPATHS += lib/spa/spa.o
+CFLAGS += -Ilib/spa/
+HPATHS += lib/spa/spa.h
+
+lib/spa/spa.o: lib/spa/spa.c
+	$(C89) $(CFLAGS) $< -c -o $@
--- /dev/null
+++ b/lib/spa/spa.c
@@ -1,0 +1,92 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+
+#define CHECK_NULL_FILE(fp) if(fp == NULL) return SP_NOT_OK
+
+int spa_open(sp_data *sp, sp_audio *spa, const char *name, int mode)
+{
+    spa_header *header;
+    header = &spa->header;
+    spa->mode = SPA_NULL;
+    spa->offset = sizeof(spa_header);
+    if(mode == SPA_READ) {
+        spa->fp = fopen(name, "rb");
+        CHECK_NULL_FILE(spa->fp);
+        fread(header, spa->offset, 1, spa->fp);
+    } else if(mode == SPA_WRITE) {
+        spa->fp = fopen(name, "wb");
+        CHECK_NULL_FILE(spa->fp);
+        header->magic = 100;
+        header->nchan = sp->nchan;
+        header->len = sp->len;
+        header->sr = sp->sr;
+        fwrite(header, spa->offset, 1, spa->fp);
+    } else {
+        return SP_NOT_OK;
+    }
+
+    spa->mode = mode;
+
+    return SP_OK;
+}
+
+size_t spa_write_buf(sp_data *sp, sp_audio *spa, SPFLOAT *buf, uint32_t size)
+{
+    if(spa->mode != SPA_WRITE) {
+        return 0;
+    }
+    return fwrite(buf, sizeof(SPFLOAT), size, spa->fp);
+}
+
+size_t spa_read_buf(sp_data *sp, sp_audio *spa, SPFLOAT *buf, uint32_t size)
+{
+    if(spa->mode != SPA_READ) {
+        return 0;
+    }
+    return fread(buf, sizeof(SPFLOAT), size, spa->fp);
+}
+
+int spa_close(sp_audio *spa)
+{
+    if(spa->fp != NULL) fclose(spa->fp);
+    return SP_OK;
+}
+
+int sp_process_spa(sp_data *sp, void *ud, void (*callback)(sp_data *, void *))
+{
+    sp_audio spa;
+    if(spa_open(sp, &spa, sp->filename, SPA_WRITE) == SP_NOT_OK) {
+        fprintf(stderr, "Error: could not open file %s.\n", sp->filename);
+    }
+    while(sp->len > 0) {
+        callback(sp, ud);
+        spa_write_buf(sp, &spa, sp->out, sp->nchan);
+        sp->len--;
+        sp->pos++;
+    }
+    spa_close(&spa);
+    return SP_OK;
+}
+
+int sp_ftbl_loadspa(sp_data *sp, sp_ftbl **ft, const char *filename)
+{
+    sp_ftbl *ftp;
+    sp_audio spa;
+    size_t size;
+
+    *ft = malloc(sizeof(sp_ftbl));
+    ftp = *ft;
+
+    spa_open(sp, &spa, filename, SPA_READ);
+
+    size = spa.header.len;
+
+    ftp->tbl = malloc(sizeof(SPFLOAT) * (size + 1));
+    sp_ftbl_init(sp, ftp, size);
+
+    spa_read_buf(sp, &spa, ftp->tbl, ftp->size);
+    spa_close(&spa);
+    return SP_OK;
+}
--- /dev/null
+++ b/lib/spa/spa.h
@@ -1,0 +1,4 @@
+int spa_open(sp_data *sp, sp_audio *spa, const char *name, int mode);
+size_t spa_write_buf(sp_data *sp, sp_audio *spa, SPFLOAT *buf, uint32_t size);
+size_t spa_read_buf(sp_data *sp, sp_audio *spa, SPFLOAT *buf, uint32_t size);
+int spa_close(sp_audio *spa);
--- /dev/null
+++ b/modules/adsr.c
@@ -1,0 +1,97 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+enum { CLEAR, ATTACK, DECAY, SUSTAIN, RELEASE };
+
+int sp_adsr_create(sp_adsr **p)
+{
+    *p = malloc(sizeof(sp_adsr));
+    return SP_OK;
+}
+
+int sp_adsr_destroy(sp_adsr **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_adsr_init(sp_data *sp, sp_adsr *p)
+{
+    p->atk = 0.1;
+    p->dec = 0.1;
+    p->sus = 0.5;
+    p->rel = 0.3;
+    p->timer = 0;
+    p->a = 0;
+    p->b = 0;
+    p->y = 0;
+    p->x = 0;
+    p->prev = 0;
+    p->atk_time = p->atk * sp->sr;
+    p->mode = CLEAR;
+    return SP_OK;
+}
+
+static SPFLOAT tau2pole(sp_data *sp, sp_adsr *p, SPFLOAT tau)
+{
+    return exp(-1.0 / (tau * sp->sr));
+}
+
+static SPFLOAT adsr_filter(sp_data *sp, sp_adsr *p)
+{
+    p->y = p->b * p->x  + p->a * p->y;
+    return p->y;
+}
+
+int sp_adsr_compute(sp_data *sp, sp_adsr *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT pole;
+    if (p->prev < *in && p->mode != DECAY) {
+        p->mode = ATTACK;
+        p->timer = 0;
+        /* quick fix: uncomment if broken */
+        /* pole = tau2pole(sp, p, p->atk * 0.75); */
+        /* p->atk_time = p->atk * sp->sr * 1.5; */
+        pole = tau2pole(sp, p, p->atk * 0.6);
+        p->atk_time = p->atk * sp->sr;
+        p->a = pole;
+        p->b = 1 - pole;
+    } else if (p->prev > *in) {
+        p->mode = RELEASE;
+        pole = tau2pole(sp, p, p->rel);
+        p->a = pole;
+        p->b = 1 - pole;
+    }
+
+    p->x = *in;
+    p->prev = *in;
+
+    switch (p->mode) {
+        case CLEAR:
+            *out = 0;
+            break;
+        case ATTACK:
+            p->timer++;
+            *out = adsr_filter(sp, p);
+            /* quick fix: uncomment if broken */
+            /* if(p->timer > p->atk_time) { */
+            if (*out > 0.99) {
+                p->mode = DECAY;
+                pole = tau2pole(sp, p, p->dec);
+                p->a = pole;
+                p->b = 1 - pole;
+            }
+            break;
+        case DECAY:
+        case RELEASE:
+            p->x *= p->sus;
+            *out = adsr_filter(sp, p);
+        default:
+            break;
+    }
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/autowah.c
@@ -1,0 +1,211 @@
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+
+static float faustpower2_f(float value) {
+	return (value * value);
+}
+
+typedef struct {
+
+	float fRec0[3];
+	float fRec3[2];
+	float fRec2[2];
+	float fRec1[2];
+	float fRec4[2];
+	float fRec5[2];
+	FAUSTFLOAT fVslider0;
+	int fSamplingFreq;
+	int iConst0;
+	float fConst1;
+	float fConst2;
+	float fConst3;
+	float fConst4;
+	float fConst5;
+	float fConst6;
+	FAUSTFLOAT fVslider1;
+	FAUSTFLOAT fVslider2;
+
+} autowah;
+
+autowah* newautowah() {
+	autowah* dsp = (autowah*)malloc(sizeof(autowah));
+	return dsp;
+}
+
+void deleteautowah(autowah* dsp) {
+	free(dsp);
+}
+
+void instanceInitautowah(autowah* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->fVslider0 = (FAUSTFLOAT)0.;
+	dsp->iConst0 = min(192000, max(1, dsp->fSamplingFreq));
+	dsp->fConst1 = (1413.72f / (float)dsp->iConst0);
+	dsp->fConst2 = exp((0.f - (100.f / (float)dsp->iConst0)));
+	dsp->fConst3 = (1.f - dsp->fConst2);
+	dsp->fConst4 = exp((0.f - (10.f / (float)dsp->iConst0)));
+	dsp->fConst5 = (1.f - dsp->fConst4);
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 2); i0 = (i0 + 1)) {
+			dsp->fRec3[i0] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec2[i1] = 0.f;
+
+		}
+
+	}
+	dsp->fConst6 = (2827.43f / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 2); i2 = (i2 + 1)) {
+			dsp->fRec1[i2] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i3;
+		for (i3 = 0; (i3 < 2); i3 = (i3 + 1)) {
+			dsp->fRec4[i3] = 0.f;
+
+		}
+
+	}
+	dsp->fVslider1 = (FAUSTFLOAT)100.;
+	dsp->fVslider2 = (FAUSTFLOAT)0.1;
+	/* C99 loop */
+	{
+		int i4;
+		for (i4 = 0; (i4 < 2); i4 = (i4 + 1)) {
+			dsp->fRec5[i4] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i5;
+		for (i5 = 0; (i5 < 3); i5 = (i5 + 1)) {
+			dsp->fRec0[i5] = 0.f;
+
+		}
+
+	}
+
+}
+
+void initautowah(autowah* dsp, int samplingFreq) {
+	instanceInitautowah(dsp, samplingFreq);
+}
+
+void buildUserInterfaceautowah(autowah* dsp, UIGlue* interface) {
+	interface->addVerticalSlider(interface->uiInterface, "level", &dsp->fVslider2, 0.1f, 0.f, 1.f, 0.01f);
+	interface->addVerticalSlider(interface->uiInterface, "wah", &dsp->fVslider0, 0.f, 0.f, 1.f, 0.01f);
+	interface->addVerticalSlider(interface->uiInterface, "wet_dry", &dsp->fVslider1, 100.f, 0.f, 100.f, 1.f);
+}
+
+void computeautowah(autowah* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* input0 = inputs[0];
+	FAUSTFLOAT* output0 = outputs[0];
+	float fSlow0 = (float)dsp->fVslider0;
+	float fSlow1 = (float)dsp->fVslider1;
+	float fSlow2 = (0.01f * (fSlow1 * (float)dsp->fVslider2));
+	float fSlow3 = ((1.f - (0.01f * fSlow1)) + (1.f - fSlow0));
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			float fTemp0 = (float)input0[i];
+			float fTemp1 = fabs(fTemp0);
+			dsp->fRec3[0] = max(fTemp1, ((dsp->fConst4 * dsp->fRec3[1]) + (dsp->fConst5 * fTemp1)));
+			dsp->fRec2[0] = ((dsp->fConst2 * dsp->fRec2[1]) + (dsp->fConst3 * dsp->fRec3[0]));
+			float fTemp2 = min(1.f, dsp->fRec2[0]);
+			float fTemp3 = pow(2.f, (2.3f * fTemp2));
+			float fTemp4 = (1.f - (dsp->fConst1 * (fTemp3 / pow(2.f, (1.f + (2.f * (1.f - fTemp2)))))));
+			dsp->fRec1[0] = ((0.999f * dsp->fRec1[1]) + (0.001f * (0.f - (2.f * (fTemp4 * cos((dsp->fConst6 * fTemp3)))))));
+			dsp->fRec4[0] = ((0.999f * dsp->fRec4[1]) + (0.001f * faustpower2_f(fTemp4)));
+			dsp->fRec5[0] = ((0.999f * dsp->fRec5[1]) + (0.0001f * pow(4.f, fTemp2)));
+			dsp->fRec0[0] = (0.f - (((dsp->fRec1[0] * dsp->fRec0[1]) + (dsp->fRec4[0] * dsp->fRec0[2])) - (fSlow2 * (dsp->fRec5[0] * fTemp0))));
+			output0[i] = (FAUSTFLOAT)((fSlow0 * (dsp->fRec0[0] - dsp->fRec0[1])) + (fSlow3 * fTemp0));
+			dsp->fRec3[1] = dsp->fRec3[0];
+			dsp->fRec2[1] = dsp->fRec2[0];
+			dsp->fRec1[1] = dsp->fRec1[0];
+			dsp->fRec4[1] = dsp->fRec4[0];
+			dsp->fRec5[1] = dsp->fRec5[0];
+			dsp->fRec0[2] = dsp->fRec0[1];
+			dsp->fRec0[1] = dsp->fRec0[0];
+		}
+
+	}
+
+}
+
+static void addVerticalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_autowah *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_autowah_create(sp_autowah **p)
+{
+    *p = malloc(sizeof(sp_autowah));
+    return SP_OK;
+}
+
+int sp_autowah_destroy(sp_autowah **p)
+{
+    sp_autowah *pp = *p;
+    autowah *dsp = pp->faust;
+    deleteautowah (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_autowah_init(sp_data *sp, sp_autowah *p)
+{
+    autowah *dsp = newautowah();
+    UIGlue UI;
+    p->argpos = 0;
+    UI.addVerticalSlider= addVerticalSlider;
+    UI.uiInterface = p;
+    buildUserInterfaceautowah(dsp, &UI);
+    initautowah(dsp, sp->sr);
+
+    p->level = p->args[0];
+    p->wah = p->args[1];
+    p->mix = p->args[2];
+
+    p->faust = dsp;
+    return SP_OK;
+}
+
+int sp_autowah_compute(sp_data *sp, sp_autowah *p, SPFLOAT *in, SPFLOAT *out)
+{
+    autowah *dsp = p->faust;
+    SPFLOAT *faust_out[] = {out};
+    SPFLOAT *faust_in[] = {in};
+    computeautowah(dsp, 1, faust_in, faust_out);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/base.c
@@ -1,0 +1,204 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#ifndef NO_LIBSNDFILE
+#include <sndfile.h>
+#endif
+#include "soundpipe.h"
+
+int sp_create(sp_data **spp)
+{
+    sp_data *sp;
+    SPFLOAT *out;
+    *spp = (sp_data *) malloc(sizeof(sp_data));
+    sp = *spp;
+    sprintf(sp->filename, "test.wav");
+    sp->nchan = 1;
+    out = malloc(sizeof(SPFLOAT) * sp->nchan);
+    *out = 0;
+    sp->out = out;
+    sp->sr = 44100;
+    sp->len = 5 * sp->sr;
+    sp->pos = 0;
+    sp->rand = 0;
+    return 0;
+}
+
+int sp_createn(sp_data **spp, int nchan)
+{
+    sp_data *sp;
+    SPFLOAT *out;
+    *spp = (sp_data *) malloc(sizeof(sp_data));
+    sp = *spp;
+    sprintf(sp->filename, "test.wav");
+    sp->nchan = nchan;
+    out = malloc(sizeof(SPFLOAT) * sp->nchan);
+    *out = 0;
+    sp->out = out;
+    sp->sr = 44100;
+    sp->len = 5 * sp->sr;
+    sp->pos = 0;
+    sp->rand = 0;
+    return 0;
+}
+
+int sp_destroy(sp_data **spp)
+{
+    sp_data *sp = *spp;
+    free(sp->out);
+    free(*spp);
+    return 0;
+}
+
+#ifndef NO_LIBSNDFILE
+
+int sp_process(sp_data *sp, void *ud, void (*callback)(sp_data *, void *))
+{
+    SNDFILE *sf[sp->nchan];
+    char tmp[140];
+    SF_INFO info;
+    memset(&info, 0, sizeof(SF_INFO));
+    SPFLOAT buf[sp->nchan][SP_BUFSIZE];
+    info.samplerate = sp->sr;
+    info.channels = 1;
+    info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
+    int numsamps, i, chan;
+
+    if (sp->nchan == 1) {
+        sf[0] = sf_open(sp->filename, SFM_WRITE, &info);
+    } else {
+        for (chan = 0; chan < sp->nchan; chan++) {
+            sprintf(tmp, "%02d_%s", chan, sp->filename);
+            sf[chan] = sf_open(tmp, SFM_WRITE, &info);
+        }
+    }
+
+    while (sp->len > 0) {
+        if (sp->len < SP_BUFSIZE) {
+            numsamps = sp->len;
+        } else {
+            numsamps = SP_BUFSIZE;
+        }
+
+        for (i = 0; i < numsamps; i++) {
+            callback(sp, ud);
+            for (chan = 0; chan < sp->nchan; chan++) {
+                buf[chan][i] = sp->out[chan];
+            }
+            sp->pos++;
+        }
+
+        for (chan = 0; chan < sp->nchan; chan++) {
+#ifdef USE_DOUBLE
+            sf_write_double(sf[chan], buf[chan], numsamps);
+#else
+            sf_write_float(sf[chan], buf[chan], numsamps);
+#endif
+        }
+        sp->len -= numsamps;
+    }
+    for (i = 0; i < sp->nchan; i++) {
+        sf_close(sf[i]);
+    }
+    return 0;
+}
+
+#endif
+
+int sp_process_raw(sp_data *sp, void *ud, void (*callback)(sp_data *, void *))
+{
+    int chan;
+    if (sp->len == 0) {
+        while(1) {
+            callback(sp, ud);
+            for (chan = 0; chan < sp->nchan; chan++) {
+                fwrite(&sp->out[chan], sizeof(SPFLOAT), 1, stdout);
+            }
+            sp->len--;
+        }
+    } else {
+        while (sp->len > 0) {
+            callback(sp, ud);
+            for (chan = 0; chan < sp->nchan; chan++) {
+                fwrite(&sp->out[chan], sizeof(SPFLOAT), 1, stdout);
+            }
+            sp->len--;
+            sp->pos++;
+        }
+    }
+    return SP_OK;
+}
+
+int sp_process_plot(sp_data *sp, void *ud, void (*callback)(sp_data *, void *))
+{
+    int chan;
+    fprintf(stdout, "sp_out =  [ ... \n");
+    while (sp->len > 0) {
+        callback(sp, ud);
+        for (chan = 0; chan < sp->nchan; chan++) {
+            /* fwrite(&sp->out[chan], sizeof(SPFLOAT), 1, stdout); */
+            fprintf(stdout, "%g ", sp->out[chan]);
+        }
+        fprintf(stdout, "; ...\n");
+        sp->len--;
+        sp->pos++;
+    }
+    fprintf(stdout, "];\n");
+
+    fprintf(stdout, "plot(sp_out);\n");
+    fprintf(stdout, "title('Plot generated by Soundpipe');\n");
+    fprintf(stdout, "xlabel('Time (samples)');\n");
+    fprintf(stdout, "ylabel('Amplitude');\n");
+    return SP_OK;
+}
+
+int sp_auxdata_alloc(sp_auxdata *aux, size_t size)
+{
+    aux->ptr = malloc(size);
+    aux->size = size;
+    memset(aux->ptr, 0, size);
+    return SP_OK;
+}
+
+int sp_auxdata_free(sp_auxdata *aux)
+{
+    free(aux->ptr);
+    return SP_OK;
+}
+
+
+SPFLOAT sp_midi2cps(SPFLOAT nn)
+{
+    return pow(2, (nn - 69.0) / 12.0) * 440.0;
+}
+
+int sp_set(sp_param *p, SPFLOAT val) {
+    p->state = 1;
+    p->val = val;
+    return SP_OK;
+}
+
+int sp_out(sp_data *sp, uint32_t chan, SPFLOAT val)
+{
+    if (chan > sp->nchan - 1) {
+        fprintf(stderr, "sp_out: Invalid channel\n");
+        return SP_NOT_OK;
+    }
+    sp->out[chan] = val;
+    return SP_OK;
+}
+
+uint32_t sp_rand(sp_data *sp)
+{
+    uint32_t val = (1103515245 * sp->rand + 12345) % SP_RANDMAX;
+    sp->rand = val;
+    return val;
+}
+
+void sp_srand(sp_data *sp, uint32_t val)
+{
+    sp->rand = val;
+}
--- /dev/null
+++ b/modules/bigverb.c
@@ -1,0 +1,44 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include "tangled/bigverb.h"
+#include "soundpipe.h"
+
+int sp_bigverb_create(sp_bigverb **p)
+{
+    *p = malloc(sizeof(sp_bigverb));
+    return SP_OK;
+}
+
+int sp_bigverb_destroy(sp_bigverb **p)
+{
+    sp_bigverb *bv;
+    bv = *p;
+    sk_bigverb_del(bv->bv);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_bigverb_init(sp_data *sp, sp_bigverb *p)
+{
+    p->feedback = 0.97;
+    p->lpfreq = 10000;
+    p->bv = sk_bigverb_new(sp->sr);
+
+    sk_bigverb_size(p->bv, p->feedback);
+    sk_bigverb_cutoff(p->bv, p->lpfreq);
+    return SP_OK;
+}
+
+int sp_bigverb_compute(sp_data *sp,
+                       sp_bigverb *p,
+                       SPFLOAT *in1,
+                       SPFLOAT *in2,
+                       SPFLOAT *out1,
+                       SPFLOAT *out2)
+{
+    sk_bigverb_size(p->bv, p->feedback);
+    sk_bigverb_cutoff(p->bv, p->lpfreq);
+    sk_bigverb_tick(p->bv, *in1, *in2, out1, out2);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/biscale.c
@@ -1,0 +1,27 @@
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_biscale_create(sp_biscale **p)
+{
+    *p = malloc(sizeof(sp_biscale));
+    return SP_OK;
+}
+
+int sp_biscale_destroy(sp_biscale **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_biscale_init(sp_data *sp, sp_biscale *p)
+{
+    p->min = 0;
+    p->max = 1;
+    return SP_OK;
+}
+
+int sp_biscale_compute(sp_data *sp, sp_biscale *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = p->min + (*in + 1.0) / 2.0 * (p->max - p->min);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/bitcrush.c
@@ -1,0 +1,56 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+int sp_bitcrush_create(sp_bitcrush **p)
+{
+    *p = malloc(sizeof(sp_bitcrush));
+    return SP_OK;
+}
+
+int sp_bitcrush_destroy(sp_bitcrush **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_bitcrush_init(sp_data *sp, sp_bitcrush *p)
+{
+    p->bitdepth = 8;
+    p->srate = 10000;
+
+    p->incr = 1000;
+    p->sample_index = 0;
+    p->index = 0.0;
+    p->value = 0.0;
+    return SP_OK;
+}
+
+int sp_bitcrush_compute(sp_data *sp, sp_bitcrush *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT bits = pow(2, floor(p->bitdepth));
+    SPFLOAT foldamt = sp->sr / p->srate;
+    SPFLOAT sig;
+    *out = *in * 65536.0;
+    *out += 32768;
+    *out *= (bits / 65536.0);
+    *out = floor(*out);
+    *out = *out * (65536.0 / bits) - 32768;
+    sig = *out;
+    p->incr = foldamt;
+
+    /* apply downsampling */
+    if (p->index < (SPFLOAT)p->sample_index) {
+        p->index += p->incr;
+        p->value = sig;
+    }
+
+    *out = p->value;
+
+    p->sample_index++;
+
+    *out /= 65536.0;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/blsaw.c
@@ -1,0 +1,171 @@
+/*
+ * Saw
+ *
+ * This code was generated by Faust. It utilizes the saw2 Faust
+ * module coded by Julius Smith. See oscillator.lib for more details.
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+static float faustpower2_f(float value) {
+	return (value * value);
+
+}
+
+typedef struct {
+
+	float fRec0[2];
+	float fVec0[2];
+	float fVec1[2];
+	int fSamplingFreq;
+	int iConst0;
+	FAUSTFLOAT fHslider0;
+	FAUSTFLOAT fHslider1;
+	float fConst1;
+	float fConst2;
+} blsaw;
+
+blsaw* newblsaw() {
+	blsaw* dsp = (blsaw*)malloc(sizeof(blsaw));
+	return dsp;
+}
+
+void deleteblsaw(blsaw* dsp) {
+	free(dsp);
+}
+
+void instanceInitblsaw(blsaw* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->iConst0 = min(192000, max(1, dsp->fSamplingFreq));
+	dsp->fHslider0 = (FAUSTFLOAT)1.;
+	dsp->fHslider1 = (FAUSTFLOAT)440.;
+	dsp->fConst1 = (float)dsp->iConst0;
+	dsp->fConst2 = (2.f / dsp->fConst1);
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 2); i0 = (i0 + 1)) {
+			dsp->fRec0[i0] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fVec0[i1] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 2); i2 = (i2 + 1)) {
+			dsp->fVec1[i2] = 0.f;
+
+		}
+
+	}
+
+}
+
+void initblsaw(blsaw* dsp, int samplingFreq) {
+	instanceInitblsaw(dsp, samplingFreq);
+}
+
+void buildUserInterfaceblsaw(blsaw* dsp, UIGlue* interface) {
+	interface->addHorizontalSlider(interface->uiInterface, "freq", &dsp->fHslider1, 440.f, 0.f, 20000.f, 0.0001f);
+	interface->addHorizontalSlider(interface->uiInterface, "amp", &dsp->fHslider0, 1.f, 0.f, 1.f, 0.0001f);
+}
+
+void computeblsaw(blsaw* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* output0 = outputs[0];
+	float fSlow0 = (float)dsp->fHslider1;
+	float fSlow1 = ((float)dsp->iConst0 * ((float)dsp->fHslider0 / fSlow0));
+	float fSlow2 = (dsp->fConst2 * fSlow0);
+	float fSlow3 = (dsp->fConst1 / fSlow0);
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			dsp->fRec0[0] = fmod((1.f + dsp->fRec0[1]), fSlow3);
+			float fTemp0 = faustpower2_f(((fSlow2 * dsp->fRec0[0]) - 1.f));
+			dsp->fVec0[0] = fTemp0;
+			dsp->fVec1[0] = 0.25f;
+			output0[i] = (FAUSTFLOAT)(fSlow1 * ((fTemp0 - dsp->fVec0[1]) * dsp->fVec1[1]));
+			dsp->fRec0[1] = dsp->fRec0[0];
+			dsp->fVec0[1] = dsp->fVec0[0];
+			dsp->fVec1[1] = dsp->fVec1[0];
+
+		}
+
+	}
+
+}
+
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_blsaw *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_blsaw_create(sp_blsaw **p)
+{
+    *p = malloc(sizeof(sp_blsaw));
+    return SP_OK;
+}
+
+int sp_blsaw_destroy(sp_blsaw **p)
+{
+    sp_blsaw *pp = *p;
+    blsaw *dsp = pp->ud;
+    deleteblsaw (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_blsaw_init(sp_data *sp, sp_blsaw *p)
+{
+    blsaw *dsp = newblsaw();
+    UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.uiInterface = p;
+    buildUserInterfaceblsaw(dsp, &UI);
+    initblsaw(dsp, sp->sr);
+
+
+    p->freq = p->args[0];
+    p->amp = p->args[1];
+
+    p->ud = dsp;
+    return SP_OK;
+}
+
+int sp_blsaw_compute(sp_data *sp, sp_blsaw *p, SPFLOAT *in, SPFLOAT *out)
+{
+
+    blsaw *dsp = p->ud;
+    SPFLOAT out1 = 0;
+    SPFLOAT *faust_out[] = {&out1};
+    SPFLOAT *faust_in[] = {in};
+    computeblsaw(dsp, 1, faust_in, faust_out);
+
+    *out = out1;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/blsquare.c
@@ -1,0 +1,185 @@
+#include <math.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+float fmodf(float dummy0, float dummy1);
+static float faustpower2_f(float value) {
+	return (value * value);
+}
+
+typedef struct {
+	float fVec2[4096];
+	int iVec0[2];
+	float fRec0[2];
+	float fVec1[2];
+	FAUSTFLOAT fHslider0;
+	int fSamplingFreq;
+	float fConst0;
+	FAUSTFLOAT fHslider1;
+	FAUSTFLOAT fHslider2;
+	float fConst1;
+	float fConst2;
+	int IOTA;
+} blsquare;
+
+blsquare* newblsquare() {
+	blsquare* dsp = (blsquare*)malloc(sizeof(blsquare));
+	return dsp;
+}
+
+void deleteblsquare(blsquare* dsp) {
+	free(dsp);
+}
+
+
+void instanceInitblsquare(blsquare* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->fHslider0 = (FAUSTFLOAT)1.;
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 2); i0 = (i0 + 1)) {
+			dsp->iVec0[i0] = 0;
+
+		}
+
+	}
+	dsp->fConst0 = (float)min(192000, max(1, dsp->fSamplingFreq));
+	dsp->fHslider1 = (FAUSTFLOAT)0.5;
+	dsp->fHslider2 = (FAUSTFLOAT)440.;
+	dsp->fConst1 = (0.25f * dsp->fConst0);
+	dsp->fConst2 = (1.f / dsp->fConst0);
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec0[i1] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 2); i2 = (i2 + 1)) {
+			dsp->fVec1[i2] = 0.f;
+
+		}
+
+	}
+	dsp->IOTA = 0;
+	/* C99 loop */
+	{
+		int i3;
+		for (i3 = 0; (i3 < 4096); i3 = (i3 + 1)) {
+			dsp->fVec2[i3] = 0.f;
+
+		}
+
+	}
+
+}
+
+void initblsquare(blsquare* dsp, int samplingFreq) {
+	instanceInitblsquare(dsp, samplingFreq);
+}
+
+void buildUserInterfaceblsquare(blsquare* dsp, UIGlue* interface) {
+	interface->addHorizontalSlider(interface->uiInterface, "frequency", &dsp->fHslider2, 440.f, 0.f, 20000.f, 0.0001f);
+	interface->addHorizontalSlider(interface->uiInterface, "amp", &dsp->fHslider0, 1.f, 0.f, 1.f, 1e-05f);
+	interface->addHorizontalSlider(interface->uiInterface, "width", &dsp->fHslider1, 0.5f, 0.f, 1.f, 0.f);
+}
+
+void computeblsquare(blsquare* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* output0 = outputs[0];
+	float fSlow0 = (float)dsp->fHslider0;
+	float fSlow1 = max((float)dsp->fHslider2, 23.4489f);
+	float fSlow2 = max(0.f, min(2047.f, (dsp->fConst0 * ((float)dsp->fHslider1 / fSlow1))));
+	int iSlow3 = (int)fSlow2;
+	int iSlow4 = (1 + iSlow3);
+	float fSlow5 = ((float)iSlow4 - fSlow2);
+	float fSlow6 = (dsp->fConst1 / fSlow1);
+	float fSlow7 = (dsp->fConst2 * fSlow1);
+	float fSlow8 = (fSlow2 - (float)iSlow3);
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			dsp->iVec0[0] = 1;
+			dsp->fRec0[0] = fmodf((dsp->fRec0[1] + fSlow7), 1.f);
+			float fTemp0 = faustpower2_f(((2.f * dsp->fRec0[0]) - 1.f));
+			dsp->fVec1[0] = fTemp0;
+			float fTemp1 = (fSlow6 * ((fTemp0 - dsp->fVec1[1]) * (float)dsp->iVec0[1]));
+			dsp->fVec2[(dsp->IOTA & 4095)] = fTemp1;
+			output0[i] = (FAUSTFLOAT)(fSlow0 * (0.f - (((fSlow5 * dsp->fVec2[((dsp->IOTA - iSlow3) & 4095)]) + (fSlow8 * dsp->fVec2[((dsp->IOTA - iSlow4) & 4095)])) - fTemp1)));
+			dsp->iVec0[1] = dsp->iVec0[0];
+			dsp->fRec0[1] = dsp->fRec0[0];
+			dsp->fVec1[1] = dsp->fVec1[0];
+			dsp->IOTA = (dsp->IOTA + 1);
+
+		}
+
+	}
+
+}
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_blsquare *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_blsquare_create(sp_blsquare **p)
+{
+    *p = malloc(sizeof(sp_blsquare));
+    return SP_OK;
+}
+
+int sp_blsquare_destroy(sp_blsquare **p)
+{
+    sp_blsquare *pp = *p;
+    blsquare *dsp = pp->ud;
+    deleteblsquare (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_blsquare_init(sp_data *sp, sp_blsquare *p)
+{
+    blsquare *dsp = newblsquare(); UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.uiInterface = p;
+    buildUserInterfaceblsquare(dsp, &UI);
+    initblsquare(dsp, sp->sr);
+
+
+    p->freq = p->args[0];
+    p->amp = p->args[1];
+    p->width = p->args[2];
+
+    p->ud = dsp;
+    return SP_OK;
+}
+
+int sp_blsquare_compute(sp_data *sp, sp_blsquare *p, SPFLOAT *in, SPFLOAT *out)
+{
+
+    blsquare *dsp = p->ud;
+    SPFLOAT out1 = 0;
+    SPFLOAT *faust_out[] = {&out1};
+    SPFLOAT *faust_in[] = {in};
+    computeblsquare(dsp, 1, faust_in, faust_out);
+
+    *out = out1;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/bltriangle.c
@@ -1,0 +1,202 @@
+#include <math.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+float fmodf(float dummy0, float dummy1);
+static float faustpower2_f(float value) {
+	return (value * value);
+
+}
+
+typedef struct {
+
+	float fVec2[4096];
+	int iVec0[2];
+	float fRec1[2];
+	float fVec1[2];
+	float fRec0[2];
+	int fSamplingFreq;
+	int iConst0;
+	float fConst1;
+	FAUSTFLOAT fHslider0;
+	FAUSTFLOAT fHslider1;
+	float fConst2;
+	float fConst3;
+	float fConst4;
+	float fConst5;
+	int IOTA;
+
+} bltriangle;
+
+bltriangle* newbltriangle() {
+	bltriangle* dsp = (bltriangle*)malloc(sizeof(bltriangle));
+	return dsp;
+}
+
+void deletebltriangle(bltriangle* dsp) {
+	free(dsp);
+}
+
+void instanceInitbltriangle(bltriangle* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 2); i0 = (i0 + 1)) {
+			dsp->iVec0[i0] = 0;
+
+		}
+
+	}
+	dsp->iConst0 = min(192000, max(1, dsp->fSamplingFreq));
+	dsp->fConst1 = (4.f / (float)dsp->iConst0);
+	dsp->fHslider0 = (FAUSTFLOAT)440.;
+	dsp->fHslider1 = (FAUSTFLOAT)1.;
+	dsp->fConst2 = (float)dsp->iConst0;
+	dsp->fConst3 = (0.5f * dsp->fConst2);
+	dsp->fConst4 = (0.25f * dsp->fConst2);
+	dsp->fConst5 = (1.f / dsp->fConst2);
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec1[i1] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 2); i2 = (i2 + 1)) {
+			dsp->fVec1[i2] = 0.f;
+
+		}
+
+	}
+	dsp->IOTA = 0;
+	/* C99 loop */
+	{
+		int i3;
+		for (i3 = 0; (i3 < 4096); i3 = (i3 + 1)) {
+			dsp->fVec2[i3] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i4;
+		for (i4 = 0; (i4 < 2); i4 = (i4 + 1)) {
+			dsp->fRec0[i4] = 0.f;
+
+		}
+
+	}
+
+}
+
+void initbltriangle(bltriangle* dsp, int samplingFreq) {
+	instanceInitbltriangle(dsp, samplingFreq);
+}
+
+void buildUserInterfacebltriangle(bltriangle* dsp, UIGlue* interface) {
+	interface->addHorizontalSlider(interface->uiInterface, "freq", &dsp->fHslider0, 440.f, 0.f, 20000.f, 0.0001f);
+	interface->addHorizontalSlider(interface->uiInterface, "amp", &dsp->fHslider1, 1.f, 0.f, 1.f, 1e-05f);
+}
+
+void computebltriangle(bltriangle* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* output0 = outputs[0];
+	float fSlow0 = (float)dsp->fHslider0;
+	float fSlow1 = (dsp->fConst1 * (fSlow0 * (float)dsp->fHslider1));
+	float fSlow2 = max(fSlow0, 23.4489f);
+	float fSlow3 = max(0.f, min(2047.f, (dsp->fConst3 / fSlow2)));
+	int iSlow4 = (int)fSlow3;
+	int iSlow5 = (1 + iSlow4);
+	float fSlow6 = ((float)iSlow5 - fSlow3);
+	float fSlow7 = (dsp->fConst4 / fSlow2);
+	float fSlow8 = (dsp->fConst5 * fSlow2);
+	float fSlow9 = (fSlow3 - (float)iSlow4);
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			dsp->iVec0[0] = 1;
+			dsp->fRec1[0] = fmodf((dsp->fRec1[1] + fSlow8), 1.f);
+			float fTemp0 = faustpower2_f(((2.f * dsp->fRec1[0]) - 1.f));
+			dsp->fVec1[0] = fTemp0;
+			float fTemp1 = (fSlow7 * ((fTemp0 - dsp->fVec1[1]) * (float)dsp->iVec0[1]));
+			dsp->fVec2[(dsp->IOTA & 4095)] = fTemp1;
+			dsp->fRec0[0] = (0.f - (((fSlow6 * dsp->fVec2[((dsp->IOTA - iSlow4) & 4095)]) + (fSlow9 * dsp->fVec2[((dsp->IOTA - iSlow5) & 4095)])) - ((0.999f * dsp->fRec0[1]) + fTemp1)));
+			output0[i] = (FAUSTFLOAT)(fSlow1 * dsp->fRec0[0]);
+			dsp->iVec0[1] = dsp->iVec0[0];
+			dsp->fRec1[1] = dsp->fRec1[0];
+			dsp->fVec1[1] = dsp->fVec1[0];
+			dsp->IOTA = (dsp->IOTA + 1);
+			dsp->fRec0[1] = dsp->fRec0[0];
+
+		}
+
+	}
+
+}
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_bltriangle *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_bltriangle_create(sp_bltriangle **p)
+{
+    *p = malloc(sizeof(sp_bltriangle));
+    return SP_OK;
+}
+
+int sp_bltriangle_destroy(sp_bltriangle **p)
+{
+    sp_bltriangle *pp = *p;
+    bltriangle *dsp = pp->ud;
+    deletebltriangle (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_bltriangle_init(sp_data *sp, sp_bltriangle *p)
+{
+    bltriangle *dsp = newbltriangle(); UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.uiInterface = p;
+    buildUserInterfacebltriangle(dsp, &UI);
+    initbltriangle(dsp, sp->sr);
+
+
+    p->freq = p->args[0];
+    p->amp = p->args[1];
+
+    p->ud = dsp;
+    return SP_OK;
+}
+
+int sp_bltriangle_compute(sp_data *sp, sp_bltriangle *p, SPFLOAT *in, SPFLOAT *out)
+{
+
+    bltriangle *dsp = p->ud;
+    SPFLOAT out1 = 0;
+    SPFLOAT *faust_out[] = {&out1};
+    SPFLOAT *faust_in[] = {in};
+    computebltriangle(dsp, 1, faust_in, faust_out);
+
+    *out = out1;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/brown.c
@@ -1,0 +1,47 @@
+/*
+ * Brown
+ *
+ * Brownian noise algorithm based on implementation found here:
+ * http://vellocet.com/dsp/noise/VRand.h
+ *
+ *
+ */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_brown_create(sp_brown **p)
+{
+    *p = malloc(sizeof(sp_brown));
+    return SP_OK;
+}
+
+int sp_brown_destroy(sp_brown **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_brown_init(sp_data *sp, sp_brown *p)
+{
+    p->brown = 0.0;
+    return SP_OK;
+}
+
+int sp_brown_compute(sp_data *sp, sp_brown *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT r;
+    while (1) {
+        r = (sp_rand(sp) % SP_RANDMAX) / (SPFLOAT)(SP_RANDMAX);
+        r = ((r * 2) - 1) * 0.5;
+        p->brown += r;
+        if (p->brown < -8.0f || p->brown > 8.0f) {
+            p->brown -= r;
+        } else {
+            break;
+        }
+    }
+
+    *out = p->brown * 0.0625;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/butbp.c
@@ -1,0 +1,86 @@
+/*
+ * Butbp
+ *
+ * This is an implementation of a 2nd-order butterworth
+ * bandpass filter, discretized using the bilinear transform.
+ *
+ * For more information on using the BLT on 2nd-order
+ * butterworth filters, see:
+ *
+ * https://ccrma.stanford.edu/~jos/filters/Example_Second_Order_Butterworth_Lowpass.html
+ */
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#define ROOT2 (1.4142135623730950488)
+
+#ifndef M_PI
+#define M_PI		3.14159265358979323846	/* pi */
+#endif
+
+#include "soundpipe.h"
+
+int sp_butbp_create(sp_butbp **p)
+{
+    *p = malloc(sizeof(sp_butbp));
+    return SP_OK;
+}
+
+int sp_butbp_destroy(sp_butbp **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_butbp_init(sp_data *sp, sp_butbp *p)
+{
+    p->freq = 1000;
+    p->bw = 10;
+    p->pidsr = M_PI / sp->sr * 1.0;
+    p->tpidsr = 2 * M_PI / sp->sr * 1.0;
+    p->a[5] = p->a[6] = 0.0;
+    p->lfreq = 0.0;
+    p->lbw = 0.0;
+    return SP_OK;
+}
+
+int sp_butbp_compute(sp_data *sp, sp_butbp *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT *a;
+    SPFLOAT t, y;
+    SPFLOAT bw, fr;
+
+    a = p->a;
+    if (p->bw <= 0.0) {
+       *out = 0;
+       return SP_OK;
+    }
+
+    bw = p->bw;
+    fr = p->freq;
+
+    if (bw != p->lbw || fr != p->lfreq) {
+        SPFLOAT c, d;
+        p->lfreq = fr;
+        p->lbw = bw;
+
+        /* Perform BLT and store components */
+        c = 1.0 / tan((SPFLOAT)(p->pidsr * bw));
+        d = 2.0 * cos((SPFLOAT)(p->tpidsr * fr));
+        a[0] = 1.0 / (1.0 + c);
+        a[1] = 0.0;
+        a[2] = -a[0];
+        a[3] = - c * d * a[0];
+        a[4] = (c - 1.0) * a[0];
+    }
+
+    /* a5 = t(n - 1); a6 = t(n - 2) */
+    t = *in - a[3]*a[5] - a[4]*a[6];
+    y = t*a[0] + a[1]*a[5] + a[2]*a[6];
+    a[6] = a[5];
+    a[5] = t;
+    *out = y;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/butbr.c
@@ -1,0 +1,80 @@
+/*
+ * Butbr
+ *
+ * This is an implementation of a 2nd-order butterworth
+ * band-reject filter, discretized using the bilinear transform.
+ *
+ * For more information on using the BLT on 2nd-order
+ * butterworth filters, see:
+ *
+ * https://ccrma.stanford.edu/~jos/filters/Example_Second_Order_Butterworth_Lowpass.html
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+int sp_butbr_create(sp_butbr **p)
+{
+    *p = malloc(sizeof(sp_butbr));
+    return SP_OK;
+}
+
+int sp_butbr_destroy(sp_butbr **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_butbr_init(sp_data *sp, sp_butbr *p)
+{
+    p->freq = 1000;
+    p->bw = 1000;
+    p->pidsr = M_PI / sp->sr * 1.0;
+    p->tpidsr = 2 * M_PI / sp->sr * 1.0;
+    p->a[5] = p->a[6] = 0.0;
+    p->lfreq = 0.0;
+    p->lbw = 0.0;
+    return SP_OK;
+}
+
+int sp_butbr_compute(sp_data *sp, sp_butbr *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT *a;
+    SPFLOAT t, y;
+    SPFLOAT bw, freq;
+
+    if (p->bw <= 0.0) {
+      *out = 0;
+      return SP_OK;
+    }
+
+    a = p->a;
+    bw = p->bw;
+    freq = p->freq;
+
+    if (bw != p->lbw || freq != p->lfreq) {
+        SPFLOAT c, d;
+        p->lfreq = freq;
+        p->lbw = bw;
+        c = tan((SPFLOAT)(p->pidsr * bw));
+        d = 2.0 * cos((SPFLOAT)(p->tpidsr * freq));
+        a[0] = 1.0 / (1.0 + c);
+        a[1] = -d * a[0];
+        a[2] = a[0];
+        a[3] = a[1];
+        a[4] = (1.0 - c) * a[0];
+    }
+
+    t = *in - a[3]*a[5] - a[4]*a[6];
+    y = t*a[0] + a[1]*a[5] + a[2]*a[6];
+    a[6] = a[5];
+    a[5] = t;
+    *out = y;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/buthp.c
@@ -1,0 +1,83 @@
+/*
+ * Buthp
+ *
+ * This is an implementation of a 2nd-order butterworth
+ * highpass filter, discretized using the bilinear transform.
+ *
+ * For more information on using the BLT on 2nd-order
+ * butterworth filters, see:
+ *
+ * https://ccrma.stanford.edu/~jos/filters/Example_Second_Order_Butterworth_Lowpass.html
+ */
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#define ROOT2 (1.4142135623730950488)
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "soundpipe.h"
+
+static int filter(SPFLOAT *in, SPFLOAT *out, SPFLOAT *a)
+{
+    SPFLOAT t, y;
+
+    /* a5 = t(n - 1); a6 = t(n - 2) */
+    t = *in - a[3]*a[5] - a[4]*a[6];
+    y = t*a[0] + a[1]*a[5] + a[2]*a[6];
+    a[6] = a[5];
+    a[5] = t;
+    *out = y;
+    return SP_OK;
+}
+
+
+int sp_buthp_create(sp_buthp **p)
+{
+    *p = malloc(sizeof(sp_buthp));
+    return SP_OK;
+}
+
+int sp_buthp_destroy(sp_buthp **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_buthp_init(sp_data *sp, sp_buthp *p)
+{
+    p->freq = 1000;
+    p->pidsr = M_PI / sp->sr * 1.0;
+    p->a[5] = p->a[6] = 0.0;
+    p->lfreq = 0.0;
+    return SP_OK;
+}
+
+int sp_buthp_compute(sp_data *sp, sp_buthp *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (p->freq <= 0.0) {
+        *out = 0;
+        return SP_OK;
+    }
+
+    if (p->freq != p->lfreq) {
+        SPFLOAT *a, c;
+        a = p->a;
+        p->lfreq = p->freq;
+        /* derive C constant used in BLT */
+        c = tan((SPFLOAT)(p->pidsr * p->freq));
+
+        /* perform BLT, store components */
+        a[0] = 1.0 / (1.0 + c*ROOT2 + c*c);
+        a[1] = -2*a[0];
+        a[2] = a[0];
+        a[3] = 2.0 * (c*c - 1.0) * a[0];
+        a[4] = (1.0 - c*ROOT2 + c*c) * a[0];
+    }
+
+    filter(in, out, p->a);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/butlp.c
@@ -1,0 +1,81 @@
+/*
+ * Butlp
+ *
+ * This is an implementation of a 2nd-order butterworth
+ * lowpass filter, discretized using the bilinear transform.
+ *
+ * For more information on using the BLT on 2nd-order
+ * butterworth filters, see:
+ *
+ * https://ccrma.stanford.edu/~jos/filters/Example_Second_Order_Butterworth_Lowpass.html
+ */
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#define ROOT2 (1.4142135623730950488)
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "soundpipe.h"
+
+static int filter(SPFLOAT *in, SPFLOAT *out, SPFLOAT *a)
+{
+    SPFLOAT t, y;
+    /* a5 = t(n - 1); a6 = t(n - 2) */
+    t = *in - a[3]*a[5] - a[4]*a[6];
+    y = t*a[0] + a[1]*a[5] + a[2]*a[6];
+    a[6] = a[5];
+    a[5] = t;
+    *out = y;
+    return SP_OK;
+}
+
+int sp_butlp_create(sp_butlp **p)
+{
+    *p = malloc(sizeof(sp_butlp));
+    return SP_OK;
+}
+
+int sp_butlp_destroy(sp_butlp **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_butlp_init(sp_data *sp, sp_butlp *p)
+{
+    p->freq = 1000;
+    p->pidsr = M_PI / sp->sr * 1.0;
+    p->a[5] = p->a[6] = 0.0;
+    p->lfreq = 0.0;
+    return SP_OK;
+}
+
+int sp_butlp_compute(sp_data *sp, sp_butlp *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (p->freq <= 0.0) {
+        *out = 0;
+        return SP_NOT_OK;
+    }
+
+    if (p->freq != p->lfreq) {
+        SPFLOAT *a, c;
+        a = p->a;
+        p->lfreq = p->freq;
+        /* derive C constant used in BLT */
+        c = 1.0 / tan((SPFLOAT)(p->pidsr * p->lfreq));
+
+        /* perform BLT, store components */
+        a[0] = 1.0 / (1.0 + c*ROOT2 + c*c);
+        a[1] = 2*a[0];
+        a[2] = a[0];
+        a[3] = 2.0 * (1.0 - c*c) * a[0];
+        a[4] = (1.0 - c*ROOT2 + c*c) * a[0];
+    }
+
+    filter(in, out, p->a);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/clamp.c
@@ -1,0 +1,31 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_clamp_create(sp_clamp **p)
+{
+    *p = malloc(sizeof(sp_clamp));
+    return SP_OK;
+}
+
+int sp_clamp_destroy(sp_clamp **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_clamp_init(sp_data *sp, sp_clamp *p)
+{
+    p->min = 0;
+    p->max = 1;
+    return SP_OK;
+}
+
+int sp_clamp_compute(sp_data *sp, sp_clamp *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in < p->min) *out = p->min;
+    else if (*in > p->max) *out = p->max;
+    else *out = *in;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/clock.c
@@ -1,0 +1,35 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_clock_create(sp_clock **p)
+{
+    *p = malloc(sizeof(sp_clock));
+    return SP_OK;
+}
+
+int sp_clock_destroy(sp_clock **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_clock_init(sp_data *sp, sp_clock *p)
+{
+    p->subdiv = 1.0;
+    p->bpm = 120;
+    p->counter = 0;
+    return SP_OK;
+}
+
+int sp_clock_compute(sp_data *sp, sp_clock *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = 0.0;
+    if (p->counter == 0 || *in != 0) {
+        *out = 1.0;
+        p->counter = (int)(sp->sr * (60.0 / (p->bpm * p->subdiv))) + 1;
+    }
+    p->counter--;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/compressor.c
@@ -1,0 +1,167 @@
+#include <math.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT SPFLOAT
+#endif
+
+typedef struct {
+	float fRec2[2];
+	float fRec1[2];
+	float fRec0[2];
+	int fSamplingFreq;
+	int iConst0;
+	float fConst1;
+	FAUSTFLOAT fHslider0;
+	FAUSTFLOAT fHslider1;
+	float fConst2;
+	FAUSTFLOAT fHslider2;
+	FAUSTFLOAT fHslider3;
+} compressor;
+
+static compressor* newcompressor() {
+	compressor* dsp = (compressor*)malloc(sizeof(compressor));
+	return dsp;
+}
+
+static void deletecompressor(compressor* dsp) {
+	free(dsp);
+}
+
+static void instanceInitcompressor(compressor* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->iConst0 = min(192000, max(1, dsp->fSamplingFreq));
+	dsp->fConst1 = (2.f / (float)dsp->iConst0);
+	dsp->fHslider0 = (FAUSTFLOAT)0.1;
+	dsp->fHslider1 = (FAUSTFLOAT)1.;
+	dsp->fConst2 = (1.f / (float)dsp->iConst0);
+	dsp->fHslider2 = (FAUSTFLOAT)0.1;
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 2); i0 = (i0 + 1)) {
+			dsp->fRec2[i0] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec1[i1] = 0.f;
+
+		}
+
+	}
+	dsp->fHslider3 = (FAUSTFLOAT)0.;
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 2); i2 = (i2 + 1)) {
+			dsp->fRec0[i2] = 0.f;
+
+		}
+
+	}
+
+}
+
+static void initcompressor(compressor* dsp, int samplingFreq) {
+	instanceInitcompressor(dsp, samplingFreq);
+}
+
+static void buildUserInterfacecompressor(compressor* dsp, UIGlue* interface) {
+	interface->addHorizontalSlider(interface->uiInterface, "ratio", &dsp->fHslider1, 1.f, 1.f, 40.f, 0.001f);
+	interface->addHorizontalSlider(interface->uiInterface, "thresh", &dsp->fHslider3, 0.f, -80.f, 0.f, 0.001f);
+	interface->addHorizontalSlider(interface->uiInterface, "atk", &dsp->fHslider0, 0.1f, 0.f, 10.f, 0.001f);
+	interface->addHorizontalSlider(interface->uiInterface, "rel", &dsp->fHslider2, 0.1f, 0.f, 10.f, 0.001f);
+}
+
+static void computecompressor(compressor* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* input0 = inputs[0];
+	FAUSTFLOAT* output0 = outputs[0];
+	float fSlow0 = (float)dsp->fHslider0;
+	float fSlow1 = exp((0.f - (dsp->fConst1 / fSlow0)));
+	float fSlow2 = ((1.f - fSlow1) * ((1.f / (float)dsp->fHslider1) - 1.f));
+	float fSlow3 = exp((0.f - (dsp->fConst2 / fSlow0)));
+	float fSlow4 = exp((0.f - (dsp->fConst2 / (float)dsp->fHslider2)));
+	float fSlow5 = (float)dsp->fHslider3;
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			float fTemp0 = (float)input0[i];
+			float fTemp1 = fabs(fTemp0);
+			float fTemp2 = ((dsp->fRec1[1] > fTemp1)?fSlow4:fSlow3);
+			dsp->fRec2[0] = ((dsp->fRec2[1] * fTemp2) + ((1.f - fTemp2) * fTemp1));
+			dsp->fRec1[0] = dsp->fRec2[0];
+			dsp->fRec0[0] = ((fSlow1 * dsp->fRec0[1]) + (fSlow2 * max(((20.f * log10(dsp->fRec1[0])) - fSlow5), 0.f)));
+			output0[i] = (FAUSTFLOAT)(pow(10.f, (0.05f * dsp->fRec0[0])) * fTemp0);
+			dsp->fRec2[1] = dsp->fRec2[0];
+			dsp->fRec1[1] = dsp->fRec1[0];
+			dsp->fRec0[1] = dsp->fRec0[0];
+
+		}
+
+	}
+
+}
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_compressor *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_compressor_create(sp_compressor **p)
+{
+    *p = malloc(sizeof(sp_compressor));
+    return SP_OK;
+}
+
+int sp_compressor_destroy(sp_compressor **p)
+{
+    sp_compressor *pp = *p;
+    compressor *dsp = pp->faust;
+    deletecompressor (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_compressor_init(sp_data *sp, sp_compressor *p)
+{
+    compressor *dsp = newcompressor();
+    UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.uiInterface = p;
+    buildUserInterfacecompressor(dsp, &UI);
+    initcompressor(dsp, sp->sr);
+
+
+    p->ratio = p->args[0];
+    p->thresh = p->args[1];
+    p->atk = p->args[2];
+    p->rel = p->args[3];
+
+    p->faust = dsp;
+    return SP_OK;
+}
+
+int sp_compressor_compute(sp_data *sp, sp_compressor *p, SPFLOAT *in, SPFLOAT *out)
+{
+
+    compressor *dsp = p->faust;
+    SPFLOAT *faust_out[] = {out};
+    SPFLOAT *faust_in[] = {in};
+    computecompressor(dsp, 1, faust_in, faust_out);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/count.c
@@ -1,0 +1,46 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_count_create(sp_count **p)
+{
+    *p = malloc(sizeof(sp_count));
+    return SP_OK;
+}
+
+int sp_count_destroy(sp_count **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_count_init(sp_data *sp, sp_count *p)
+{
+    p->count = 4;
+    p->curcount = -1;
+    p->mode = 0;
+    return SP_OK;
+}
+
+int sp_count_compute(sp_data *sp, sp_count *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in){
+        if (p->mode == 0) {
+            p->curcount = (p->curcount + 1) % p->count;
+        } else {
+            if (p->curcount == -2) {
+                *out = -2;
+                return SP_OK;
+            }
+            if (p->curcount >= p->count - 1) {
+                p->curcount = -2;
+            } else {
+                if (p->curcount == -1) p->curcount = 0;
+                else p->curcount++;
+            }
+        }
+    }
+    *out = p->curcount;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/crossfade.c
@@ -1,0 +1,28 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_crossfade_create(sp_crossfade **p)
+{
+    *p = malloc(sizeof(sp_crossfade));
+    return SP_OK;
+}
+
+int sp_crossfade_destroy(sp_crossfade **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_crossfade_init(sp_data *sp, sp_crossfade *p)
+{
+    p->pos = 0.5;
+    return SP_OK;
+}
+
+int sp_crossfade_compute(sp_data *sp, sp_crossfade *p, SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out)
+{
+    *out = *in2 * p->pos + *in1 * (1 - p->pos);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/data/adsr.lua
@@ -1,0 +1,75 @@
+sptbl["adsr"] = {
+
+    files = {
+        module = "adsr.c",
+        header = "adsr.h",
+        example = "ex_adsr.c",
+    },
+
+    func = {
+        create = "sp_adsr_create",
+        destroy = "sp_adsr_destroy",
+        init = "sp_adsr_init",
+        compute = "sp_adsr_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "atk",
+                type = "SPFLOAT",
+                description = "Attack",
+                default = 0.1
+            },
+            {
+                name = "dec",
+                type = "SPFLOAT",
+                description ="Decay",
+                default = 0.1
+            },
+            {
+                name = "sus",
+                type = "SPFLOAT",
+                description ="Sustain (in range 0-1)",
+                default = 0.5
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT",
+                description ="Release",
+                default = 0.3
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[ADSR generator
+This is an ADSR generator whose curves are created using a one-pole low pass filter.
+
+NOTE: The attack, decay, and release parameters are "fuzzy" values that don't
+exactly correspond to duration in seconds. More accurately, they are special
+tau constant units that feed into the filter used to generate the envelope. The
+attack value specificly undergoes some "creative" modificiations in order to
+create snappier attack times. It is highly recommend to tune parameters by
+ear rather than to read the values literally.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "gate",
+            description = "Gate signal. This should be a steady state signal that jumps from 0 to 1."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "ADSR envelope."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/autowah.lua
@@ -1,0 +1,62 @@
+sptbl["autowah"] = {
+
+    files = {
+        module = "autowah.c",
+        header = "autowah.h",
+        example = "ex_autowah.c",
+    },
+
+    func = {
+        create = "sp_autowah_create",
+        destroy = "sp_autowah_destroy",
+        init = "sp_autowah_init",
+        compute = "sp_autowah_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "level",
+                type = "SPFLOAT*",
+                description = "Overall level (between 0 and 1)",
+                default = 0.1
+            },
+            {
+                name = "wah",
+                type = "SPFLOAT*",
+                description ="wah amount",
+                default = 0
+            },
+            {
+                name = "mix",
+                type = "SPFLOAT*",
+                description ="Wet/dry amount (100 = wet, 0 = dry)",
+                default = 100
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Automatic wah pedal
+	An automatic wah effect, ported from Guitarix via Faust. 
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Audio input"
+        },
+    },
+    
+    outputs = {
+        {
+            name = "output",
+            description = "Audio output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/biscale.lua
@@ -1,0 +1,57 @@
+sptbl["biscale"] = {
+
+    files = {
+        module = "biscale.c",
+        header = "biscale.h",
+        example = "ex_biscale.c",
+    },
+
+    func = {
+        create = "sp_biscale_create",
+        destroy = "sp_biscale_destroy",
+        init = "sp_biscale_init",
+        compute = "sp_biscale_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "min",
+                type = "SPFLOAT",
+                description = "Minimum value to scale to.",
+                default = 0
+            },
+            {
+                name = "max",
+                type = "SPFLOAT",
+                description ="Maximum value to scale to.",
+                default = 1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Bipolar Scale
+
+    This module scales from bipolar [-1, 1] to another range defined by min and max.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in",
+            description = "Signal to be scaled."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Scaled signal out"
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/bitcrush.lua
@@ -1,0 +1,56 @@
+sptbl["bitcrush"] = {
+
+    files = {
+        module = "bitcrush.c",
+        header = "bitcrush.h",
+        example = "ex_bitcrush.c",
+    },
+
+    func = {
+        create = "sp_bitcrush_create",
+        destroy = "sp_bitcrush_destroy",
+        init = "sp_bitcrush_init",
+        compute = "sp_bitcrush_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "bitdepth",
+                type = "SPFLOAT",
+                description = "Bit depth. Expects an integer in the range of 1-16. Fractional values will be truncated.",
+                default = 8
+            },
+            {
+                name = "srate",
+                type = "SPFLOAT",
+                description ="Sampling rate.",
+                default = 10000
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Digital signal degradation
+
+    Bitcrusher will digitally degrade a signal by altering the bitdepth and sampling-rate. ]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output"
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/blsaw.lua
@@ -1,0 +1,57 @@
+sptbl["blsaw"] = {
+
+    files = {
+        module = "blsaw.c",
+        header = "blsaw.h",
+        example = "ex_blsaw.c",
+    },
+
+    func = {
+        create = "sp_blsaw_create",
+        destroy = "sp_blsaw_destroy",
+        init = "sp_blsaw_init",
+        compute = "sp_blsaw_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT*",
+                description = "Frequency, (range 0-20000)",
+                default = 440
+            },
+            {
+                name = "amp",
+                type = "SPFLOAT*",
+                description ="Amplitude (range 0-1).",
+		default = 1.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Bandlimited sawtooth oscillator
+This is a bandlimited sawtooth oscillator ported from the "sawtooth" function from the Faust
+programming language.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This doesn't do anything."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/blsquare.lua
@@ -1,0 +1,63 @@
+sptbl["blsquare"] = {
+
+    files = {
+        module = "blsquare.c",
+        header = "blsquare.h",
+        example = "ex_blsquare.c",
+    },
+
+    func = {
+        create = "sp_blsquare_create",
+        destroy = "sp_blsquare_destroy",
+        init = "sp_blsquare_init",
+        compute = "sp_blsquare_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT*",
+                description = "Frequency, (range 0-20000)",
+                default = 440
+            },
+            {
+                name = "amp",
+                type = "SPFLOAT*",
+                description ="Amplitude (range 0-1).",
+		default = 1.0
+            },
+            {
+                name = "width",
+                type = "SPFLOAT*",
+                description ="Duty cycle width (range 0-1).",
+		default = 0.5
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Bandlimited square oscillator
+This is a bandlimited square oscillator ported from the "squaretooth" function from the Faust
+programming language.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This doesn't do anything."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/bltriangle.lua
@@ -1,0 +1,57 @@
+sptbl["bltriangle"] = {
+
+    files = {
+        module = "bltriangle.c",
+        header = "bltriangle.h",
+        example = "ex_bltriangle.c",
+    },
+
+    func = {
+        create = "sp_bltriangle_create",
+        destroy = "sp_bltriangle_destroy",
+        init = "sp_bltriangle_init",
+        compute = "sp_bltriangle_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT*",
+                description = "Frequency, (range 0-20000)",
+                default = 440
+            },
+            {
+                name = "amp",
+                type = "SPFLOAT*",
+                description ="Amplitude (range 0-1).",
+		default = 1.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Bandlimited triangle oscillator
+This is a bandlimited triangle oscillator ported from the "triangletooth" function from the Faust
+programming language.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This doesn't do anything."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/brown.lua
@@ -1,0 +1,37 @@
+sptbl["brown"] = {
+
+    files = {
+        module = "brown.c",
+        header = "brown.h",
+        example = "ex_brown.c",
+    },
+
+    func = {
+        create = "sp_brown_create",
+        destroy = "sp_brown_destroy",
+        init = "sp_brown_init",
+        compute = "sp_brown_compute",
+    },
+
+    params = {
+    },
+
+    modtype = "module",
+
+    description = [[Brownian noise generator.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Brownian noise output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/butbp.lua
@@ -1,0 +1,54 @@
+sptbl["butbp"] = {
+
+    files = {
+        module = "butbp.c",
+        header = "butbp.h",
+        example = "ex_butbp.c",
+    },
+
+    func = {
+        create = "sp_butbp_create",
+        destroy = "sp_butbp_destroy",
+        init = "sp_butbp_init",
+        compute = "sp_butbp_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Center Frequency. (in Hertz)",
+                default = 1000
+            },
+            {
+                name = "bw",
+                type = "SPFLOAT",
+                description = "Bandwidth. (in Hertz)",
+                default = 10
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Bandpass Butterworth filter]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Input signal that the filter should be applied to."
+        },
+    },
+
+    outputs = {
+        {
+            name = "output",
+            description = "Output signal (input modified by the filter)."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/butbr.lua
@@ -1,0 +1,54 @@
+sptbl["butbr"] = {
+
+    files = {
+        module = "butbr.c",
+        header = "butbr.h",
+        example = "ex_butbr.c",
+    },
+
+    func = {
+        create = "sp_butbr_create",
+        destroy = "sp_butbr_destroy",
+        init = "sp_butbr_init",
+        compute = "sp_butbr_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Center Frequency. (in Hertz)",
+                default = 1000
+            },
+            {
+                name = "bw",
+                type = "SPFLOAT",
+                description = "Bandwidth. (in Hertz)",
+                default = 1000
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Band-reject Butterworth filter]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "output",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/buthp.lua
@@ -1,0 +1,48 @@
+sptbl["buthp"] = {
+
+    files = {
+        module = "buthp.c",
+        header = "buthp.h",
+        example = "ex_buthp.c",
+    },
+
+    func = {
+        create = "sp_buthp_create",
+        destroy = "sp_buthp_destroy",
+        init = "sp_buthp_init",
+        compute = "sp_buthp_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Cutoff Frequency.",
+                default = 1000
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Highpass Butterworth filter]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "output",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/butlp.lua
@@ -1,0 +1,48 @@
+sptbl["butlp"] = {
+
+    files = {
+        module = "butlp.c",
+        header = "butlp.h",
+        example = "ex_butlp.c",
+    },
+
+    func = {
+        create = "sp_butlp_create",
+        destroy = "sp_butlp_destroy",
+        init = "sp_butlp_init",
+        compute = "sp_butlp_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Cutoff Frequency.",
+                default = 1000
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Lowpass Butterworth filter]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "output",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/clamp.lua
@@ -1,0 +1,61 @@
+sptbl["clamp"] = {
+
+    files = {
+        module = "clamp.c",
+        header = "clamp.h",
+        example = "ex_clamp.c",
+    },
+
+    func = {
+        create = "sp_clamp_create",
+        destroy = "sp_clamp_destroy",
+        init = "sp_clamp_init",
+        compute = "sp_clamp_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "min",
+                type = "SPFLOAT",
+                description = "Minimum value.",
+                default = 0
+            },
+            {
+                name = "max",
+                type = "SPFLOAT",
+                description ="Maximum value.",
+                default = 1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Performs a clamp operation on an input signal.
+
+This module performs what is known as a "clamp" operation, which sets the
+bounds of a signal in between a minimum and a maximum value. Anything exceeding
+the bounds in either direction will be set to the closest valid value. In
+other words: if x is less than minimum, set x to the minimum;
+if x is greater than the maximum, set x to be the maximum.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Input audio signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Output audio signal."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/clock.lua
@@ -1,0 +1,56 @@
+sptbl["clock"] = {
+
+    files = {
+        module = "clock.c",
+        header = "clock.h",
+        example = "ex_clock.c",
+    },
+
+    func = {
+        create = "sp_clock_create",
+        destroy = "sp_clock_destroy",
+        init = "sp_clock_init",
+        compute = "sp_clock_compute",
+    },
+
+    params = {
+
+        optional = {
+            {
+                name = "bpm",
+                type = "SPFLOAT",
+                description = "Clock tempo, in beats per minute.",
+                default = 120
+            },
+            {
+                name = "subdiv",
+                type = "SPFLOAT",
+                description ="Clock subdivision. 2 = eighths, 4 = 16ths, etc.",
+                default = 1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Resettable clock with subdivisions
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When non-zero, will reset clock"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Clock output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/compressor.lua
@@ -1,0 +1,69 @@
+sptbl["compressor"] = {
+
+    files = {
+        module = "compressor.c",
+        header = "compressor.h",
+        example = "ex_compressor.c",
+    },
+
+    func = {
+        create = "sp_compressor_create",
+        destroy = "sp_compressor_destroy",
+        init = "sp_compressor_init",
+        compute = "sp_compressor_compute",
+    },
+
+    params = {
+        mandatory = {
+        },
+
+        optional = {
+            {
+                name = "ratio",
+                type = "SPFLOAT*",
+                description = "Ratio to compress with, a value > 1 will compress",
+                default = 1
+            },
+            {
+                name = "thresh",
+                type = "SPFLOAT*",
+                description ="Threshold (in dB) 0 = max",
+                default = 0
+            },
+            {
+                name = "atk",
+                type = "SPFLOAT*",
+                description ="Compressor attack",
+                default = 0.1
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT*",
+                description ="Compressor release",
+                default = 0.1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Compressor]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/count.lua
@@ -1,0 +1,57 @@
+sptbl["count"] = {
+
+    files = {
+        module = "count.c",
+        header = "count.h",
+        example = "ex_count.c",
+    },
+
+    func = {
+        create = "sp_count_create",
+        destroy = "sp_count_destroy",
+        init = "sp_count_init",
+        compute = "sp_count_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "count",
+                type = "SPFLOAT",
+                description = "Number to count up to (count - 1). Decimal points will be truncated.",
+                default = 4
+            },
+            {
+                name = "mode",
+                type = "SPFLOAT",
+                description = "Counting mode. 0 = wrap-around, 1 = count up to N -1, then stop and spit out -1",
+                default = 0
+            },
+        },
+    },
+
+    modtype = "module",
+
+    description = [[Trigger-based fixed counter
+
+    The signal output will count from 0 to [N-1], and then
+repeat itself. Count will start when it has been triggered, otherwise it will be -1.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When non-zero, this value will increment."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/crossfade.lua
@@ -1,0 +1,57 @@
+sptbl["crossfade"] = {
+
+    files = {
+        module = "crossfade.c",
+        header = "crossfade.h",
+        example = "ex_crossfade.c",
+    },
+
+    func = {
+        create = "sp_crossfade_create",
+        destroy = "sp_crossfade_destroy",
+        init = "sp_crossfade_init",
+        compute = "sp_crossfade_compute",
+    },
+
+    params = {
+        mandatory = {
+        },
+
+        optional = {
+            {
+                name = "pos",
+                type = "SPFLOAT",
+                description = "Crossfade position. 0 = all signal 1, 1 = all signal 2",
+                default = 0.5
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Crossfade two signals. 
+This module will perform a linear crossfade between two input signals.
+]],
+
+    ninputs = 2,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in1",
+            description = "Input signal 1."
+        },
+        {
+            name = "in2",
+            description = "Input signal 2."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/delay.lua
@@ -1,0 +1,58 @@
+sptbl["delay"] = {
+
+    files = {
+        module = "delay.c",
+        header = "delay.h",
+        example = "ex_delay.c",
+    },
+
+    func = {
+        create = "sp_delay_create",
+        destroy = "sp_delay_destroy",
+        init = "sp_delay_init",
+        compute = "sp_delay_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "time",
+                type = "SPFLOAT",
+                description = "Delay time, in seconds.",
+                default = 1.0
+            }
+        },
+
+        optional = {
+            {
+                name = "feedback",
+                type = "SPFLOAT",
+                description = "Feedback amount. Should be a value between 0-1.",
+                default = 0.0
+            }
+        }
+
+    },
+
+    modtype = "module",
+
+    description = [[Adds a delay to an incoming signal with optional feedback.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/diode.lua
@@ -1,0 +1,62 @@
+sptbl["diode"] = {
+
+    files = {
+        module = "diode.c",
+        header = "diode.h",
+        example = "ex_diode.c",
+    },
+
+    func = {
+        create = "sp_diode_create",
+        destroy = "sp_diode_destroy",
+        init = "sp_diode_init",
+        compute = "sp_diode_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "",
+                default = 1000
+            },
+            {
+                name = "res",
+                type = "SPFLOAT",
+                description ="",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Diode-ladder virtual analogue low-pass filter
+This is a diode-ladder filter designed by Will Pirkle. 
+More information can be found in this paper here: 
+http://www.willpirkle.com/Downloads/AN-6DiodeLadderFilter.pdf
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out_left",
+            description = "Stereo left output for diode."
+        },
+        {
+            name = "out_right",
+            description = "Stereo right output for diode."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/dmetro.lua
@@ -1,0 +1,54 @@
+sptbl["dmetro"] = {
+
+    files = {
+        module = "dmetro.c",
+        header = "dmetro.h",
+        example = "ex_dmetro.c",
+    },
+
+    func = {
+        create = "sp_dmetro_create",
+        destroy = "sp_dmetro_destroy",
+        init = "sp_dmetro_init",
+        compute = "sp_dmetro_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "time",
+                type = "SPFLOAT",
+                description ="Time between triggers (in seconds). This will update at the start of each trigger.",
+                default = 1.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Delta Metro
+
+    Produce a set of triggers spaced apart by time.
+
+An implementation note: while dmetro does indeed use sample
+precision, it will intentionally add 1 sample to the
+duration time as a way to avoid divide-by-zero errors. A
+dmetro of one second will really be one second and 1 sample.
+For most musical purposes, this is negligible. For more
+scientific purposes, this could cause problems, and it is
+recommended to find or build another module.]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Trigger output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/dtrig.lua
@@ -1,0 +1,71 @@
+sptbl["dtrig"] = {
+
+    files = {
+        module = "dtrig.c",
+        header = "dtrig.h",
+        example = "ex_dtrig.c",
+    },
+
+    func = {
+        create = "sp_dtrig_create",
+        destroy = "sp_dtrig_destroy",
+        init = "sp_dtrig_init",
+        compute = "sp_dtrig_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "ft",
+                type = "sp_ftbl *",
+                description = "An ftable containing times in seconds.",
+                default = "N/A"
+            }
+        },
+
+        optional = {
+            {
+                name = "loop",
+                type = "int",
+                description = "When set to 1, dtrig will wrap around and loop again.",
+                default = 0
+            },
+            {
+                name = "delay",
+                type = "SPFLOAT",
+                description = "This sets a delay (in seconds) on the triggered output when it is initially triggered. This is useful for rhythmic sequences with rests in the beginnings.",
+                default = 0
+            },
+            {
+                name = "scale",
+                type = "SPFLOAT",
+                description = "Scales the timing signal. A scale of 1 is normal, a scale of 2 will double the duration, and a scale of 0.5 will halve it.",
+                default = 0
+            }
+        }
+    },
+
+    modtype = "module",
+
+    description = [[ Delta trigger
+
+    This is able to create spaced out triggers. It is set off by a single trigger.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "trigger input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "These are the triggered outputs."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/expon.lua
@@ -1,0 +1,64 @@
+sptbl["expon"] = {
+
+    files = {
+        module = "expon.c",
+        header = "expon.h",
+        example = "ex_expon.c",
+    },
+
+    func = {
+        create = "sp_expon_create",
+        destroy = "sp_expon_destroy",
+        init = "sp_expon_init",
+        compute = "sp_expon_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "a",
+                type = "SPFLOAT",
+                description = "Inital point.",
+                default = 1.0
+            },
+            {
+                name = "dur",
+                type = "SPFLOAT",
+                description = "Duration (in seconds)",
+                default = 1.0
+            },
+            {
+                name = "b",
+                type = "SPFLOAT",
+                description = "End point",
+                default = 1.0
+            }
+        },
+
+    },
+
+    modtype = "module",
+
+    description = [[Produce a line segment with exponential slope
+This will generate a line from value A to value B in given amount of time. 
+When it reaches it's target, it will stay at that value. 
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When nonzero, will retrigger line segment"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/foo.lua
@@ -1,0 +1,103 @@
+sptbl["foo"] = {
+
+    files = {
+        module = "foo.c",
+        header = "foo.h",
+        example = "ex_foo.c",
+    },
+
+    func = {
+        create = "sp_foo_create",
+        destroy = "sp_foo_destroy",
+        init = "sp_foo_init",
+        compute = "sp_foo_compute",
+        other = {
+            sp_foo_set = {
+                description = "foo_set description goes here.",
+                args = {
+                    {
+                        name = "var1",
+                        type = "SPFLOAT",
+                        description = "This is the first parameter",
+                        default = 1.5
+                    },
+                    {
+                        name = "var2",
+                        type = "SPFLOAT",
+                        description = "This is the second parameter",
+                        default = 1.5
+                    }
+                }
+            }
+        }
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "bar",
+                type = "sp_ftbl *",
+                description = "This is a mandatory table value. It does not have a default value, so we set it to 'N/A'. Any that does not or cannot have a default value should set this default value to 'N/A'.",
+                default = "N/A"
+            },
+            {
+                name = "bar2",
+                type = "SPFLOAT",
+                description = "This is a mandatory parameter. In soundpipe, users will always need to specify this value, but a default value has been giving in case it is needed to write more complicated engines in the future.",
+                default = 123
+            }
+        },
+
+        optional = {
+            {
+                name = "blah_1",
+                type = "SPFLOAT",
+                description = "This is an optional parameter. These values are always set to a value by default, and can be set after the init function has been called.",
+                default = 1.5
+            },
+            {
+                name = "blah_2",
+                type = "SPFLOAT",
+                description ="This is yet another optional parameter...",
+                default = 456.7
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[A short title describing the module
+
+    This is a description of the entire module.  This is not a real module. This description should be a comprehensive sumary of what this function does.
+
+Inside the Lua table, this is expressed as a multiline string, however it does not adhere to the tradtional 80 column rule found in programming.
+
+Write as much text as needed here...
+]],
+
+    ninputs = 2,
+    noutputs = 2,
+
+    inputs = {
+        {
+            name = "clock",
+            description = "this is the clock source for a made up plugin."
+        },
+        {
+            name = "input",
+            description = "this is the audio input for a made up plugin."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out_left",
+            description = "Stereo left output for foo."
+        },
+        {
+            name = "out_right",
+            description = "Stereo right output for foo."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/gen_padsynth.lua
@@ -1,0 +1,46 @@
+sptbl["gen_padsynth"] = {
+
+    files = {
+        module = "ftbl.c",
+        header = "ftbl.h",
+        example = "extra/ex_padsynth.c",
+    },
+
+    func = {
+        name = "sp_gen_padsynth",
+    },
+
+    params = {
+        {
+            name = "amps",
+            type = "sp_ftbl *",
+            description = [[ftable of amplitudes to use]],
+            default = "N/A"
+        },
+        {
+            name = "f",
+            type = "SPFLOAT",
+            description = [[Base frequency.]],
+            default = 440.0
+        },
+        {
+            name = "bw",
+            type = "SPFLOAT",
+            description = [[Bandwidth.]],
+            default = 40.0
+        },
+    },
+
+    modtype = "gen",
+
+    description = [[An implementation of the Padsynth Algorithm by Paul Nasca. 
+
+This is a basic implemenation of the padsynth algorithm. More information can be found here:
+
+http://zynaddsubfx.sourceforge.net/doc/PADsynth/PADsynth.htm
+
+This gen routine requires libfftw, and is not compiled by default. See config.mk for more info.
+    
+    ]],
+
+}
--- /dev/null
+++ b/modules/data/gen_rand.lua
@@ -1,0 +1,26 @@
+sptbl["gen_rand"] = {
+
+    files = {
+        module = "ftbl.c",
+        header = "ftbl.h",
+        example = "ex_gen_rand.c",
+    },
+
+    func = {
+        name = "sp_gen_rand",
+    },
+
+    params = {
+        {
+            name = "argstring",
+            type = "char *",
+            description = [[A string of value pairs. The first value is the value, then the probability.]],
+            default = "1 0.5 2 0.5"
+        },
+    },
+
+    modtype = "gen",
+
+    description = [[Generates a user defined random number distribution.]],
+
+}
--- /dev/null
+++ b/modules/data/gen_scrambler.lua
@@ -1,0 +1,29 @@
+sptbl["gen_scrambler"] = {
+
+    files = {
+        module = "ftbl.c",
+        header = "ftbl.h",
+        example = "ex_scrambler.c",
+    },
+
+    func = {
+        name = "sp_gen_scrambler",
+    },
+    params = {
+        {
+            name = "dest",
+            type = "&sp_ftbl *",
+            description = [[destination ftable]],
+            default = 123456
+        },
+    },
+
+    modtype = "gen",
+
+    description = [[Scrambles phase of ftable.
+This gen routine will copy the ftable, apply an FFT, apply
+a random phase, and then do an inverse FFT. This effect 
+is ideal for creating pad-like sounds. 
+]],
+
+}
--- /dev/null
+++ b/modules/data/gen_sine.lua
@@ -1,0 +1,17 @@
+sptbl["gen_sine"] = {
+
+    files = {
+        module = "ftbl.c",
+        header = "ftbl.h",
+        example = "ex_gen_sine.c",
+    },
+
+    func = {
+        name = "sp_gen_sine",
+    },
+
+    modtype = "gen",
+
+    description = [[generates a sampled sinusoid]],
+
+}
--- /dev/null
+++ b/modules/data/gen_triangle.lua
@@ -1,0 +1,17 @@
+sptbl["gen_triangle"] = {
+
+    files = {
+        module = "ftbl.c",
+        header = "ftbl.h",
+        example = "ex_gen_triangle.c",
+    },
+
+    func = {
+        name = "sp_gen_triangle",
+    },
+
+    modtype = "gen",
+
+    description = [[generates a sampled triangle wave]],
+
+}
--- /dev/null
+++ b/modules/data/in.lua
@@ -1,0 +1,58 @@
+sptbl["in"] = {
+
+    files = {
+        module = "in.c",
+        header = "in.h",
+        example = "ex_in.c",
+    },
+
+    func = {
+        create = "sp_in_create",
+        destroy = "sp_in_destroy",
+        init = "sp_in_init",
+        compute = "sp_in_compute",
+    },
+
+    params = {
+    },
+
+    modtype = "module",
+
+    description = [[Reads from standard input.
+
+    Expects type of SPFLOAT, which by default is a float. If the input data is larger than the number of samples, you will get a complaint about a broken pipe (but it will still work). If there is no input data from STDIN, it will hang.
+
+
+
+
+The expected use case of sp_in is to utilize pipes from the commandline, like so:
+
+
+
+
+cat /dev/urandom | ./my_program
+
+
+
+
+Assuming my_program is using sp_in, this will write /dev/urandom (essentially white noise) to an audio file.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This doesn't do anything."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/incr.lua
@@ -1,0 +1,72 @@
+sptbl["incr"] = {
+
+    files = {
+        module = "incr.c",
+        header = "incr.h",
+        example = "ex_incr.c",
+    },
+
+    func = {
+        create = "sp_incr_create",
+        destroy = "sp_incr_destroy",
+        init = "sp_incr_init",
+        compute = "sp_incr_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "val",
+                type = "SPFLOAT",
+                description = "Initial value",
+                default = 0.5
+            },
+        },
+        optional = {
+            {
+                name = "step",
+                type = "SPFLOAT",
+                description = "Step value to increment by.",
+                default = 0.1
+            },
+            {
+                name = "min",
+                type = "SPFLOAT",
+                description = "Minimum value",
+                default = 0
+            },
+            {
+                name = "max",
+                type = "SPFLOAT",
+                description = "Maximum value",
+                default = 1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Trigger-based Incrementor
+When triggered, this module will increment and decrement a value bounded between a min
+and max. Initially, this was designed for the specific use case of interfacing with the
+griffin knob. 
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "Trigger signal. When positive, the value will increase. When negative, the value will decrease."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "incr output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/jcrev.lua
@@ -1,0 +1,48 @@
+sptbl["jcrev"] = {
+
+    files = {
+        module = "jcrev.c",
+        header = "jcrev.h",
+        example = "ex_jcrev.c",
+    },
+
+    func = {
+        create = "sp_jcrev_create",
+        destroy = "sp_jcrev_destroy",
+        init = "sp_jcrev_init",
+        compute = "sp_jcrev_compute",
+    },
+
+    params = {
+    },
+
+    modtype = "module",
+
+    description = [[John Chowning reverberator
+
+    This is was built using the JC reverb implentation found in FAUST. According to the source code, the specifications for
+this implementation were found on an old SAIL DART backup tape.
+
+  This class is derived from the CLM JCRev function, which is based on the use of
+  networks of simple allpass and comb delay filters.  This class implements three series
+  allpass units, followed by four parallel comb filters, and two decorrelation delay lines in
+  parallel at the output.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal Output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/line.lua
@@ -1,0 +1,64 @@
+sptbl["line"] = {
+
+    files = {
+        module = "line.c",
+        header = "line.h",
+        example = "ex_line.c",
+    },
+
+    func = {
+        create = "sp_line_create",
+        destroy = "sp_line_destroy",
+        init = "sp_line_init",
+        compute = "sp_line_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "a",
+                type = "SPFLOAT",
+                description = "Inital point.",
+                default = 0.0
+            },
+            {
+                name = "dur",
+                type = "SPFLOAT",
+                description = "Duration (in seconds)",
+                default = 0.5
+            },
+            {
+                name = "b",
+                type = "SPFLOAT",
+                description = "End point",
+                default = 1.0
+            }
+        },
+
+    },
+
+    modtype = "module",
+
+    description = [[Produce a line segment with linear slope
+This will generate a line from value A to value B in given amount of time. 
+When it reaches it's target, it will stay at that value. 
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When non-zero, will retrigger the line slope."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/lpc.lua
@@ -1,0 +1,82 @@
+sptbl["lpc"] = {
+
+    files = {
+        module = "lpc.c",
+        header = "lpc.h",
+        example = "ex_lpc.c",
+    },
+
+    func = {
+        create = "sp_lpc_create",
+        destroy = "sp_lpc_destroy",
+        init = "sp_lpc_init",
+        compute = "sp_lpc_compute",
+        other = {
+            sp_lpc_synth = {
+                description = [[Toggle synth mode. 
+                Instead of reading an input, manipulate the parameters in  
+                a scaled ftable.]],
+                args = { 
+                    {
+                        name = "ft",
+                        type = "sp_ftbl *",
+                        description = "ftable of size 7",
+                        default = "N/A"
+                    }
+                }
+            }
+        }
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "framesize",
+                type = "int",
+                description = "Sets the frame size for the encoder.",
+                default = 512
+            },
+        },
+
+        optional = {
+        }
+    },
+
+    modtype = "module",
+
+    description = [[A linear predictive coding filter.
+This module is a wrapper for the open source library openlpc, which implements
+the LPC10 audio codec optimized for speech signals. This module takes in an
+input signal, downsamples it, and produces a decoded LPC10 audio signal, which
+has a similar sound to that of a speak and spell. In this context, the LPC
+signal is meant to be more of a audio effect rather than a utility for
+communication. 
+
+Because the LPC10 encoder
+relies on frames for encoding, the output signal has a few milliseconds of
+delay. The delay can be calculated in seconds as (framesize * 4) / samplerate.
+
+In addition to using the LPC as a decoder/encoder, this module can also be 
+set to synth mode. Instead of reading from an input signal, the LPC can
+instead read from parameters set directly in a scaled ftable. 
+
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Input signal to be processed with LPC."
+        },
+    },
+
+    outputs = {
+        {
+            name = "output",
+            description = "LPC encoded signal."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/maygate.lua
@@ -1,0 +1,57 @@
+sptbl["maygate"] = {
+
+    files = {
+        module = "maygate.c",
+        header = "maygate.h",
+        example = "ex_maygate.c",
+    },
+
+    func = {
+        create = "sp_maygate_create",
+        destroy = "sp_maygate_destroy",
+        init = "sp_maygate_init",
+        compute = "sp_maygate_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "prob",
+                type = "SPFLOAT",
+                description = "Probability of maygate. This is a value between 0-1. The closer to 1, the more likely the maygate will let a signal through.",
+                default = 0
+            },
+
+            {
+                name = "mode",
+                type = "int",
+                description = "If mode is nonzero, maygate will output one sample triggers instead of a gate signal.",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[A randomly open or closed "maybe gate"
+
+    It takes in a trigger, and then it will randomly decide to turn the gate on or not. One particular application for maygate is to arbitrarily turn on/off sends to effects. One specific example of this could be a randomized reverb throw on a snare.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "This expects a trigger signal."
+        }
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal out."
+        }
+    }
+
+}
--- /dev/null
+++ b/modules/data/metro.lua
@@ -1,0 +1,50 @@
+sptbl["metro"] = {
+
+    files = {
+        module = "metro.c",
+        header = "metro.h",
+        --example = "ex_tone.c",
+    },
+
+    func = {
+        create = "sp_metro_create",
+        destroy = "sp_metro_destroy",
+        init = "sp_metro_init",
+        compute = "sp_metro_compute",
+    },
+
+    params = {
+        optional = {
+             {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "The frequency to repeat.",
+                default = 2.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Metronome
+
+    Metro produces a series of 1-sample ticks at a regular rate. Typically, this is used alongside trigger-driven modules.]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This input doesn't do anything"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal out."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/noise.lua
@@ -1,0 +1,48 @@
+sptbl["noise"] = {
+
+    files = {
+        module = "noise.c",
+        header = "noise.h",
+        example = "ex_noise.c",
+    },
+
+    func = {
+        create = "sp_noise_create",
+        destroy = "sp_noise_destroy",
+        init = "sp_noise_init",
+        compute = "sp_noise_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "amp",
+                type = "SPFLOAT",
+                description = "Amplitude. (Value between 0-1).",
+                default = 1.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[White noise generator]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This doesn't do anything"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/nsmp.lua
@@ -1,0 +1,100 @@
+sptbl["nsmp"] = {
+
+    files = {
+        module = "nsmp.c",
+        header = "nsmp.h",
+        example = "ex_nsmp.c",
+    },
+
+    func = {
+        create = "sp_nsmp_create",
+        destroy = "sp_nsmp_destroy",
+        init = "sp_nsmp_init",
+        compute = "sp_nsmp_compute",
+        other = {
+            sp_nsmp_print_index = {
+                description = "Prints the index and their corresponding keyword",
+                args = {
+                }
+            }
+        }
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "ft",
+                type = "sp_ftbl*",
+                description = "ftbl of the audio file. It should be mono.",
+                default = "N/A"
+            },
+            {
+                name = "sr",
+                type = "int",
+                description = "samplerate.",
+                default = "N/A"
+            },
+            {
+                name = "init",
+                type = "const char*",
+                description = "ini file.",
+                default = "N/A"
+            }
+        },
+
+        optional = {
+            {
+                name = "index",
+                type = "uint32_t",
+                description = "This is an optional parameter. These values are always set to a value by default, and can be set after the init function has been called.",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Nanosamp: a tiny sampler built for Soundpipe
+
+    A nanosamp file is comprised of a mono audio file and an ini file. Nanosamp is geared towards percussive and found sound sample players, and is intended to be combined with soundpipe modules.
+
+The ini file contains mappings that correspond to the audio file. Such an entry would look like this:
+
+
+
+[keyword]
+
+pos = 2.3
+
+size = 3
+
+
+</pre>
+In this instance, an entry called "keyword" has been made, starting at 2.3 seconds in the
+audio file, with a length of 3 seconds. An example file oneart.ini has been created in the
+examples folder.
+
+The SoundPipe implementation of nanosamp will automatically index the entries
+in the order they appear in the INI file and must be selected this way by changing the index
+parameter. Soundpipe will only select the new entry when the trigger input is a non-zero value.
+
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trigger",
+            description = "Trigger input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "signal out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/osc.lua
@@ -1,0 +1,68 @@
+sptbl["osc"] = {
+
+    files = {
+        module = "osc.c",
+        header = "osc.h",
+        example = "ex_osc.c",
+    },
+
+    func = {
+        create = "sp_osc_create",
+        destroy = "sp_osc_destroy",
+        init = "sp_osc_init",
+        compute = "sp_osc_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "tbl",
+                type = "sp_ftbl *",
+                description = "Wavetable to read from. Note: the size of this table must be a power of 2.",
+                default = "N/A"
+            },
+            {
+                name = "phase",
+                type = "SPFLOAT",
+                description ="Initial phase of waveform, expects a value 0-1",
+                default = 0
+            }
+        },
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Frequency (in Hz)",
+                default = 440
+            },
+            {
+                name = "amp",
+                type = "SPFLOAT",
+                description ="Amplitude (typically a value between 0 and 1).",
+                default = 0.2
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[ Table-lookup oscilator with linear interpolation]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This does nothing."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/oscmorph.lua
@@ -1,0 +1,84 @@
+sptbl["oscmorph"] = {
+
+    files = {
+        module = "oscmorph.c",
+        header = "oscmorph.h",
+        example = "ex_oscmorph.c",
+    },
+
+    func = {
+        create = "sp_oscmorph_create",
+        destroy = "sp_oscmorph_destroy",
+        init = "sp_oscmorph_init",
+        compute = "sp_oscmorph_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "tbl",
+                type = "sp_ftbl **",
+                description = "An array of ftables to read from. Note: the size of these tables must be a power of 2 (and the same size as well).",
+                default = "N/A"
+            },
+            {
+                name = "nft",
+                type = "int",
+                description ="Number of ftbls",
+                default = 2
+            },
+            {
+                name = "phase",
+                type = "SPFLOAT",
+                description ="Initial phase of waveform, expects a value 0-1",
+                default = 0
+            }
+        },
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Frequency (in Hz)",
+                default = 440
+            },
+            {
+                name = "amp",
+                type = "SPFLOAT",
+                description ="Amplitude (typically a value between 0 and 1).",
+                default = 0.2
+            },
+            {
+                name = "wtpos",
+                type = "SPFLOAT",
+                description ="Wavetable position. (scaled 0-1)",
+                default = 0.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Wavetable morphing oscillator
+
+This is an oscillator with linear interpolation that is capable of morphing 
+between an arbitrary number of wavetables. 
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in",
+            description = "This does nothing."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/paulstretch.lua
@@ -1,0 +1,66 @@
+sptbl["paulstretch"] = {
+
+    files = {
+        module = "paulstretch.c",
+        header = "paulstretch.h",
+        example = "ex_paulstretch.c",
+    },
+
+    func = {
+        create = "sp_paulstretch_create",
+        destroy = "sp_paulstretch_destroy",
+        init = "sp_paulstretch_init",
+        compute = "sp_paulstretch_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "ft",
+                type = "sp_ftbl *",
+                description = "ftable containing audio data",
+                default = "N/A"
+            },
+            {
+                name = "windowsize",
+                type = "SPFLOAT",
+                description = "Window size, in seconds.",
+                default = 10
+            },
+            {
+                name = "stretch",
+                type = "SPFLOAT",
+                description = "Stretch factor, 1.0 is no stretch.",
+                default = 10
+            },
+        },
+
+        optional = {
+        }
+    },
+
+    modtype = "module",
+
+    description = [[An extreme time-stretching algorithm by Paul Nasca Octavian
+This is an implementation of the popular paulstretch algorithm used for time
+stretching an audio signal to create ambient textures. Ideally, this algorithm 
+is best used for stretching signals by very very long amounts. 
+
+This version of paulstretch will take an ftable and loop through it, make
+it an ideal means for creating sustained pads. 
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/peaklim.lua
@@ -1,0 +1,63 @@
+sptbl["peaklim"] = {
+
+    files = {
+        module = "peaklim.c",
+        header = "peaklim.h",
+        example = "ex_peaklim.c",
+    },
+
+    func = {
+        create = "sp_peaklim_create",
+        destroy = "sp_peaklim_destroy",
+        init = "sp_peaklim_init",
+        compute = "sp_peaklim_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "atk",
+                type = "SPFLOAT",
+                description = "Attack time, in seconds",
+                default = 0.01
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT",
+                description ="Release time, in seconds",
+                default = 0.1
+            },
+            {
+                name = "thresh",
+                type = "SPFLOAT",
+                description ="Threshold, in dB",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Peak limiter 
+This is a simple peak limiting algorithm, based off code from the Stanford
+Music-424 class.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Input signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Output signal."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/phaser.lua
@@ -1,0 +1,114 @@
+sptbl["phaser"] = {
+
+    files = {
+        module = "phaser.c",
+        header = "phaser.h",
+        example = "ex_phaser.c",
+    },
+
+    func = {
+        create = "sp_phaser_create",
+        destroy = "sp_phaser_destroy",
+        init = "sp_phaser_init",
+        compute = "sp_phaser_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "MaxNotch1Freq",
+                type = "SPFLOAT*",
+                description = "Between 20 and 10000",
+                default = 800 
+            },
+            {
+                name = "MinNotch1Freq",
+                type = "SPFLOAT*",
+                description ="Between 20 and 5000",
+                default = 100
+            },
+            {
+                name = "Notch_width",
+                type = "SPFLOAT*",
+                description ="Between 10 and 5000",
+                default = 1000
+            },
+            {
+                name = "NotchFreq",
+                type = "SPFLOAT*",
+                description ="Between 1.1 and 4",
+                default = 1.5 
+            },
+            {
+                name = "VibratoMode",
+                type = "SPFLOAT*",
+                description ="1 or 0",
+                default = 1
+            },
+            {
+                name = "depth",
+                type = "SPFLOAT*",
+                description ="Between 0 and 1",
+                default = 1
+            },
+            {
+                name = "feedback_gain",
+                type = "SPFLOAT*",
+                description ="Between 0 and 1",
+                default = 0
+            },
+            {
+                name = "invert",
+                type = "SPFLOAT*",
+                description ="1 or 0",
+                default = 0
+            },
+            {
+                name = "level",
+                type = "SPFLOAT*",
+                description ="-60 to 10 dB",
+                default = 0
+            },
+            {
+                name = "lfobpm",
+                type = "SPFLOAT*",
+                description ="Between 24 and 360",
+                default = 30
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[A stereo phaser
+
+	This is a stereo phaser, generated from Faust code taken from the 
+Guitarix project.
+]],
+
+    ninputs = 2,
+    noutputs = 2,
+
+    inputs = {
+        {
+            name = "input1",
+            description = "Left audio input signal."
+        },
+        {
+            name = "input2",
+            description = "Right audio input signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out_left",
+            description = "Stereo left output for phaser."
+        },
+        {
+            name = "out_right",
+            description = "Stereo right output for phaser."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/phasor.lua
@@ -1,0 +1,59 @@
+sptbl["phasor"] = {
+
+    files = {
+        module = "phasor.c",
+        header = "phasor.h",
+        example = "ex_phasor.c",
+    },
+
+    func = {
+        create = "sp_phasor_create",
+        destroy = "sp_phasor_destroy",
+        init = "sp_phasor_init",
+        compute = "sp_phasor_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "iphs",
+                type = "SPFLOAT",
+                description = "initial phase",
+                default = 0
+            },
+        },
+
+        optional = {
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Frequency.",
+                default = 1.5
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Normalized sawtooth wave from 0 to 1
+
+    Phasors are often used when building table-lookup oscillators.]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "this doesn't do anything."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/pinknoise.lua
@@ -1,0 +1,48 @@
+sptbl["pinknoise"] = {
+
+    files = {
+        module = "pinknoise.c",
+        header = "pinknoise.h",
+        example = "ex_pinknoise.c",
+    },
+
+    func = {
+        create = "sp_pinknoise_create",
+        destroy = "sp_pinknoise_destroy",
+        init = "sp_pinknoise_init",
+        compute = "sp_pinknoise_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "amp",
+                type = "SPFLOAT",
+                description = "Amplitude. (Value between 0-1).",
+                default = 1.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Pink pinknoise generator]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This doesn't do anything"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/prop.lua
@@ -1,0 +1,80 @@
+sptbl["prop"] = {
+
+    files = {
+        module = "prop.c",
+        header = "prop.h",
+        example = "ex_prop.c",
+    },
+
+    func = {
+        create = "sp_prop_create",
+        destroy = "sp_prop_destroy",
+        init = "sp_prop_init",
+        compute = "sp_prop_compute",
+        other = {
+            sp_prop_reset = {
+                description = "Resets prop back to starting position.",
+                args = {
+                }
+            }
+        }
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "str",
+                type = "const char *",
+                description = "Prop string to be parsed.",
+                default = "N/A"
+            },
+        },
+
+        optional = {
+            {
+                name = "bpm",
+                type = "SPFLOAT",
+                description = "Beats per minute of the prop string.",
+                default = 60
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Simple rhythmic notation gate generator
+
+    Creates a gate using a simple rhythmic notation system called prop. When it reaches the end of the prop string, it will loop back to the beginning.
+
+Prop has a few basic rules:
+
+1. A '+' denotes a on. A '-' denotes an off (rest). They each have an equal duration of a quarter note.
+
+2. On and off values can be strung together to create equally spaced gates: +-+--
+
+3. When notes are enclosed in parantheses '()' following a positive integer N, their duration is reduced N times: ++2(+-)
+
+4. When notes are enclosed in brackets '[]' following a positive integer N, their duration is scaled by a factor of N: ++2[++]
+
+5. Parenthesis and brackets can be nested: +- 2[3(+2(++)+)]2(++)
+
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummy",
+            description = "This is doesn't do anything."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Gate output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/pshift.lua
@@ -1,0 +1,60 @@
+sptbl["pshift"] = {
+
+    files = {
+        module = "pshift.c",
+        header = "pshift.h",
+        example = "ex_pshift.c",
+    },
+
+    func = {
+        create = "sp_pshift_create",
+        destroy = "sp_pshift_destroy",
+        init = "sp_pshift_init",
+        compute = "sp_pshift_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "shift",
+                type = "SPFLOAT*",
+                description = "Pitch shift (in semitones), range -24/24.",
+                default = 0
+            },
+            {
+                name = "window",
+                type = "SPFLOAT*",
+                description ="Window size (in samples), max 10000",
+                default = 1000
+            },
+            {
+                name = "xfade",
+                type = "SPFLOAT*",
+                description ="Crossfade (in samples), max 10000",
+                default = 10
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Time-domain pitch shifter.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/randh.lua
@@ -1,0 +1,57 @@
+sptbl["randh"] = {
+
+    files = {
+        module = "randh.c",
+        header = "randh.h",
+        example = "ex_randh.c",
+    },
+
+    func = {
+        create = "sp_randh_create",
+        destroy = "sp_randh_destroy",
+        init = "sp_randh_init",
+        compute = "sp_randh_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "min",
+                type = "SPFLOAT",
+                description ="Minimum value to use.",
+                default = 0
+            },
+            {
+                name = "max",
+                type = "SPFLOAT",
+                description ="Maximum value to use.",
+                default = 1
+            },
+            {
+                name = "freq",
+                type = "SPFLOAT",
+                description = "Frequency of randomization (in Hz)",
+                default = 10
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Random number generator with hold time.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/random.lua
@@ -1,0 +1,54 @@
+sptbl["random"] = {
+
+    files = {
+        module = "random.c",
+        header = "random.h",
+        example = "ex_random.c",
+    },
+
+    func = {
+        create = "sp_random_create",
+        destroy = "sp_random_destroy",
+        init = "sp_random_init",
+        compute = "sp_random_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "min",
+                type = "SPFLOAT",
+                description = "Minimum value.",
+                default = -0.2
+            },
+            {
+                name = "max",
+                type = "SPFLOAT",
+                description ="Maximum value.",
+                default = 0.2
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Random values within a range]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "dummmy",
+            description = "This does nothing."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/reverse.lua
@@ -1,0 +1,50 @@
+sptbl["reverse"] = {
+
+	files = {
+	    module = "reverse.c",
+	    header = "reverse.h",
+	    example = "ex_reverse.c",
+	},
+
+	func = {
+	    create = "sp_reverse_create",
+	    destroy = "sp_reverse_destroy",
+	    init = "sp_reverse_init",
+	    compute = "sp_reverse_compute",
+	},
+
+	params = {
+	    mandatory = {
+	        {
+	            name = "delay",
+	            type = "SPFLOAT",
+	            description = "Delay time in seconds.",
+	            default = "1.0"
+	        }
+	    }
+	},
+
+	modtype = "module",
+
+	description = [[Signal reverser
+
+	Reverse will store a signal inside a buffer and play it back reversed.]],
+
+	ninputs = 1,
+	noutputs = 1,
+
+	inputs = {
+	    {
+	        name = "input",
+	        description = "Signal input."
+	    }
+	},
+
+	outputs = {
+	    {
+	        name = "out",
+	        description = "Signal output."
+	    }
+	}
+
+}
--- /dev/null
+++ b/modules/data/rpt.lua
@@ -1,0 +1,54 @@
+sptbl["rpt"] = {
+
+    files = {
+        module = "rpt.c",
+        header = "rpt.h",
+        example = "ex_rpt.c",
+    },
+
+    func = {
+        create = "sp_rpt_create",
+        destroy = "sp_rpt_destroy",
+        init = "sp_rpt_init",
+        compute = "sp_rpt_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "maxdur",
+                type = "SPFLOAT",
+                description = "Maximum delay duration in seconds. This will set the buffer size.",
+                default = "0.7"
+            }
+        },
+    },
+
+    modtype = "module",
+
+    description = [[Trigger based beat-repeat stuttering effect
+
+    When the input is a non-zero value, rpt will load up the buffer and loop a certain number of times. Speed and repeat amounts can be set with the sp_rpt_set function.]],
+
+    ninputs = 2,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When this value is non-zero, it will start the repeater."
+        },
+        {
+            name = "input",
+            description = "The signal to be repeated."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal out. This is passive unless explicity triggered in the input."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/samphold.lua
@@ -1,0 +1,44 @@
+sptbl["samphold"] = {
+
+    files = {
+        module = "samphold.c",
+        header = "samphold.h",
+        example = "ex_samphold.c",
+    },
+
+    func = {
+        create = "sp_samphold_create",
+        destroy = "sp_samphold_destroy",
+        init = "sp_samphold_init",
+        compute = "sp_samphold_compute",
+    },
+
+    params = {
+    },
+
+    modtype = "module",
+
+    description = [[Classic sample and hold]],
+
+    ninputs = 2,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "Will hold the current input value when non-zero."
+        },
+        {
+            name = "input",
+            description = "Audio input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        }
+    }
+
+}
--- /dev/null
+++ b/modules/data/saturator.lua
@@ -1,0 +1,54 @@
+sptbl["saturator"] = {
+
+    files = {
+        module = "saturator.c",
+        header = "saturator.h",
+        example = "ex_saturator.c",
+    },
+
+    func = {
+        create = "sp_saturator_create",
+        destroy = "sp_saturator_destroy",
+        init = "sp_saturator_init",
+        compute = "sp_saturator_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "drive",
+                type = "SPFLOAT",
+                description ="Input gain into the distortion section, in decibels. Controls overall amount of distortion.",
+                default = 1.0
+            },
+            {
+                name = "dcoffset",
+                type = "SPFLOAT",
+                description = "Constant linear offset applied to the signal. A small offset will introduce odd harmonics into the distoration spectrum, whereas a zero offset will have only even harmonics.",
+                default = 0.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Soft clip saturating distortion, based on examples from Abel/Berners' Music 424 course at Stanford.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in",
+            description = "input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/scale.lua
@@ -1,0 +1,57 @@
+sptbl["scale"] = {
+
+    files = {
+        module = "scale.c",
+        header = "scale.h",
+        example = "ex_scale.c",
+    },
+
+    func = {
+        create = "sp_scale_create",
+        destroy = "sp_scale_destroy",
+        init = "sp_scale_init",
+        compute = "sp_scale_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "min",
+                type = "SPFLOAT",
+                description = "Minimum value to scale to.",
+                default = 0
+            },
+            {
+                name = "max",
+                type = "SPFLOAT",
+                description ="Maximum value to scale to.",
+                default = 1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Bipolar Scale
+
+    This module scales from unipolar [0, 1] to another range defined by min and max.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in",
+            description = "Signal to be scaled."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Scaled signal out"
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/sdelay.lua
@@ -1,0 +1,50 @@
+sptbl["sdelay"] = {
+
+    files = {
+        module = "sdelay.c",
+        header = "sdelay.h",
+        example = "ex_sdelay.c",
+    },
+
+    func = {
+        create = "sp_sdelay_create",
+        destroy = "sp_sdelay_destroy",
+        init = "sp_sdelay_init",
+        compute = "sp_sdelay_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "size",
+                type = "SPFLOAT",
+                description = "Size of delay (in samples)",
+                default = "128"
+            },
+        }
+
+    },
+
+    modtype = "module",
+
+    description = [[Delays a signal by a number of samples.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Input signal to be delayed."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output for sdelay."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/slice.lua
@@ -1,0 +1,69 @@
+sptbl["slice"] = {
+
+    files = {
+        module = "slice.c",
+        header = "slice.h",
+        example = "ex_slice.c",
+    },
+
+    func = {
+        create = "sp_slice_create",
+        destroy = "sp_slice_destroy",
+        init = "sp_slice_init",
+        compute = "sp_slice_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "vals",
+                type = "sp_ftbl *",
+                description = "A table containing slice points, in samples",
+                default = "N/A"
+            },
+            {
+                name = "buf",
+                type = "sp_ftbl *",
+                description = "The buffer containing the audio samples.",
+                default = "N/A"
+            }
+        },
+
+        optional = {
+            {
+                name = "id",
+                type = "SPFLOAT",
+                description = "Value position.",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Yet another slice-based sample player.
+This module takes in an audio buffer and a table with slice points. 
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When non-zero, (re)triggers samples"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+        {
+            name = "out_right",
+            description = "Stereo right output for slice."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/smoothdelay.lua
@@ -1,0 +1,74 @@
+sptbl["smoothdelay"] = {
+
+    files = {
+        module = "smoothdelay.c",
+        header = "smoothdelay.h",
+        example = "ex_smoothdelay.c",
+    },
+
+    func = {
+        create = "sp_smoothdelay_create",
+        destroy = "sp_smoothdelay_destroy",
+        init = "sp_smoothdelay_init",
+        compute = "sp_smoothdelay_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "maxdel",
+                type = "SPFLOAT",
+                description = "Maximum delay time (in seconds)",
+                default = 1.0
+            },
+            {
+                name = "interp",
+                type = "uint32_t",
+                description = "interpolation time (in samples)",
+                default = 1024
+            }
+        },
+
+        optional = {
+            {
+                name = "feedback",
+                type = "SPFLOAT",
+                description ="",
+                default = 0.1
+            },
+            {
+                name = "del",
+                type = "SPFLOAT",
+                description = "",
+                default = 0.5
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Smooth variable delay line without varispeed pitch.
+Smooth delay is based off the sdelay module in Faust. The smooth delay 
+algorithm involves a double delay line. Any time the delay time changes, 
+the delay time of buffer not heard changes, then is crossfaded to 
+that buffer.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/smoother.lua
@@ -1,0 +1,65 @@
+sptbl["smoother"] = {
+
+    files = {
+        module = "smoother.c",
+        header = "smoother.h",
+        example = "ex_smoother.c",
+    },
+
+    func = {
+        create = "sp_smoother_create",
+        destroy = "sp_smoother_destroy",
+        init = "sp_smoother_init",
+        compute = "sp_smoother_compute",
+        other = {
+            sp_smoother_reset = {
+                description = "Resets internal buffers, snapping to input value instead of ramping to it.",
+                args = {
+                    {
+                        name = "input",
+                        type = "SPFLOAT *",
+                        description = "input value to snap to.",
+                        default = 0.0
+                    },
+                }
+            }
+        }
+    },
+
+    params = {
+        mandatory = {
+        },
+        optional = {
+            {
+                name = "smooth",
+                type = "SPFLOAT",
+                description = "Smooth time amount.",
+                default = 0.01
+            },
+        },
+    },
+
+    modtype = "module",
+
+    description = [[ Smootheramento-style control signal smoothing
+
+    Useful for smoothing out low-resolution signals and applying glissando to filters.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in",
+            description = "Signal input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/spa.lua
@@ -1,0 +1,49 @@
+sptbl["spa"] = {
+
+    files = {
+        module = "spa.c",
+        header = "spa.h",
+        example = "ex_spa.c",
+    },
+
+    func = {
+        create = "sp_spa_create",
+        destroy = "sp_spa_destroy",
+        init = "sp_spa_init",
+        compute = "sp_spa_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "filename",
+                type = "const char *",
+                description = "Filename of SPA file",
+                default = "N/A"
+            },
+        },
+
+    },
+
+    modtype = "module",
+
+    description = [[Stream a Soundpipe Audio File
+Similar to sp_diskin, sp_spa will stream a file in the internal soundpipe
+audio format. Such a format is useful for instances where you need to read
+audio files, but can't use libsndfile. 
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Output to spa."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/sparec.lua
@@ -1,0 +1,56 @@
+sptbl["sparec"] = {
+
+    files = {
+        module = "sparec.c",
+        header = "sparec.h",
+        example = "ex_sparec.c",
+    },
+
+    func = {
+        create = "sp_sparec_create",
+        destroy = "sp_sparec_destroy",
+        init = "sp_sparec_init",
+        compute = "sp_sparec_compute",
+        other = {
+            sp_sparec_close = {
+                description = "Close spa file and writes the rest of the data in the buffer.",
+                args = {
+                }
+            }
+        }
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "filename",
+                type = "const char *",
+                description = "Filename to write to",
+                default = "N/A"
+            },
+        },
+
+    },
+
+    modtype = "module",
+
+    description = [[Writes signal to spa file.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Input signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Copy of input signal."
+        }
+    }
+
+}
--- /dev/null
+++ b/modules/data/switch.lua
@@ -1,0 +1,50 @@
+sptbl["switch"] = {
+
+    files = {
+        module = "switch.c",
+        header = "switch.h",
+        example = "ex_switch.c",
+    },
+
+    func = {
+        create = "sp_switch_create",
+        destroy = "sp_switch_destroy",
+        init = "sp_switch_init",
+        compute = "sp_switch_compute",
+    },
+
+    params = {
+    },
+
+    modtype = "module",
+
+    description = [[Switch between two signals
+
+    By default, the incoming first signal is selected. When triggered, the output signal will switch to the other signal.]],
+
+    ninputs = 3,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When non-zero, will switch to the other signal."
+        },
+        {
+            name = "input_1",
+            description = "Signal input 1. This is the default signal."
+        },
+        {
+            name = "input_2",
+            description = "Signal input 2."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tadsr.lua
@@ -1,0 +1,66 @@
+sptbl["tadsr"] = {
+
+    files = {
+        module = "tadsr.c",
+        header = "tadsr.h",
+        example = "ex_tadsr.c",
+    },
+
+    func = {
+        create = "sp_tadsr_create",
+        destroy = "sp_tadsr_destroy",
+        init = "sp_tadsr_init",
+        compute = "sp_tadsr_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "atk",
+                type = "SPFLOAT",
+                description = "Attack time",
+                default = 0.1
+            },
+            {
+                name = "dec",
+                type = "SPFLOAT",
+                description ="Decay time",
+                default = 0.1
+            },
+            {
+                name = "sus",
+                type = "SPFLOAT",
+                description ="Sustain Level",
+                default = 0.5
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT",
+                description ="release",
+                default = 0.5
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Triggerable classic ADSR envelope]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "Expects trigger signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Envelope signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/talkbox.lua
@@ -1,0 +1,59 @@
+sptbl["talkbox"] = {
+
+    files = {
+        module = "talkbox.c",
+        header = "talkbox.h",
+        example = "ex_talkbox.c",
+    },
+
+    func = {
+        create = "sp_talkbox_create",
+        destroy = "sp_talkbox_destroy",
+        init = "sp_talkbox_init",
+        compute = "sp_talkbox_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "quality",
+                type = "SPFLOAT",
+                description = "Quality of the talkbox sound. 0=lowest fidelity. 1=highest fidelity",
+                default = 1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[A high talkbox emulation, simular to a vocoder.
+This is the talkbox plugin ported from the MDA plugin suite. In many ways,
+this Talkbox functions like a vocoder: it takes in a source signal (usually
+speech), which then excites an excitation signal 
+(usually a harmonically rich signal like a saw wave). This particular algorithm
+uses linear-predictive coding (LPC), making speech intelligibility better 
+than most vocoder implementations.
+]],
+
+    ninputs = 2,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "source",
+            description = "Input signal that shapes the excitation. Also known as the modulator."
+        },
+        {
+            name = "excitation",
+            description = "The signal to be excited. Also known as the carrier."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Talkbox signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tblrec.lua
@@ -1,0 +1,56 @@
+sptbl["tblrec"] = {
+
+    files = {
+        module = "tblrec.c",
+        header = "tblrec.h",
+        example = "ex_tblrec.c",
+    },
+
+    func = {
+        create = "sp_tblrec_create",
+        destroy = "sp_tblrec_destroy",
+        init = "sp_tblrec_init",
+        compute = "sp_tblrec_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "bar",
+                type = "sp_ftbl *",
+                description = "",
+                default = "N/A"
+            },
+        },
+    },
+
+    modtype = "module",
+
+    description = [[Record a signal to an ftable.
+This module will write audio-rate signals to a preallocated soundpipe ftable. 
+Every time record is enabled, it will got back to index 0 overwrite any
+previous information that was on it. 
+]],
+
+    ninputs = 2,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "in",
+            description = "Input signal."
+        },
+        {
+            name = "trig",
+            description = "When non-zero, will toggle recording on/off. Recording will set the playhead back to zero"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Copy of the input signal."
+        }
+    }
+
+}
--- /dev/null
+++ b/modules/data/tdiv.lua
@@ -1,0 +1,64 @@
+sptbl["tdiv"] = {
+
+    files = {
+        module = "tdiv.c",
+        header = "tdiv.h",
+        example = "ex_tdiv.c",
+    },
+
+    func = {
+        create = "sp_tdiv_create",
+        compute = "sp_tdiv_compute",
+        destroy = "sp_tdiv_destroy",
+        init = "sp_tdiv_init",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "num",
+                type = "SPFLOAT",
+                description = "Triggers every N times.",
+                default = 2
+            },
+            {
+                name = "offset",
+                type = "SPFLOAT",
+                description = "Offset amoutn.",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Trigger divider.
+This module will take in a trigger signal, and output a trigger signal
+every N times.
+
+For instance, when N = 3:
+
+in: * * * * * * * * *
+
+out *     *     *   
+
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trigger",
+            description = "Trigger. Should be a non-zero value"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tenv.lua
@@ -1,0 +1,60 @@
+sptbl["tenv"] = {
+
+    files = {
+        module = "tenv.c",
+        header = "tenv.h",
+        example = "ex_tenv.c",
+    },
+
+    func = {
+        create = "sp_tenv_create",
+        destroy = "sp_tenv_destroy",
+        init = "sp_tenv_init",
+        compute = "sp_tenv_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "atk",
+                type = "SPFLOAT",
+                description = "Attack time, in seconds.",
+                default = 0.1
+            },
+            {
+                name = "hold",
+                type = "SPFLOAT",
+                description = "Hold time, in seconds.",
+                default = 0.3
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT",
+                description = "Release time, in seconds.",
+                default = 0.2
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Trigger based linear AHD envelope generator]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "Trigger input. When non-zero, the envelope will (re)trigger."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output"
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tenv2.lua
@@ -1,0 +1,58 @@
+sptbl["tenv2"] = {
+
+    files = {
+        module = "tenv2.c",
+        header = "tenv2.h",
+        example = "ex_tenv2.c",
+    },
+
+    func = {
+        create = "sp_tenv2_create",
+        destroy = "sp_tenv2_destroy",
+        init = "sp_tenv2_init",
+        compute = "sp_tenv2_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "atk",
+                type = "SPFLOAT",
+                description = "Attack time (in seconds).",
+                default = 0.1
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT",
+                description ="Release time (in seconds).",
+                default = 0.1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Linear 2-stage Attack/Release envelope generator
+
+    This envelope takes 2 triggers. When triggered once,
+the envelope will rise to 1 according to the attack time. When triggered again, it will decay to 0 according to
+the decay time.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "Expects a trigger signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal out (a unipolar envelope)."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tenvx.lua
@@ -1,0 +1,65 @@
+sptbl["tenvx"] = {
+
+    files = {
+        module = "tenvx.c",
+        header = "tenvx.h",
+        example = "ex_tenvx.c",
+    },
+
+    func = {
+        create = "sp_tenvx_create",
+        destroy = "sp_tenvx_destroy",
+        init = "sp_tenvx_init",
+        compute = "sp_tenvx_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "atk",
+                type = "SPFLOAT",
+                description = "Tau attack time, in seconds. Must be non-zero.",
+                default = 0.1
+            },
+            {
+                name = "hold",
+                type = "SPFLOAT",
+                description = "Hold time, in seconds. The duration of the gate signal.",
+                default = 0.3
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT",
+                description = "Tau release time, in seconds. Must be non-zero.",
+                default = 0.2
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Trigger based exponential AHD envelope generator.
+    This envelope generator emulates the exponential behavior of analogue 
+envelope generators by passing a gate signal (whose duration is specified via
+the hold parameter) through a one-pole filter, whose filter coefficeints are
+calculated in terms of tau.  
+    ]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "Trigger input. When non-zero, the envelope will (re)trigger."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output"
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tgate.lua
@@ -1,0 +1,49 @@
+sptbl["tgate"] = {
+
+    files = {
+        module = "tgate.c",
+        header = "tgate.h",
+        example = "ex_tgate.c",
+    },
+
+    func = {
+        create = "sp_tgate_create",
+        destroy = "sp_tgate_destroy",
+        init = "sp_tgate_init",
+        compute = "sp_tgate_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "time",
+                type = "SPFLOAT",
+                description = "Duration of the gate (in seconds)",
+                default = 0.5
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[A triggerable gate.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trigger",
+            description = "When non-zero, will (re)trigger gate."
+        },
+    },
+
+    outputs = {
+        {
+            name = "gate",
+            description = "Gate output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/thresh.lua
@@ -1,0 +1,55 @@
+sptbl["thresh"] = {
+
+    files = {
+        module = "thresh.c",
+        header = "thresh.h",
+        example = "ex_thresh.c",
+    },
+
+    func = {
+        create = "sp_thresh_create",
+        destroy = "sp_thresh_destroy",
+        init = "sp_thresh_init",
+        compute = "sp_thresh_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "thresh",
+                type = "SPFLOAT",
+                description = "Threshold level",
+                default = 1.5
+            },
+            {
+                name = "mode",
+                type = "int",
+                description ="Sets when to detect theshold crossings. 0 = from below. 1 = from above. 2 = from above/below",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Trigger generator for signals that cross a given threshold. 
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Input signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "trig",
+            description = "Produces a trigger when the input signal crosses the set threshold."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/timer.lua
@@ -1,0 +1,44 @@
+sptbl["timer"] = {
+
+    files = {
+        module = "timer.c",
+        header = "timer.h",
+        example = "ex_timer.c",
+    },
+
+    func = {
+        create = "sp_timer_create",
+        destroy = "sp_timer_destroy",
+        init = "sp_timer_init",
+        compute = "sp_timer_compute",
+    },
+
+    params = {
+    },
+
+    modtype = "module",
+
+    description = [[Tap-tempo like timer
+
+When triggered, timer will begin an internal stopwatch until it is triggered again.
+The output of the timer will be the time elapsed in seconds.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "clock",
+            description = "When non-zero, will start/stop the timer."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Outputs the time of the last timer (in seconds)."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tin.lua
@@ -1,0 +1,40 @@
+sptbl["tin"] = {
+
+    files = { 
+        module = "tin.c",
+        header = "tin.h",
+        example = "ex_tin.c",
+    },
+    
+    func = {
+        create = "sp_tin_create",
+        destroy = "sp_tin_destroy",
+        init = "sp_tin_init",
+        compute = "sp_tin_compute",
+    },
+    
+    params = {
+    },
+    
+    modtype = "module",
+    
+    description = [[Similar to in, tin reads SPFLOATs (by default, this is a 4 byte binary float) from standard input every time it is triggered. behaves like a sample and hold, retaining the previous value (initial set to 0) until triggered. ]], 
+    
+    ninputs = 1,
+    noutputs = 1,
+    
+    inputs = { 
+        {
+            name = "trig",
+            description = "When non-zero, reads a single SPFLOAT from standard input."
+        },
+    },
+    
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/trand.lua
@@ -1,0 +1,55 @@
+sptbl["trand"] = {
+
+    files = {
+        module = "trand.c",
+        header = "trand.h",
+        example = "ex_trand.c",
+    },
+
+    func = {
+        create = "sp_trand_create",
+        destroy = "sp_trand_destroy",
+        init = "sp_trand_init",
+        compute = "sp_trand_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "min",
+                type = "SPFLOAT",
+                description ="Minimum value to use.",
+                default = 0
+            },
+            {
+                name = "max",
+                type = "SPFLOAT",
+                description ="Maximum value to use.",
+                default = 1
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Triggered random number generator.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "When non-zero, will create a new random value."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tseg.lua
@@ -1,0 +1,70 @@
+sptbl["tseg"] = {
+
+    files = {
+        module = "tseg.c",
+        header = "tseg.h",
+        example = "ex_tseg.c",
+    },
+
+    func = {
+        create = "sp_tseg_create",
+        destroy = "sp_tseg_destroy",
+        init = "sp_tseg_init",
+        compute = "sp_tseg_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "ibeg",
+                type = "SPFLOAT",
+                description = "Beginning value.",
+                default = 0.001; 
+            },
+        },
+
+        optional = {
+            {
+                name = "end",
+                type = "SPFLOAT",
+                description = "End parameter to go to.",
+                default = 1.0
+            },
+            {
+                name = "dur",
+                type = "SPFLOAT",
+                description = "duration to rise to (in seconds).",
+                default = 1.0
+            },
+            {
+                name = "type",
+                type = "SPFLOAT",
+                description ="The type of line, which determines slope of line",
+                default = -1.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[This module creates a series of line segments. 
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "trigger."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "tseg output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/tseq.lua
@@ -1,0 +1,59 @@
+sptbl["tseq"] = {
+
+    files = {
+        module = "tseq.c",
+        header = "tseq.h",
+        example = "ex_tseq.c",
+    },
+
+    func = {
+        create = "sp_tseq_create",
+        destroy = "sp_tseq_destroy",
+        init = "sp_tseq_init",
+        compute = "sp_tseq_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "ft",
+                type = "sp_ftbl *",
+                description = "An ftable of values",
+                default = "N/A"
+            },
+        },
+
+        optional = {
+            {
+                name = "shuf",
+                type = "int",
+                description = "When shuf is non-zero, randomly pick a value rather than cycle through sequentially.",
+                default = 0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[Function table looper
+
+    TSeq runs through values in an ftable. It will change values when the trigger input is a non-zero value, and wrap around when it reaches the end.]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "trig",
+            description = "Trigger."
+        },
+    },
+
+    outputs = {
+        {
+            name = "val",
+            description = "Value from current position in the ftable."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/voc.lua
@@ -1,0 +1,53 @@
+sptbl["voc"] = {
+
+    files = {
+        module = "voc.c",
+        header = "voc.h",
+        example = "ex_voc.c",
+    },
+
+    func = {
+        create = "sp_voc_create",
+        destroy = "sp_voc_destroy",
+        init = "sp_voc_init",
+        compute = "sp_voc_compute",
+    },
+
+    params = {
+    },
+
+    modtype = "module",
+
+    description = [[A vocal tract physical model.
+
+Based on the Pink Trombone algorithm by Neil Thapen, Voc implements a physical 
+model of the vocal tract glottal pulse wave. The tract model is based on the 
+classic Kelly-Lochbaum
+segmented cylindrical 1d waveguide model, and the glottal pulse wave is a
+LF glottal pulse model. 
+
+The soundpipe source code for Voc is generated via ctangle, one half of the
+literate documentation system known CWEB. The CWEB are maintained in a 
+separate repository. They are hosted on github here: 
+http://www.github.com/paulbatchelor/voc
+
+This documentation is a stub. For a full overview on proper usage, consult
+the "Top-level functions" section of the documented code, a copy of which
+can be found at the Voc project page pbat.ch/proj/voc, or generate the PDF
+from the github page described above.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Voc output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/vocoder.lua
@@ -1,0 +1,68 @@
+sptbl["vocoder"] = {
+
+    files = {
+        module = "vocoder.c",
+        header = "vocoder.h",
+        example = "ex_vocoder.c",
+    },
+
+    func = {
+        create = "sp_vocoder_create",
+        destroy = "sp_vocoder_destroy",
+        init = "sp_vocoder_init",
+        compute = "sp_vocoder_compute",
+    },
+
+    params = {
+        mandatory = {
+        },
+
+        optional = {
+            {
+                name = "atk",
+                type = "SPFLOAT*",
+                description = "Attack time . (Range 0.001 and 0.5 seconds)",
+                default = 0.1
+            },
+            {
+                name = "rel",
+                type = "SPFLOAT*",
+                description = "Release time",
+                default = 0.1
+            },
+            {
+                name = "bwratio",
+                type = "SPFLOAT*",
+                description = "Coeffecient to adjust the bandwidth of each band (0.1 - 2)",
+                default = 0.5
+            },
+            
+        }
+    },
+
+    modtype = "module",
+
+    description = [[16-band channel vocoder]],
+
+    ninputs = 2,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "source",
+            description = "Source signal (also known as carrier)."
+        },
+        {
+            name = "excite",
+            description = "Excitation signal (also known as modulator)"
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/wavin.lua
@@ -1,0 +1,73 @@
+sptbl["wavin"] = {
+
+    files = {
+        module = "wavin.c",
+        header = "wavin.h",
+        example = "ex_wavin.c",
+    },
+
+    func = {
+        create = "sp_wavin_create",
+        destroy = "sp_wavin_destroy",
+        init = "sp_wavin_init",
+        compute = "sp_wavin_compute",
+        other = {
+            sp_wavin_seek = {
+                description = "Seeks to position in file.",
+                args = {
+                    {
+                        name = "sample",
+                        type = "unsigned long",
+                        description = "Sample position",
+                        default = 0
+                    }
+                }
+            },
+            sp_wavin_get_sample = {
+                description = "Get a particular sample from the file.",
+                args = {
+                    {
+                        name = "pos",
+                        type = "SPFLOAT",
+                        description = "Sample position",
+                        default = 0
+                    }
+                }
+            }
+        }
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "filename",
+                type = "const char *",
+                description = "Filename",
+                default = "N/A"
+            },
+        },
+
+    },
+
+    modtype = "module",
+
+    description = [[Reads a mono WAV file.
+
+This module reads a mono WAV file from disk. It uses the public-domain 
+dr_wav library for decoding, so it can be a good substitute for libsndfile.
+]],
+
+    ninputs = 0,
+    noutputs = 1,
+
+    inputs = {
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "output signal."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/wavout.lua
@@ -1,0 +1,52 @@
+sptbl["wavout"] = {
+
+    files = {
+        module = "wavout.c",
+        header = "wavout.h",
+        example = "ex_wavout.c",
+    },
+
+    func = {
+        create = "sp_wavout_create",
+        destroy = "sp_wavout_destroy",
+        init = "sp_wavout_init",
+        compute = "sp_wavout_compute",
+    },
+
+    params = {
+        mandatory = {
+            {
+                name = "filename",
+                type = "const char*",
+                description = "The filename of the output file.",
+                default = "N/A"
+            }
+        },
+    },
+
+    modtype = "module",
+
+    description = [[Writes a mono signal to a WAV file.
+This module uses the public-domain dr_wav library to write WAV files
+to disk. This module is ideal for instances where GPL-licensed libsndfile 
+cannot be used for legal reasons.
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Mono input signal."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "A passthrough signal: a copy of the input signal."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/wpkorg35.lua
@@ -1,0 +1,65 @@
+sptbl["wpkorg35"] = {
+
+    files = {
+        module = "wpkorg35.c",
+        header = "wpkorg35.h",
+        example = "ex_wpkorg35.c",
+    },
+
+    func = {
+        create = "sp_wpkorg35_create",
+        destroy = "sp_wpkorg35_destroy",
+        init = "sp_wpkorg35_init",
+        compute = "sp_wpkorg35_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "cutoff",
+                type = "SPFLOAT",
+                description = "Filter cutoff",
+                default = 1000
+            },
+            {
+                name = "res",
+                type = "SPFLOAT",
+                description ="Filter resonance (should be between 0-2)",
+                default = 1.0
+            },
+            {
+                name = "saturation",
+                type = "SPFLOAT",
+                description ="Filter saturation.",
+                default = 0.0
+            },
+        }
+    },
+
+    modtype = "module",
+
+    description = [[ Analogue model of the Korg 35 Lowpass Filter
+
+Original port done by Will Pirkle:
+http://www.willpirkle.com/Downloads/AN-5Korg35_V3.pdf
+
+]],
+
+    ninputs = 1,
+    noutputs = 1,
+
+    inputs = {
+        {
+            name = "input",
+            description = "Audio input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/data/zitarev.lua
@@ -1,0 +1,139 @@
+sptbl["zitarev"] = {
+
+    files = {
+        module = "zitarev.c",
+        header = "zitarev.h",
+        example = "ex_zitarev.c",
+    },
+
+    func = {
+        create = "sp_zitarev_create",
+        destroy = "sp_zitarev_destroy",
+        init = "sp_zitarev_init",
+        compute = "sp_zitarev_compute",
+    },
+
+    params = {
+        optional = {
+            {
+                name = "in_delay",
+                type = "SPFLOAT*",
+                description = "Delay in ms before reverberation begins.",
+                default = 60,
+                min = 10,
+                max = 100 
+                
+            },
+            {
+                name = "lf_x",
+                type = "SPFLOAT*",
+                description ="Crossover frequency separating low and middle frequencies (Hz).",
+                default = 200,
+                min = 200,
+                max = 1000
+            },
+            {
+                name = "rt60_low",
+                type = "SPFLOAT*",
+                description ="Time (in seconds) to decay 60db in low-frequency band.",
+                default = 3.0,
+                min = 1,
+                max = 8 
+            },
+            {
+                name = "rt60_mid",
+                type = "SPFLOAT*",
+                description ="Time (in seconds) to decay 60db in mid-frequency band.",
+                default = 2.0,
+                min = 1,
+                max = 8
+            },
+            {
+                name = "hf_damping",
+                type = "SPFLOAT*",
+                description ="Frequency (Hz) at which the high-frequency T60 is half the middle-band's T60.",
+                default = 6000.0,
+                min = 1500,
+                max = 0.5 * 48000
+            },
+            {
+                name = "eq1_freq",
+                type = "SPFLOAT*",
+                description ="Center frequency of second-order Regalia Mitra peaking equalizer section 1.",
+                default = 315.0,
+                min = 40,
+                max = 2500
+            },
+            {
+                name = "eq1_level",
+                type = "SPFLOAT*",
+                description ="Peak level in dB of second-order Regalia-Mitra peaking equalizer section 1",
+                default = 0,
+                min = -15,
+                max = 15
+            },
+            {
+                name = "eq2_freq",
+                type = "SPFLOAT*",
+                description ="Center frequency of second-order Regalia Mitra peaking equalizer section 2.",
+                default = 1500.0,
+                min = 160,
+                max = 10000
+            },
+            {
+                name = "eq2_level",
+                type = "SPFLOAT*",
+                description ="Peak level in dB of second-order Regalia-Mitra peaking equalizer section 2",
+                default = 0 ,
+                min = -15,
+                max = 15
+            },
+            {
+                name = "mix",
+                type = "SPFLOAT*",
+                description ="0 = all dry, 1 = all wet",
+                default = 1,
+                min = 0,
+                max = 1
+            },
+            {
+                name = "level",
+                type = "SPFLOAT*",
+                description ="Output scale factor (in dB).",
+                default = -20,
+                min = -70,
+                max = 40
+            }
+        }
+    },
+
+    modtype = "module",
+
+    description = [[8 FDN stereo zitareverb algorithm, imported from Faust.]],
+
+    ninputs = 2,
+    noutputs = 2,
+
+    inputs = {
+        {
+            name = "input_1",
+            description = "First input."
+        },
+        {
+            name = "input_2",
+            description = "Second input."
+        },
+    },
+
+    outputs = {
+        {
+            name = "out_1",
+            description = "Channel 1 output. Most likely for the left channel."
+        },
+        {
+            name = "out_2",
+            description = "Channel 2 output. Mose likely for the right channel."
+        },
+    }
+
+}
--- /dev/null
+++ b/modules/dcblocker.c
@@ -1,0 +1,37 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#define SK_DCBLOCKER_PRIV
+#include "tangled/dcblocker.h"
+#include "soundpipe.h"
+
+int sp_dcblocker_create(sp_dcblocker **p)
+{
+    *p = malloc(sizeof(sp_dcblocker));
+    return SP_OK;
+}
+
+int sp_dcblocker_destroy(sp_dcblocker **p)
+{
+    sp_dcblocker *pp;
+    pp = *p;
+    free(pp->dcblocker);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_dcblocker_init(sp_data *sp, sp_dcblocker *p)
+{
+    p->dcblocker = malloc(sizeof(sk_dcblocker));
+    sk_dcblocker_init(p->dcblocker);
+    return SP_OK;
+}
+
+int sp_dcblocker_compute(sp_data *sp, sp_dcblocker *p,
+                         SPFLOAT *in, SPFLOAT *out)
+{
+    *out = sk_dcblocker_tick(p->dcblocker, *in);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/delay.c
@@ -1,0 +1,42 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+int sp_delay_create(sp_delay **p)
+{
+    *p = malloc(sizeof(sp_delay));
+    return SP_OK;
+}
+
+int sp_delay_destroy(sp_delay **p)
+{
+    sp_delay *pp = *p;
+    sp_auxdata_free(&pp->buf);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_delay_init(sp_data *sp, sp_delay *p, SPFLOAT time)
+{
+    p->time = time;
+    p->bufsize = round(time * sp->sr);
+    sp_auxdata_alloc(&p->buf, p->bufsize * sizeof(SPFLOAT));
+    p->bufpos = 0;
+    p->feedback = 0;
+    p->last = 0;
+    return SP_OK;
+}
+
+int sp_delay_compute(sp_data *sp, sp_delay *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT delay = 0, sig = 0;
+    SPFLOAT *buf = (SPFLOAT *)p->buf.ptr;
+    delay = buf[p->bufpos];
+    sig = (delay * p->feedback) + *in;
+    buf[p->bufpos] = sig;
+    p->bufpos = (p->bufpos + 1) % p->bufsize;
+    *out = delay;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/diode.c
@@ -1,0 +1,177 @@
+/*
+ * Diode
+ *
+ * Based on Will Pirkle's Diode Ladder filter design.
+ * Code adapted from the CCRMA Chugin WPDiodeLadder
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+int sp_diode_create(sp_diode **p)
+{
+    *p = malloc(sizeof(sp_diode));
+    return SP_OK;
+}
+
+int sp_diode_destroy(sp_diode **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+static SPFLOAT sp_diode_opva_fdbk_out(sp_data *sp, sp_diode *p, int filt)
+{
+    return p->opva_beta[filt] *
+        (p->opva_z1[filt] + p->opva_fdbk[filt] * p->opva_delta[filt]);
+}
+
+static SPFLOAT sp_diode_opva_compute(sp_data *sp, sp_diode *p, SPFLOAT in, int filt)
+{
+    /*
+	double x_in = (xn*m_dGamma + m_dFeedback + m_dEpsilon*getFeedbackOutput());
+
+	double vn = (m_da0*x_in - m_dZ1)*m_dAlpha;
+	double out = vn + m_dZ1;
+	m_dZ1 = vn + out;
+    */
+
+	/* m_dBeta*(m_dZ1 + m_dFeedback*m_dDelta); */
+
+	SPFLOAT x_in = (in*p->opva_gamma[filt]
+        + p->opva_fdbk[filt]
+        + p->opva_eps[filt] * sp_diode_opva_fdbk_out(sp, p, filt));
+	SPFLOAT vn = (p->opva_a0[filt]*x_in -
+        p->opva_z1[filt])*p->opva_alpha[filt];
+	SPFLOAT out = vn + p->opva_z1[filt];
+	p->opva_z1[filt] = vn + out;
+    return out;
+}
+
+static void sp_diode_update(sp_data *sp, sp_diode *p)
+{
+	/* calculate alphas */
+	SPFLOAT G1, G2, G3, G4;
+	SPFLOAT wd = 2*M_PI*p->freq;
+	SPFLOAT T  = 1/(SPFLOAT)sp->sr;
+	SPFLOAT wa = (2/T)*tan(wd*T/2);
+	SPFLOAT g = wa*T/2;
+    int i;
+
+    /* Big G's */
+	G4 = 0.5*g/(1.0 + g);
+	G3 = 0.5*g/(1.0 + g - 0.5*g*G4);
+	G2 = 0.5*g/(1.0 + g - 0.5*g*G3);
+	G1 = g/(1.0 + g - g*G2);
+
+    /* big G value gamma */
+    p->gamma  = G4*G3*G2*G1;
+
+    p->SG[0] =  G4*G3*G2;
+	p->SG[1] =  G4*G3;
+	p->SG[2] =  G4;
+	p->SG[3] =  1.0;
+
+	/* set alphas */
+    for (i = 0; i < 4; i++) p->opva_alpha[i] = g/(1.0 + g);
+
+    /* set betas */
+    p->opva_beta[0] = 1.0/(1.0 + g - g*G2);
+	p->opva_beta[1] = 1.0/(1.0 + g - 0.5*g*G3);
+	p->opva_beta[2] = 1.0/(1.0 + g - 0.5*g*G4);
+	p->opva_beta[3] = 1.0/(1.0 + g);
+
+	/* set gammas */
+	p->opva_gamma[0] = 1.0 + G1*G2;
+	p->opva_gamma[1] = 1.0 + G2*G3;
+	p->opva_gamma[2] = 1.0 + G3*G4;
+
+    /* set deltas */
+	p->opva_delta[0] = g;
+	p->opva_delta[1] = 0.5*g;
+	p->opva_delta[2] = 0.5*g;
+
+    /* set epsilons */
+	p->opva_eps[0] = G2;
+	p->opva_eps[1] = G3;
+	p->opva_eps[2] = G4;
+}
+
+int sp_diode_init(sp_data *sp, sp_diode *p)
+{
+    int i;
+    /* initialize the 4 one-pole VA filters */
+
+    for (i = 0; i < 4; i++) {
+        p->opva_alpha[i] = 1.0;
+        p->opva_beta[i] = -1.0;
+        p->opva_gamma[i] = 1.0;
+        p->opva_delta[i] = 0.0;
+        p->opva_eps[i] = 1.0;
+        p->opva_fdbk[i] = 0.0;
+        p->opva_a0[i] = 1.0;
+        p->opva_z1[i] = 0.0;
+
+        p->SG[i] = 0.0;
+    }
+
+	p->gamma = 0.0;
+	p->K = 0.0;
+
+	/* Filter coeffs that are constant */
+	/* set a0s */
+    p->opva_a0[0] = 1.0;
+    p->opva_a0[1] = 0.5;
+    p->opva_a0[2] = 0.5;
+    p->opva_a0[3] = 0.5;
+
+	/* last LPF has no feedback path */
+    p->opva_gamma[3] = 1.0;
+    p->opva_delta[3] = 0.0;
+    p->opva_eps[3] = 0.0;
+    p->opva_fdbk[3] = 0.0;
+
+    /* default cutoff to 1000hz */
+    p->freq = 1000;
+    p->res = 0;
+    /* update filter coefs */
+
+    sp_diode_update(sp, p);
+    return SP_OK;
+}
+
+int sp_diode_compute(sp_data *sp, sp_diode *p, SPFLOAT *in, SPFLOAT *out)
+{
+    int i;
+    SPFLOAT sigma;
+    SPFLOAT un;
+    SPFLOAT tmp = 0.0;
+
+    /* update filter coefficients */
+    p->K = p->res * 17;
+    sp_diode_update(sp, p);
+
+    p->opva_fdbk[2] = sp_diode_opva_fdbk_out(sp, p, 3);
+    p->opva_fdbk[1] = sp_diode_opva_fdbk_out(sp, p, 2);
+    p->opva_fdbk[0] = sp_diode_opva_fdbk_out(sp, p, 1);
+
+    sigma =
+        p->SG[0] * sp_diode_opva_fdbk_out(sp, p, 0) +
+        p->SG[1] * sp_diode_opva_fdbk_out(sp, p, 1) +
+        p->SG[2] * sp_diode_opva_fdbk_out(sp, p, 2) +
+        p->SG[3] * sp_diode_opva_fdbk_out(sp, p, 3);
+
+    un = (*in - p->K * sigma) / (1 + p->K * p->gamma);
+    tmp = un;
+    for (i = 0; i < 4; i++) {
+        tmp = sp_diode_opva_compute(sp, p, tmp, i);
+    }
+    *out = tmp;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/dmetro.c
@@ -1,0 +1,37 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_dmetro_create(sp_dmetro **p)
+{
+    *p = malloc(sizeof(sp_dmetro));
+    return SP_OK;
+}
+
+int sp_dmetro_destroy(sp_dmetro **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_dmetro_init(sp_data *sp, sp_dmetro *p)
+{
+    p->counter = 0;
+    p->time = 1.0;
+    return SP_OK;
+}
+
+int sp_dmetro_compute(sp_data *sp, sp_dmetro *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = 0;
+
+    if (p->counter == 0) {
+        *out = 1.0;
+        p->counter = (int)(sp->sr * p->time) + 1;
+    }
+
+    p->counter--;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/dtrig.c
@@ -1,0 +1,54 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_dtrig_create(sp_dtrig **p)
+{
+    *p = malloc(sizeof(sp_dtrig));
+    return SP_OK;
+}
+
+int sp_dtrig_destroy(sp_dtrig **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_dtrig_init(sp_data *sp, sp_dtrig *p, sp_ftbl *ft)
+{
+    p->ft = ft;
+    p->counter = 0;
+    p->pos = 0;
+    p->running = 0;
+    p->loop = 0;
+    p->delay = 0;
+    p->scale = 1;
+    return SP_OK;
+}
+
+int sp_dtrig_compute(sp_data *sp, sp_dtrig *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in == 1.0) {
+        p->running = 1.0;
+        p->pos = 0;
+        p->counter = p->delay * sp->sr;
+    }
+    if ((p->pos < p->ft->size) && p->running) {
+        if (p->counter == 0) {
+            p->counter = (uint32_t)(p->scale * p->ft->tbl[p->pos] * sp->sr - 1);
+            *out = 1.0;
+            p->pos++;
+            if (p->loop) {
+                p->pos %= p->ft->size;
+            }
+            return SP_OK;
+        } else {
+            *out = 0;
+            p->counter--;
+            return SP_OK;
+        }
+    }
+    *out = 0;
+    return SP_NOT_OK;
+}
--- /dev/null
+++ b/modules/expon.c
@@ -1,0 +1,68 @@
+/* This code is placed in the public domain. */
+
+#include <math.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_expon_create(sp_expon **p)
+{
+    *p = malloc(sizeof(sp_expon));
+    return SP_OK;
+}
+
+int sp_expon_destroy(sp_expon **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+static void expon_reinit(sp_data *sp, sp_expon *p)
+{
+    SPFLOAT onedsr;
+    p->stime = 0;
+    p->sdur = p->dur * sp->sr;
+    onedsr = 1.0 / sp->sr;
+
+    if ((p->a * p->b) > 0.0) {
+        p->incr = pow((SPFLOAT)(p->b / p->a), onedsr / p->dur);
+    } else {
+        p->incr = 1;
+        p->val = p->a;
+    }
+
+    p->val = p->a;
+}
+
+int sp_expon_init(sp_data *sp, sp_expon *p)
+{
+    p->a = 0.000001;
+    p->b = 1;
+    p->dur = 1;
+    expon_reinit(sp, p);
+    p->init = 1;
+    return SP_OK;
+}
+
+int sp_expon_compute(sp_data *sp, sp_expon *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in) {
+        expon_reinit(sp, p);
+        p->init = 0;
+    }
+
+    if (p->init) {
+        *out = 0;
+        return SP_OK;
+    }
+
+    if (p->stime < p->sdur) {
+        SPFLOAT val = p->val;
+        p->val *= p->incr;
+        p->stime++;
+        *out = val;
+    } else {
+        *out = p->b;
+    }
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/fftwrapper.c
@@ -1,0 +1,130 @@
+/*
+  FFTwrapper.c  -  A wrapper for Fast Fourier Transforms
+  Author: Nasca O. Paul, Tg. Mures, Romania
+
+  De-classified and ported to C code by Paul Batchelor 2015
+
+  License: Public Domain
+
+  This requires FFTW library (http://www.fftw.org) to compile and run.
+*/
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "soundpipe.h"
+#include "kiss_fftr.h"
+
+void FFTwrapper_create(FFTwrapper **fw, int fftsize)
+{
+    FFTwrapper *fwp;
+    *fw = malloc(sizeof(FFTwrapper));
+    fwp = *fw;
+    fwp->fftsize = fftsize;
+
+#ifdef USE_FFTW3
+    fftw_real *tf1 = malloc(fftsize * sizeof(fftw_real));
+    fftw_real *tf2 = malloc(fftsize * sizeof(fftw_real));
+    fwp->tmpfftdata1 = tf1;
+    fwp->tmpfftdata2 = tf2;
+    fwp->planfftw = fftw_plan_r2r_1d(fftsize, fwp->tmpfftdata1,
+            fwp->tmpfftdata1, FFTW_R2HC, FFTW_ESTIMATE);
+    fwp->planfftw_inv = fftw_plan_r2r_1d(fftsize, fwp->tmpfftdata2,
+            fwp->tmpfftdata2, FFTW_HC2R, FFTW_ESTIMATE);
+#else
+    fwp->fft = kiss_fftr_alloc(fftsize, 0, NULL, NULL);
+    fwp->ifft = kiss_fftr_alloc(fftsize, 1, NULL, NULL);
+    fwp->tmp1 = KISS_FFT_MALLOC(sizeof(kiss_fft_cpx) * fftsize);
+    fwp->tmp2 = KISS_FFT_MALLOC(sizeof(kiss_fft_cpx) * fftsize);
+    memset(fwp->tmp1, 0, sizeof(kiss_fft_cpx) * fftsize);
+    memset(fwp->tmp2, 0, sizeof(kiss_fft_cpx) * fftsize);
+#endif
+
+}
+
+void FFTwrapper_destroy(FFTwrapper **fw)
+{
+    FFTwrapper *fwp = *fw;
+#ifdef USE_FFTW3
+    fftw_destroy_plan(fwp->planfftw);
+    fftw_destroy_plan(fwp->planfftw_inv);
+    free(fwp->tmpfftdata1);
+    free(fwp->tmpfftdata2);
+#else
+    kiss_fftr_free(fwp->fft);
+    kiss_fftr_free(fwp->ifft);
+    KISS_FFT_FREE(fwp->tmp1);
+    KISS_FFT_FREE(fwp->tmp2);
+#endif
+    free(*fw);
+}
+
+/* do the Fast Fourier Transform */
+
+void smps2freqs(FFTwrapper *ft, SPFLOAT *smps, FFTFREQS *freqs)
+{
+    int i;
+
+#ifdef USE_FFTW3
+    for (i = 0; i < ft->fftsize; i++) ft->tmpfftdata1[i]=smps[i];
+    fftw_execute(ft->planfftw);
+
+    for (i = 0; i < ft->fftsize/2; i++) {
+        freqs.c[i] = ft->tmpfftdata1[i];
+        if (i != 0) freqs.s[i] = ft->tmpfftdata1[ft->fftsize-i];
+    }
+
+    ft->tmpfftdata2[ft->fftsize/2] = 0.0;
+#else
+    kiss_fftr(ft->fft, smps, ft->tmp1);
+    for (i = 0; i < ft->fftsize/2; i++) {
+        freqs->c[i] = ft->tmp1[i].r;
+        freqs->s[i] = ft->tmp1[i].i;
+    }
+#endif
+}
+
+/*
+ * do the Inverse Fast Fourier Transform
+ */
+void freqs2smps(FFTwrapper *ft, FFTFREQS *freqs, SPFLOAT *smps)
+{
+
+    int i;
+#ifdef USE_FFTW3
+    ft->tmpfftdata2[ft->fftsize/2]=0.0;
+    for (i=0; i<ft->fftsize/2 ;i++) {
+        ft->tmpfftdata2[i]=freqs.c[i];
+        if (i != 0) ft->tmpfftdata2[ft->fftsize-i]=freqs.s[i];
+    }
+    fftw_execute(ft->planfftw_inv);
+    for (i = 0; i < ft->fftsize; i++) smps[i]=ft->tmpfftdata2[i];
+#else
+    for (i = 0; i < ft->fftsize / 2; i++) {
+        ft->tmp2[i].r = freqs->c[i];
+        ft->tmp2[i].i = freqs->s[i];
+    }
+    kiss_fftri(ft->ifft, ft->tmp2, smps);
+#endif
+
+}
+
+void newFFTFREQS(FFTFREQS *f,int size)
+{
+    int i;
+    SPFLOAT *c = malloc(size * sizeof(SPFLOAT));
+    SPFLOAT *s = malloc(size * sizeof(SPFLOAT));
+    f->c = c;
+    f->s = s;
+    for (i = 0; i<size ;i++) {
+        f->c[i]=0.0;
+        f->s[i]=0.0;
+    };
+}
+
+void deleteFFTFREQS(FFTFREQS *f)
+{
+    free(f->c);
+    free(f->s);
+    f->c= f->s = NULL;
+}
--- /dev/null
+++ b/modules/fmpair.c
@@ -1,0 +1,54 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#define SK_FMPAIR_PRIV
+#include "tangled/fmpair.h"
+#include "soundpipe.h"
+
+int sp_fmpair_create(sp_fmpair **p)
+{
+    *p = malloc(sizeof(sp_fmpair));
+    return SP_OK;
+}
+
+int sp_fmpair_destroy(sp_fmpair **p)
+{
+    sp_fmpair *pp;
+    pp = *p;
+    free(pp->fmpair);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_fmpair_init(sp_data *sp, sp_fmpair *p, sp_ftbl *ft)
+{
+    p->fmpair = malloc(sizeof(sk_fmpair));
+    sk_fmpair_init(p->fmpair, sp->sr,
+                   ft->tbl, ft->size, 0,
+                   ft->tbl, ft->size, 0);
+
+    p->mod = 1.0;
+    p->car = 1.0;
+    p->indx = 1.0;
+    p->amp = 0.4;
+    p->freq = 440;
+
+    sk_fmpair_freq(p->fmpair, p->freq);
+    sk_fmpair_modulator(p->fmpair, p->mod);
+    sk_fmpair_carrier(p->fmpair, p->car);
+    sk_fmpair_modindex(p->fmpair, p->indx);
+    return SP_OK;
+}
+
+int sp_fmpair_compute(sp_data *sp, sp_fmpair *p,
+                      SPFLOAT *in, SPFLOAT *out)
+{
+    sk_fmpair_freq(p->fmpair, p->freq);
+    sk_fmpair_modulator(p->fmpair, p->mod);
+    sk_fmpair_carrier(p->fmpair, p->car);
+    sk_fmpair_modindex(p->fmpair, p->indx);
+    *out = sk_fmpair_tick(p->fmpair) * p->amp;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/foo.c
@@ -1,0 +1,36 @@
+/*
+ * Foo
+ *
+ * This is a dummy module. It doesn't do much.
+ * Feel free to use this as a boilerplate template.
+ *
+ */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_foo_create(sp_foo **p)
+{
+    *p = malloc(sizeof(sp_foo));
+    return SP_OK;
+}
+
+int sp_foo_destroy(sp_foo **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_foo_init(sp_data *sp, sp_foo *p)
+{
+    /* Initalize variables here. */
+    p->bar = 123;
+    return SP_OK;
+}
+
+int sp_foo_compute(sp_data *sp, sp_foo *p, SPFLOAT *in, SPFLOAT *out)
+{
+    /* Send the signal's input to the output */
+    *out = *in;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/ftbl.c
@@ -1,0 +1,106 @@
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef NO_LIBSNDFILE
+#include <sndfile.h>
+#endif
+#include "soundpipe.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#define tpd360 0.0174532925199433
+
+int sp_ftbl_init(sp_data *sp, sp_ftbl *ft, size_t size)
+{
+    ft->size = size;
+    return SP_OK;
+}
+
+int sp_ftbl_create(sp_data *sp, sp_ftbl **ft, size_t size)
+{
+    sp_ftbl *ftp;
+    *ft = malloc(sizeof(sp_ftbl));
+    ftp = *ft;
+    ftp->tbl = malloc(sizeof(SPFLOAT) * (size + 1));
+    memset(ftp->tbl, 0, sizeof(SPFLOAT) * (size + 1));
+
+    sp_ftbl_init(sp, ftp, size);
+    return SP_OK;
+}
+
+int sp_ftbl_destroy(sp_ftbl **ft)
+{
+    sp_ftbl *ftp = *ft;
+    free(ftp->tbl);
+    free(*ft);
+    return SP_OK;
+}
+
+static char * tokenize(char **next, int *size)
+{
+    char *token;
+    char *str;
+    char *peak;
+
+    if (*size <= 0) return NULL;
+    token = *next;
+    str = *next;
+
+    peak = str + 1;
+
+    while ((*size)--) {
+        if (*str == ' ') {
+            *str = 0;
+            if (*peak != ' ') break;
+        }
+        str = str + 1;
+        peak = str + 1;
+    }
+    *next = peak;
+    return token;
+}
+
+int sp_gen_vals(sp_data *sp, sp_ftbl *ft, const char *string)
+{
+    int size;
+    char *str;
+    char *out;
+    char *ptr;
+    int j;
+
+    size = strlen(string);
+    str = malloc(sizeof(char) * size + 1);
+    strcpy(str, string);
+    ptr = str;
+    j = 0;
+
+    while (size > 0) {
+        out = tokenize(&str, &size);
+        if (ft->size < j + 1) {
+            ft->tbl = realloc(ft->tbl, sizeof(SPFLOAT) * (ft->size + 2));
+            /* zero out new tables */
+            ft->tbl[ft->size] = 0;
+            ft->tbl[ft->size + 1] = 0;
+            ft->size++;
+        }
+        ft->tbl[j] = atof(out);
+        j++;
+    }
+
+    sp_ftbl_init(sp, ft, ft->size);
+    free(ptr);
+    return SP_OK;
+}
+
+int sp_gen_sine(sp_data *sp, sp_ftbl *ft)
+{
+    unsigned long i;
+    SPFLOAT step = 2 * M_PI / ft->size;
+    for (i = 0; i < ft->size; i++) {
+        ft->tbl[i] = sin(i * step);
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/in.c
@@ -1,0 +1,31 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_in_create(sp_in **p)
+{
+    *p = malloc(sizeof(sp_in));
+    return SP_OK;
+}
+
+int sp_in_destroy(sp_in **p)
+{
+    sp_in *pp = *p;
+    fclose(pp->fp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_in_init(sp_data *sp, sp_in *p)
+{
+    p->fp = stdin;
+    return SP_OK;
+}
+
+int sp_in_compute(sp_data *sp, sp_in *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = 0;
+    fread(out, sizeof(SPFLOAT), 1, p->fp);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/incr.c
@@ -1,0 +1,47 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+#ifndef max
+#define max(a, b) ((a > b) ? a : b)
+#endif
+
+#ifndef min
+#define min(a, b) ((a < b) ? a : b)
+#endif
+
+
+int sp_incr_create(sp_incr **p)
+{
+    *p = malloc(sizeof(sp_incr));
+    return SP_OK;
+}
+
+int sp_incr_destroy(sp_incr **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_incr_init(sp_data *sp, sp_incr *p, SPFLOAT val)
+{
+    p->min = 0;
+    p->max = 1;
+    p->step = 0.1;
+    p->val = val;
+    return SP_OK;
+}
+
+int sp_incr_compute(sp_data *sp, sp_incr *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in > 0 ) {
+        p->val += p->step;
+        p->val = max(min(p->val, p->max), p->min);
+    } else if (*in < 0) {
+        p->val -= p->step;
+        p->val = max(min(p->val, p->max), p->min);
+    }
+    *out = p->val;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/jcrev.c
@@ -1,0 +1,327 @@
+/*
+ * JCrev
+ *
+ * This code has been partially generated using Faust.
+ * See the file "jcrev.dsp" to see the original faust code utilized.
+ *
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT SPFLOAT
+#endif
+
+typedef struct {
+
+	float fVec5[4096];
+	float fVec6[4096];
+	float fVec3[2048];
+	float fVec4[2048];
+	float fVec0[512];
+	float fVec1[128];
+	float fVec2[64];
+	float fRec6[2];
+	float fRec4[2];
+	float fRec2[2];
+	float fRec0[2];
+	float fRec1[2];
+	float fRec8[2];
+	float fRec9[2];
+	float fRec10[2];
+	float fRec11[2];
+	float fRec12[2];
+	float fRec13[2];
+	int IOTA;
+	int fSamplingFreq;
+
+} jcrev;
+
+jcrev* newjcrev() {
+	jcrev* dsp = (jcrev*)malloc(sizeof(jcrev));
+	return dsp;
+}
+
+void deletejcrev(jcrev* dsp) {
+	free(dsp);
+}
+
+void instanceInitjcrev(jcrev* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->IOTA = 0;
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 512); i0 = (i0 + 1)) {
+			dsp->fVec0[i0] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec6[i1] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 128); i2 = (i2 + 1)) {
+			dsp->fVec1[i2] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i3;
+		for (i3 = 0; (i3 < 2); i3 = (i3 + 1)) {
+			dsp->fRec4[i3] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i4;
+		for (i4 = 0; (i4 < 64); i4 = (i4 + 1)) {
+			dsp->fVec2[i4] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i5;
+		for (i5 = 0; (i5 < 2); i5 = (i5 + 1)) {
+			dsp->fRec2[i5] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i6;
+		for (i6 = 0; (i6 < 2048); i6 = (i6 + 1)) {
+			dsp->fVec3[i6] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i7;
+		for (i7 = 0; (i7 < 2); i7 = (i7 + 1)) {
+			dsp->fRec0[i7] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i8;
+		for (i8 = 0; (i8 < 2); i8 = (i8 + 1)) {
+			dsp->fRec1[i8] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i9;
+		for (i9 = 0; (i9 < 2048); i9 = (i9 + 1)) {
+			dsp->fVec4[i9] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i10;
+		for (i10 = 0; (i10 < 2); i10 = (i10 + 1)) {
+			dsp->fRec8[i10] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i11;
+		for (i11 = 0; (i11 < 2); i11 = (i11 + 1)) {
+			dsp->fRec9[i11] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i12;
+		for (i12 = 0; (i12 < 4096); i12 = (i12 + 1)) {
+			dsp->fVec5[i12] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i13;
+		for (i13 = 0; (i13 < 2); i13 = (i13 + 1)) {
+			dsp->fRec10[i13] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i14;
+		for (i14 = 0; (i14 < 2); i14 = (i14 + 1)) {
+			dsp->fRec11[i14] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i15;
+		for (i15 = 0; (i15 < 4096); i15 = (i15 + 1)) {
+			dsp->fVec6[i15] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i16;
+		for (i16 = 0; (i16 < 2); i16 = (i16 + 1)) {
+			dsp->fRec12[i16] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i17;
+		for (i17 = 0; (i17 < 2); i17 = (i17 + 1)) {
+			dsp->fRec13[i17] = 0.f;
+
+		}
+
+	}
+
+}
+
+void initjcrev(jcrev* dsp, int samplingFreq) {
+	instanceInitjcrev(dsp, samplingFreq);
+}
+
+void computejcrev(jcrev* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* input0 = inputs[0];
+	FAUSTFLOAT* output0 = outputs[0];
+	FAUSTFLOAT* output1 = outputs[1];
+	FAUSTFLOAT* output2 = outputs[2];
+	FAUSTFLOAT* output3 = outputs[3];
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			float fTemp0 = ((0.7f * dsp->fRec6[1]) + (0.06f * (float)input0[i]));
+			dsp->fVec0[(dsp->IOTA & 511)] = fTemp0;
+			dsp->fRec6[0] = dsp->fVec0[((dsp->IOTA - 346) & 511)];
+			float fRec7 = (0.f - (0.7f * fTemp0));
+			float fTemp1 = (dsp->fRec6[1] + (fRec7 + (0.7f * dsp->fRec4[1])));
+			dsp->fVec1[(dsp->IOTA & 127)] = fTemp1;
+			dsp->fRec4[0] = dsp->fVec1[((dsp->IOTA - 112) & 127)];
+			float fRec5 = (0.f - (0.7f * fTemp1));
+			float fTemp2 = (dsp->fRec4[1] + (fRec5 + (0.7f * dsp->fRec2[1])));
+			dsp->fVec2[(dsp->IOTA & 63)] = fTemp2;
+			dsp->fRec2[0] = dsp->fVec2[((dsp->IOTA - 36) & 63)];
+			float fRec3 = (0.f - (0.7f * fTemp2));
+			float fTemp3 = (dsp->fRec2[1] + (fRec3 + (0.802f * dsp->fRec0[1])));
+			dsp->fVec3[(dsp->IOTA & 2047)] = fTemp3;
+			dsp->fRec0[0] = dsp->fVec3[((dsp->IOTA - 1600) & 2047)];
+			dsp->fRec1[0] = fTemp3;
+			float fTemp4 = (fRec3 + dsp->fRec2[1]);
+			float fTemp5 = (fTemp4 + (0.773f * dsp->fRec8[1]));
+			dsp->fVec4[(dsp->IOTA & 2047)] = fTemp5;
+			dsp->fRec8[0] = dsp->fVec4[((dsp->IOTA - 1866) & 2047)];
+			dsp->fRec9[0] = fTemp5;
+			float fTemp6 = (fTemp4 + (0.753f * dsp->fRec10[1]));
+			dsp->fVec5[(dsp->IOTA & 4095)] = fTemp6;
+			dsp->fRec10[0] = dsp->fVec5[((dsp->IOTA - 2052) & 4095)];
+			dsp->fRec11[0] = fTemp6;
+			float fTemp7 = (fTemp4 + (0.733f * dsp->fRec12[1]));
+			dsp->fVec6[(dsp->IOTA & 4095)] = fTemp7;
+			dsp->fRec12[0] = dsp->fVec6[((dsp->IOTA - 2250) & 4095)];
+			dsp->fRec13[0] = fTemp7;
+			float fTemp8 = (((dsp->fRec1[1] + dsp->fRec9[1]) + dsp->fRec11[1]) + dsp->fRec13[1]);
+			output0[i] = (FAUSTFLOAT)fTemp8;
+			output1[i] = (FAUSTFLOAT)(0.f - fTemp8);
+			float fTemp9 = (dsp->fRec1[1] + dsp->fRec11[1]);
+			float fTemp10 = (dsp->fRec9[1] + dsp->fRec13[1]);
+			output2[i] = (FAUSTFLOAT)(0.f - (fTemp9 - fTemp10));
+			output3[i] = (FAUSTFLOAT)(0.f - (fTemp10 - fTemp9));
+			dsp->IOTA = (dsp->IOTA + 1);
+			dsp->fRec6[1] = dsp->fRec6[0];
+			dsp->fRec4[1] = dsp->fRec4[0];
+			dsp->fRec2[1] = dsp->fRec2[0];
+			dsp->fRec0[1] = dsp->fRec0[0];
+			dsp->fRec1[1] = dsp->fRec1[0];
+			dsp->fRec8[1] = dsp->fRec8[0];
+			dsp->fRec9[1] = dsp->fRec9[0];
+			dsp->fRec10[1] = dsp->fRec10[0];
+			dsp->fRec11[1] = dsp->fRec11[0];
+			dsp->fRec12[1] = dsp->fRec12[0];
+			dsp->fRec13[1] = dsp->fRec13[0];
+
+		}
+
+	}
+
+}
+
+
+int sp_jcrev_create(sp_jcrev **p)
+{
+    *p = malloc(sizeof(sp_jcrev));
+    return SP_OK;
+}
+
+int sp_jcrev_destroy(sp_jcrev **p)
+{
+    sp_jcrev *pp = *p;
+    jcrev *dsp = pp->ud;
+    deletejcrev(dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_jcrev_init(sp_data *sp, sp_jcrev *p)
+{
+    jcrev *dsp = newjcrev();
+    initjcrev(dsp, sp->sr);
+    p->ud = dsp;
+    return SP_OK;
+}
+
+int sp_jcrev_compute(sp_data *sp, sp_jcrev *p, SPFLOAT *in, SPFLOAT *out)
+{
+
+    jcrev *dsp = p->ud;
+    SPFLOAT out1 = 0, out2 = 0, out3 = 0, out4 = 0;
+    SPFLOAT *faust_out[] = {&out1, &out2, &out3, &out4};
+    computejcrev(dsp, 1, &in, faust_out);
+
+    /* As you can see, only 1 out of the 4 channels are being used */
+    *out = out1;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/line.c
@@ -1,0 +1,59 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_line_create(sp_line **p)
+{
+    *p = malloc(sizeof(sp_line));
+    return SP_OK;
+}
+
+int sp_line_destroy(sp_line **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+static void line_reinit(sp_data *sp, sp_line *p)
+{
+    SPFLOAT onedsr = 1.0 / sp->sr;
+    p->incr = (SPFLOAT)((p->b - p->a) / (p->dur)) * onedsr;
+    p->val = p->a;
+    p->stime = 0;
+    p->sdur = sp->sr * p->dur;
+}
+
+int sp_line_init(sp_data *sp, sp_line *p)
+{
+    p->a = 0;
+    p->dur = 0.5;
+    p->b = 1;
+    line_reinit(sp, p);
+    p->init = 1;
+    return SP_OK;
+}
+
+int sp_line_compute(sp_data *sp, sp_line *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in != 0 ) {
+        line_reinit(sp, p);
+        p->init = 0;
+    }
+
+    if (p->init) {
+        *out = 0;
+        return SP_OK;
+    }
+
+    if (p->stime < p->sdur) {
+        SPFLOAT val = p->val;
+        p->val += p->incr;
+        p->stime++;
+        *out = val;
+    } else {
+        *out = p->b;
+    }
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/loadwav.c
@@ -1,0 +1,27 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+#include "lib/dr_wav/sp_dr_wav.h"
+
+int sp_ftbl_loadwav(sp_data *sp, sp_ftbl **ft, const char *filename)
+{
+    drwav *wav;
+    size_t size;
+    SPFLOAT *tbl;
+    sp_ftbl *ftp;
+
+    wav = calloc(1, sp_drwav_size());
+    if (!sp_drwav_init_file(wav, filename)) return SP_NOT_OK;
+
+    size = sp_drwav_sampcount(wav);
+    *ft = malloc(sizeof(sp_ftbl));
+    ftp = *ft;
+    ftp->tbl = malloc(sizeof(SPFLOAT) * (size + 1));
+    tbl = ftp->tbl;
+    sp_ftbl_init(sp, ftp, size);
+    sp_drwav_read_f32(wav, size, tbl);
+    sp_drwav_uninit(wav);
+    free(wav);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/lpc.c
@@ -1,0 +1,104 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "openlpc.h"
+
+int sp_lpc_create(sp_lpc **lpc)
+{
+    *lpc = malloc(sizeof(sp_lpc));
+    return SP_OK;
+}
+
+int sp_lpc_destroy(sp_lpc **lpc)
+{
+    sp_lpc *plpc;
+    plpc = *lpc;
+    sp_auxdata_free(&plpc->m_e);
+    sp_auxdata_free(&plpc->m_d);
+    sp_auxdata_free(&plpc->m_out);
+    sp_auxdata_free(&plpc->m_in);
+    free(*lpc);
+    return SP_OK;
+}
+
+int sp_lpc_init(sp_data *sp, sp_lpc *lpc, int framesize)
+{
+    int i;
+    lpc->counter = 0;
+    lpc->clock = 0;
+    lpc->block = 4;
+    lpc->samp = 0;
+    lpc->mode = 0;
+    lpc->framesize = framesize;
+    openlpc_sr(sp->sr / lpc->block);
+
+    sp_auxdata_alloc(&lpc->m_d, openlpc_get_decoder_state_size());
+    sp_auxdata_alloc(&lpc->m_e, openlpc_get_encoder_state_size());
+    lpc->d = lpc->m_d.ptr;
+    lpc->e = lpc->m_e.ptr;
+
+    sp_auxdata_alloc(&lpc->m_in, sizeof(short) * framesize);
+    sp_auxdata_alloc(&lpc->m_out, sizeof(short) * framesize);
+
+    lpc->out = lpc->m_out.ptr;
+    lpc->in = lpc->m_in.ptr;
+
+    init_openlpc_decoder_state(lpc->d, framesize);
+    init_openlpc_encoder_state(lpc->e, framesize);
+
+    for (i = 0; i < framesize; i++) {
+        lpc->in[i] = 0;
+        lpc->out[i] = 0;
+        if(i < 7) lpc->data[i] = 0;
+    }
+    return SP_OK;
+}
+
+int sp_lpc_compute(sp_data *sp, sp_lpc *lpc, SPFLOAT *in, SPFLOAT *out)
+{
+    int i;
+
+    if (lpc->clock == 0) {
+        if (lpc->counter == 0) {
+            if (lpc->mode == 0) {
+                openlpc_encode(lpc->in, lpc->data, lpc->e);
+            } else {
+                for (i = 0; i < 7; i++) {
+                    lpc->y[i] =
+                        lpc->smooth*lpc->y[i] +
+                        (1-lpc->smooth)*lpc->ft->tbl[i];
+                    lpc->data[i] = 255 * lpc->y[i];
+                }
+            }
+            openlpc_decode(sp, lpc->data, lpc->out, lpc->d);
+        }
+
+        if (lpc->mode == 0) lpc->in[lpc->counter] = *in * 32767;
+        lpc->samp = lpc->out[lpc->counter] / 32767.0;
+
+        lpc->counter = (lpc->counter + 1) % lpc->framesize;
+    }
+
+
+    lpc->clock = (lpc->clock + 1) % lpc->block;
+    *out = lpc->samp;
+
+    return SP_OK;
+}
+
+int sp_lpc_synth(sp_data *sp, sp_lpc *lpc, sp_ftbl *ft)
+{
+    int i;
+    int sr;
+    sr = sp->sr;
+
+    sr = sr / 4;
+    sr = sr / lpc->framesize;
+    lpc->ft = ft;
+    lpc->mode = 1;
+    for (i = 0; i < 7; i++) lpc->y[i] = 0;
+    lpc->smooth = exp(-1.0 / (0.01 * sr));
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/maygate.c
@@ -1,0 +1,45 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_maygate_create(sp_maygate **p)
+{
+    *p = malloc(sizeof(sp_maygate));
+    return SP_OK;
+}
+
+int sp_maygate_destroy(sp_maygate **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_maygate_init(sp_data *sp, sp_maygate *p)
+{
+    p->prob = 0.0;
+    p->gate = 0;
+    p->mode = 0;
+    return SP_OK;
+}
+
+int sp_maygate_compute(sp_data *sp, sp_maygate *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in == 0) {
+        if (p->mode) {
+            *out = 0;
+        } else {
+            *out = p->gate;
+        }
+        return SP_OK;
+    }
+
+    if ((1.0 * sp_rand(sp) / SP_RANDMAX) <= p->prob) {
+        *out = 1;
+        p->gate = 1;
+    } else {
+        *out = 0;
+        p->gate = 0;
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/metro.c
@@ -1,0 +1,62 @@
+/*
+ * Metro
+ *
+ * Metro produces a signal steady sequence of impulses,
+ * which is typically used as a clock signal to for other
+ * modules.
+ *
+ * Metro is very similar to the "metro" object in puredata,
+ * except that the rate parameter unit is supplied in Hz,
+ * not ms.
+ *
+ * This code has been placed in the public domain.
+ */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_metro_create(sp_metro **p)
+{
+    *p = malloc(sizeof(sp_metro));
+    return SP_OK;
+}
+
+int sp_metro_destroy(sp_metro **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_metro_init(sp_data *sp, sp_metro *p)
+{
+    p->freq = 2.0;
+    p->phs = 0;
+    p->init = 1;
+    p->onedsr = 1.0 / sp->sr;
+    return SP_OK;
+}
+
+int sp_metro_compute(sp_data *sp, sp_metro *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT phs;
+
+    phs = p->phs;
+
+    *out = 0;
+
+    if (p->init) {
+        *out = 1.0;
+        p->init = 0;
+    } else {
+        phs += p->freq * p->onedsr;
+
+        if (phs >= 1) {
+            *out = 1.0;
+            phs -= 1.0;
+        }
+    }
+
+    p->phs = phs;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/modalres.c
@@ -1,0 +1,44 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#define SK_MODALRES_PRIV
+#include "tangled/modalres.h"
+#include "soundpipe.h"
+
+int sp_modalres_create(sp_modalres **p)
+{
+    *p = malloc(sizeof(sp_modalres));
+    return SP_OK;
+}
+
+int sp_modalres_destroy(sp_modalres **p)
+{
+    sp_modalres *pp;
+    pp = *p;
+    free(pp->modalres);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_modalres_init(sp_data *sp, sp_modalres *p)
+{
+    p->modalres = malloc(sizeof(sk_modalres));
+    sk_modalres_init(p->modalres, sp->sr);
+    p->freq = 500;
+    p->q = 50;
+
+    sk_modalres_freq(p->modalres, p->freq);
+    sk_modalres_q(p->modalres, p->q);
+    return SP_OK;
+}
+
+int sp_modalres_compute(sp_data *sp, sp_modalres *p,
+                         SPFLOAT *in, SPFLOAT *out)
+{
+    sk_modalres_freq(p->modalres, p->freq);
+    sk_modalres_q(p->modalres, p->q);
+    *out = sk_modalres_tick(p->modalres, *in);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/noise.c
@@ -1,0 +1,31 @@
+/* This code is placed in the public domain. */
+
+#include <math.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_noise_create(sp_noise **ns)
+{
+    *ns = malloc(sizeof(sp_noise));
+    return SP_OK;
+}
+
+int sp_noise_init(sp_data *sp, sp_noise *ns)
+{
+    ns->amp = 1.0;
+    return SP_OK;
+}
+
+int sp_noise_compute(sp_data *sp, sp_noise *ns, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = ((sp_rand(sp) % SP_RANDMAX) / (SP_RANDMAX * 1.0));
+    *out = (*out * 2) - 1;
+    *out *= ns->amp;
+    return SP_OK;
+}
+
+int sp_noise_destroy(sp_noise **ns)
+{
+    free(*ns);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/nsmp.c
@@ -1,0 +1,244 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "ini.h"
+
+int nano_dict_add(nano_dict *dict, const char *name)
+{
+    nano_entry *entry = malloc(sizeof(nano_entry));
+    entry->size = 0;
+    entry->speed = 1;
+    entry->pos = 0;
+    strcpy(entry->name, name);
+    dict->last->next = entry;
+    dict->last = entry;
+    dict->nval++;
+    return SP_OK;
+}
+
+int nano_ini_handler(void *user, const char *section, const char *name,
+        const char *value)
+{
+    nanosamp *ss = user;
+    nano_dict *dict = &ss->dict;
+    const char *entry_name = dict->last->name;
+
+    if (dict->init) {
+        nano_dict_add(dict, section);
+        dict->init = 0;
+    } else if(strncmp(entry_name, section, 50) != 0) {
+        nano_dict_add(dict, section);
+    }
+
+    dict->last->speed = 1.0;
+
+    if (strcmp(name, "pos") == 0) {
+        dict->last->pos = (uint32_t)(atof(value) * ss->sr);
+    } else if (strcmp(name, "size") == 0) {
+        dict->last->size = (uint32_t)(atof(value) * ss->sr);
+    } else if (strcmp(name, "speed") == 0) {
+        dict->last->speed = atof(value);
+    }
+
+    return SP_OK;
+}
+
+int nano_create(nanosamp **smp, const char *ini, int sr)
+{
+    nanosamp *psmp;
+    *smp = malloc(sizeof(nanosamp));
+    psmp = *smp;
+    strcpy(psmp->ini, ini);
+    psmp->dict.last = &psmp->dict.root;
+    psmp->dict.nval = 0;
+    psmp->dict.init = 1;
+    psmp->selected = 0;
+    psmp->curpos = 0;
+    psmp->sr = sr;
+
+    if (ini_parse(psmp->ini, nano_ini_handler, psmp) < 0) {
+        printf("Can't load file %s\n", psmp->ini);
+        return SP_NOT_OK;
+    }
+
+    return SP_OK;
+}
+
+int nano_select_from_index(nanosamp *smp, uint32_t pos)
+{
+    pos %= smp->dict.nval;
+    smp->selected = 1;
+    smp->sample = smp->index[pos];
+    smp->curpos = 0;
+    return SP_OK;
+}
+
+uint32_t nano_keyword_to_index(nanosamp *smp, const char *keyword)
+{
+    uint32_t i;
+    for (i = 0; i < smp->dict.nval; i++) {
+        if (strcmp(keyword, smp->index[i]->name)) {
+            return i;
+        }
+    }
+    return 0;
+}
+
+int nano_select(nanosamp *smp, const char *keyword)
+{
+    uint32_t i;
+    nano_dict *dict = &smp->dict;
+    nano_entry *entry = dict->root.next;
+
+    smp->curpos = 0;
+    smp->selected = 0;
+
+    for (i = 0; i < dict->nval; i++) {
+        if (strncmp(keyword, entry->name, 50) == 0) {
+            smp->selected = 1;
+            smp->sample = entry;
+            smp->curpos = 0;
+            break;
+        } else {
+            entry = entry->next;
+        }
+    }
+
+    if (smp->selected == 1) return SP_OK;
+    else return SP_NOT_OK;
+}
+
+
+int nano_compute(sp_data *sp, nanosamp *smp, SPFLOAT *out)
+{
+    if (!smp->selected) {
+        *out = 0;
+        return SP_NOT_OK;
+    }
+
+    if (smp->curpos < (SPFLOAT)smp->sample->size) {
+        SPFLOAT x1 = 0 , x2 = 0, frac = 0, tmp = 0;
+        uint32_t index = 0;
+        SPFLOAT *tbl = smp->ft->tbl;
+
+        tmp = (smp->curpos + smp->sample->pos);
+        index = floorf(tmp);
+        frac = fabs(tmp - index);
+
+        if (index >= smp->ft->size) {
+            index = smp->ft->size - 1;
+        }
+
+        x1 = tbl[index];
+        x2 = tbl[index + 1];
+        *out = x1 + (x2 - x1) * frac;
+        smp->curpos += smp->sample->speed;
+    } else {
+        smp->selected = 0;
+        *out = 0;
+    }
+
+    return SP_OK;
+}
+
+int nano_dict_destroy(nano_dict *dict)
+{
+    int i;
+    nano_entry *entry, *next;
+    entry = dict->root.next;
+
+    for (i = 0; i < dict->nval; i++) {
+        next = entry->next;
+        free(entry);
+        entry = next;
+    }
+
+    return SP_OK;
+}
+
+int nano_destroy(nanosamp **smp)
+{
+    nanosamp *psmp = *smp;
+    nano_dict_destroy(&psmp->dict);
+    free(*smp);
+    return SP_OK;
+}
+
+int nano_create_index(nanosamp *smp)
+{
+    int i;
+    nano_entry *entry, *next;
+    nano_dict *dict = &smp->dict;
+    smp->index = malloc(dict->nval * sizeof(nano_entry *));
+    entry = dict->root.next;
+
+    for (i = 0; i < dict->nval; i++) {
+        next = entry->next;
+        smp->index[i] = entry;
+        entry = next;
+    }
+    return SP_OK;
+}
+
+int nano_destroy_index(nanosamp *smp)
+{
+    free(smp->index);
+    return SP_OK;
+}
+
+int sp_nsmp_create(sp_nsmp **p)
+{
+    *p = malloc(sizeof(sp_nsmp));
+    return SP_OK;
+}
+
+int sp_nsmp_destroy(sp_nsmp **p)
+{
+    sp_nsmp *pp = *p;
+    nano_destroy_index(pp->smp);
+    nano_destroy(&pp->smp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_nsmp_init(sp_data *sp, sp_nsmp *p, sp_ftbl *ft, int sr, const char *ini)
+{
+    if (nano_create(&p->smp, ini, sr) == SP_NOT_OK) {
+        nano_destroy(&p->smp);
+        return SP_NOT_OK;
+    }
+    nano_create_index(p->smp);
+    p->smp->sr = sr;
+    p->index= 0;
+    p->triggered = 0;
+    p->smp->ft = ft;
+    return SP_OK;
+}
+
+int sp_nsmp_compute(sp_data *sp, sp_nsmp *p, SPFLOAT *trig, SPFLOAT *out)
+{
+    if (*trig != 0) {
+       p->triggered = 1;
+       nano_select_from_index(p->smp, p->index);
+    }
+
+    if (p->triggered == 1) {
+        nano_compute(sp, p->smp, out);
+    } else {
+        *out = 0;
+    }
+
+    return SP_OK;
+}
+
+int sp_nsmp_print_index(sp_data *sp, sp_nsmp *p)
+{
+    uint32_t i;
+    for (i = 0; i < p->smp->dict.nval; i++) {
+        printf("%d: key = %s\n", i, p->smp->index[i]->name);
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/osc.c
@@ -1,0 +1,40 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#define SK_OSC_PRIV
+#include "tangled/osc.h"
+#include "soundpipe.h"
+
+int sp_osc_create(sp_osc **osc)
+{
+    *osc = malloc(sizeof(sp_osc));
+    return SP_OK;
+}
+
+int sp_osc_destroy(sp_osc **osc)
+{
+    sp_osc *o;
+    o = *osc;
+    free(o->osc);
+    free(*osc);
+    return SP_OK;
+}
+
+int sp_osc_init(sp_data *sp, sp_osc *osc, sp_ftbl *ft, SPFLOAT iphs)
+{
+    osc->freq = 440.0;
+    osc->amp = 0.2;
+    osc->osc = malloc(sizeof(sk_osc));
+    sk_osc_init(osc->osc, sp->sr, ft->tbl, ft->size, iphs);
+    return SP_OK;
+}
+
+int sp_osc_compute(sp_data *sp, sp_osc *osc, SPFLOAT *in, SPFLOAT *out)
+{
+    sk_osc_freq(osc->osc, osc->freq);
+    sk_osc_amp(osc->osc, osc->amp);
+    *out = sk_osc_tick(osc->osc);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/oscmorph.c
@@ -1,0 +1,90 @@
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+int sp_oscmorph_create(sp_oscmorph **p)
+{
+    *p = malloc(sizeof(sp_oscmorph));
+    return SP_OK;
+}
+
+int sp_oscmorph_destroy(sp_oscmorph **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_oscmorph_init(sp_data *sp, sp_oscmorph *osc, sp_ftbl **ft, int nft, SPFLOAT iphs)
+{
+    int i;
+    osc->freq = 440.0;
+    osc->amp = 0.2;
+    osc->tbl = ft;
+    osc->iphs = fabs(iphs);
+    osc->inc = 0;
+    osc->lphs = ((int32_t)(osc->iphs * SP_FT_MAXLEN)) & SP_FT_PHMASK;
+    osc->wtpos = 0.0;
+    osc->nft = nft;
+    uint32_t prev = (uint32_t)ft[0]->size;
+    for (i = 0; i < nft; i++) {
+        if (prev != ft[i]->size) {
+            fprintf(stderr, "sp_oscmorph: size mismatch\n");
+            return SP_NOT_OK;
+        }
+        prev = (uint32_t)ft[i]->size;
+    }
+    return SP_OK;
+}
+
+int sp_oscmorph_compute(sp_data *sp, sp_oscmorph *osc, SPFLOAT *in, SPFLOAT *out)
+{
+    sp_ftbl *ftp1;
+    SPFLOAT amp, cps, fract, v1, v2;
+    SPFLOAT *ft1, *ft2;
+    int32_t phs, lobits, pos;
+    SPFLOAT sicvt = osc->tbl[0]->sicvt;
+
+    /* Use only the fractional part of the position or 1 */
+    if (osc->wtpos > 1.0) {
+        osc->wtpos -= (int)osc->wtpos;
+    }
+    SPFLOAT findex = osc->wtpos * (osc->nft - 1);
+    int index = floor(findex);
+    SPFLOAT wtfrac = findex - index;
+
+    lobits = osc->tbl[0]->lobits;
+    amp = osc->amp;
+    cps = osc->freq;
+    phs = osc->lphs;
+    ftp1 = osc->tbl[index];
+    ft1 = osc->tbl[index]->tbl;
+
+    if (index >= osc->nft - 1) {
+        ft2 = ft1;
+    } else {
+        ft2 = osc->tbl[index + 1]->tbl;
+    }
+
+    osc->inc = (int32_t)lrintf(cps * sicvt);
+
+    fract = ((phs) & ftp1->lomask) * ftp1->lodiv;
+
+    pos = phs >> lobits;
+
+    v1 = (1 - wtfrac) *
+        *(ft1 + pos) +
+        wtfrac *
+        *(ft2 + pos);
+    v2 = (1 - wtfrac) *
+        *(ft1 + ((pos + 1) % ftp1->size))+
+        wtfrac *
+        *(ft2 + ((pos + 1) % ftp1->size));
+
+    *out = (v1 + (v2 - v1) * fract) * amp;
+
+    phs += osc->inc;
+    phs &= SP_FT_PHMASK;
+
+    osc->lphs = phs;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/padsynth.c
@@ -1,0 +1,127 @@
+/*
+    Example implementation of the PADsynth basic algorithm
+    By: Nasca O. Paul, Tg. Mures, Romania
+
+    Ported to pure C by Paul Batchelor
+
+    This implementation and the algorithm are released under Public Domain
+    Feel free to use it into your projects or your products ;-)
+
+    This implementation is tested under GCC/Linux, but it's
+    very easy to port to other compiler/OS.
+*/
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+#ifndef M_PI
+#define M_PI		3.14159265358979323846
+#endif
+
+int sp_gen_padsynth(sp_data *sp, sp_ftbl *ps, sp_ftbl *amps,
+        SPFLOAT f, SPFLOAT bw)
+{
+
+    int i, nh;
+    int N = (int) ps->size;
+    int number_harmonics = (int) amps->size;
+    SPFLOAT *A = amps->tbl;
+    SPFLOAT *smp = ps->tbl;
+
+    SPFLOAT *freq_amp = malloc((N / 2) * sizeof(SPFLOAT));
+    SPFLOAT *freq_phase = malloc((N / 2) * sizeof(SPFLOAT));
+
+
+    N = (int) ps->size;
+    number_harmonics = (int) amps->size;
+    A = amps->tbl;
+    smp = ps->tbl;
+
+    freq_amp = malloc((N / 2) * sizeof(SPFLOAT));
+    freq_phase = malloc((N / 2) * sizeof(SPFLOAT));
+
+    for (i = 0; i < N/2; i++) freq_amp[i]=0.0;
+
+    for (nh=1; nh < number_harmonics; nh++) {
+        SPFLOAT bw_Hz;
+        SPFLOAT bwi;
+        SPFLOAT fi;
+        bw_Hz = (pow(2.0, bw/1200.0) - 1.0) * f * nh;
+        bwi = bw_Hz/(2.0*ps->size);
+        fi = f*nh/ps->size;
+        for (i = 0; i < N/2 ; i++) {
+            SPFLOAT hprofile;
+            hprofile = sp_padsynth_profile((i / (SPFLOAT) N) - fi, bwi);
+            freq_amp[i] += hprofile*A[nh];
+        }
+    }
+
+    for (i = 0; i < N/2; i++) {
+        freq_phase[i] = (sp_rand(sp) / (SP_RANDMAX + 1.0)) * 2.0 * M_PI;
+    };
+
+    sp_padsynth_ifft(N,freq_amp,freq_phase,smp);
+    sp_padsynth_normalize(N,smp);
+
+    free(freq_amp);
+    free(freq_phase);
+    return SP_OK;
+}
+
+/* This is the profile of one harmonic
+   In this case is a Gaussian distribution (e^(-x^2))
+   The amplitude is divided by the bandwidth to ensure that the harmonic
+   keeps the same amplitude regardless of the bandwidth */
+
+SPFLOAT sp_padsynth_profile(SPFLOAT fi, SPFLOAT bwi)
+{
+    SPFLOAT x =fi/bwi;
+    x *= x;
+
+    /*
+     * this avoids computing the e^(-x^2) where
+     * it's results are very close to zero
+     */
+
+    if (x>14.71280603) return 0.0;
+
+    return exp(-x)/bwi;
+}
+
+int sp_padsynth_ifft(int N, SPFLOAT *freq_amp,
+        SPFLOAT *freq_phase, SPFLOAT *smp)
+{
+    int i;
+    FFTwrapper *fft;
+    FFTFREQS fftfreqs;
+
+    FFTwrapper_create(&fft, N);
+    newFFTFREQS(&fftfreqs,N/2);
+
+    for (i = 0; i < N/2; i++) {
+        fftfreqs.c[i] = freq_amp[i]*cos(freq_phase[i]);
+        fftfreqs.s[i] = freq_amp[i]*sin(freq_phase[i]);
+    };
+
+    freqs2smps(fft, &fftfreqs,smp);
+    deleteFFTFREQS(&fftfreqs);
+    FFTwrapper_destroy(&fft);
+    return SP_OK;
+}
+
+/*
+    Simple normalization function. It normalizes the sound to 1/sqrt(2)
+*/
+
+int sp_padsynth_normalize(int N, SPFLOAT *smp)
+{
+    int i;
+    SPFLOAT max=0.0;
+    for (i = 0; i < N;i++) {
+        if (fabs(smp[i]) > max) max = fabs(smp[i]);
+    }
+    if (max < 1e-5) max = 1e-5;
+    for (i = 0; i < N; i++) smp[i] /= max*1.4142;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/paulstretch.c
@@ -1,0 +1,156 @@
+/*
+ * PaulStretch
+ *
+ * An implementation of the PaulStretch algorithm by Paul Nasca Octavian.
+ * This code is based off the Python Numpy/Scipy implementation of
+ * PaulStretch, found here: https://github.com/paulnasca/paulstretch_python
+ *
+ * This implementation has been placed in the public domain.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "kiss_fftr.h"
+
+#ifndef M_PI
+#define M_PI		3.14159265358979323846
+#endif
+
+static void compute_block(sp_data *sp, sp_paulstretch *p) {
+    uint32_t istart_pos = floor(p->start_pos);
+    uint32_t pos;
+    uint32_t i;
+    uint32_t windowsize = p->windowsize;
+    uint32_t half_windowsize = p->half_windowsize;
+    SPFLOAT *buf = p->buf;
+    SPFLOAT *hinv_buf = p->hinv_buf;
+    SPFLOAT *old_windowed_buf= p->old_windowed_buf;
+    SPFLOAT *tbl = p->ft->tbl;
+    SPFLOAT *window = p->window;
+    SPFLOAT *output= p->output;
+
+    for (i = 0; i < windowsize; i++) {
+        /* Loop through buffer */
+        pos = (istart_pos + i);
+
+        if (p->wrap) {
+            pos %= p->ft->size;
+        }
+
+        if (pos < p->ft->size) {
+            buf[i] = tbl[pos] * window[i];
+        } else {
+            buf[i] = 0;
+        }
+    }
+
+    kiss_fftr(p->fft, buf, p->tmp1);
+
+    for (i = 0; i < windowsize / 2; i++) {
+        SPFLOAT mag = sqrt(p->tmp1[i].r*p->tmp1[i].r + p->tmp1[i].i*p->tmp1[i].i);
+        SPFLOAT ph = ((SPFLOAT)sp_rand(sp) / SP_RANDMAX) * 2 * M_PI;
+        p->tmp1[i].r = mag * cos(ph);
+        p->tmp1[i].i = mag * sin(ph);
+    }
+
+    kiss_fftri(p->ifft, p->tmp1, buf);
+
+    for (i = 0; i < windowsize; i++) {
+        buf[i] *= window[i];
+        if (i < half_windowsize) {
+            output[i] = (SPFLOAT)(buf[i] + old_windowed_buf[half_windowsize + i]) / windowsize;
+            output[i] *= hinv_buf[i];
+        }
+        old_windowed_buf[i] = buf[i];
+    }
+    p->start_pos += p->displace_pos;
+}
+
+int sp_paulstretch_create(sp_paulstretch **p)
+{
+    *p = malloc(sizeof(sp_paulstretch));
+    return SP_OK;
+}
+
+int sp_paulstretch_destroy(sp_paulstretch **p)
+{
+    sp_paulstretch *pp = *p;
+    sp_auxdata_free(&pp->m_window);
+    sp_auxdata_free(&pp->m_old_windowed_buf);
+    sp_auxdata_free(&pp->m_hinv_buf);
+    sp_auxdata_free(&pp->m_buf);
+    sp_auxdata_free(&pp->m_output);
+    kiss_fftr_free(pp->fft);
+    kiss_fftr_free(pp->ifft);
+    KISS_FFT_FREE(pp->tmp1);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_paulstretch_init(sp_data *sp, sp_paulstretch *p, sp_ftbl *ft, SPFLOAT windowsize, SPFLOAT stretch)
+{
+    uint32_t i;
+    SPFLOAT hinv_sqrt2;
+    kiss_fft_cpx *tmp1;
+
+    p->ft = ft;
+    p->windowsize = (uint32_t)(sp->sr * windowsize);
+    p->stretch = stretch;
+
+    if (p->windowsize < 16) p->windowsize = 16;
+
+    p->half_windowsize = p->windowsize / 2;
+    p->displace_pos = (p->windowsize * 0.5) / p->stretch;
+
+    sp_auxdata_alloc(&p->m_window, sizeof(SPFLOAT) * p->windowsize);
+    p->window = p->m_window.ptr;
+
+    sp_auxdata_alloc(&p->m_old_windowed_buf, sizeof(SPFLOAT) * p->windowsize);
+    p->old_windowed_buf = p->m_old_windowed_buf.ptr;
+
+    sp_auxdata_alloc(&p->m_hinv_buf, sizeof(SPFLOAT) * p->half_windowsize);
+    p->hinv_buf = p->m_hinv_buf.ptr;
+
+    sp_auxdata_alloc(&p->m_buf, sizeof(SPFLOAT) * p->windowsize);
+    p->buf = p->m_buf.ptr;
+
+    sp_auxdata_alloc(&p->m_output, sizeof(SPFLOAT) * p->half_windowsize);
+    p->output = p->m_output.ptr;
+
+    /* Create Hann window */
+    for (i = 0; i < p->windowsize; i++) {
+        p->window[i] = 0.5 - cos(i * 2.0 * M_PI / (p->windowsize - 1)) * 0.5;
+    }
+    /* creatve inverse hann window */
+    hinv_sqrt2 = (1 + sqrt(0.5)) * 0.5;
+    for (i = 0; i < p->half_windowsize; i++) {
+        p->hinv_buf[i] = hinv_sqrt2 - (1.0 - hinv_sqrt2) * cos(i * 2.0 * M_PI / p->half_windowsize);
+    }
+
+    p->start_pos = 0.0;
+    p->counter = 0;
+
+    /* set up kissfft */
+    p->fft = kiss_fftr_alloc(p->windowsize, 0, NULL, NULL);
+    p->ifft = kiss_fftr_alloc(p->windowsize, 1, NULL, NULL);
+    tmp1 = malloc(sizeof(kiss_fft_cpx) * p->windowsize);
+    memset(tmp1, 0, sizeof(SPFLOAT) * p->windowsize);
+    p->tmp1 = tmp1;
+
+    /* turn on wrap mode by default */
+    p->wrap = 1;
+    return SP_OK;
+}
+
+int sp_paulstretch_compute(sp_data *sp, sp_paulstretch *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (p->counter == 0) compute_block(sp, p);
+
+    *out = p->output[p->counter];
+    p->counter = (p->counter + 1) % p->half_windowsize;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/peakeq.c
@@ -1,0 +1,47 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#define SK_PEAKEQ_PRIV
+#include "tangled/peakeq.h"
+#include "soundpipe.h"
+
+int sp_peakeq_create(sp_peakeq **p)
+{
+    *p = malloc(sizeof(sp_peakeq));
+    return SP_OK;
+}
+
+int sp_peakeq_destroy(sp_peakeq **p)
+{
+    sp_peakeq *pp;
+    pp = *p;
+    free(pp->peakeq);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_peakeq_init(sp_data *sp, sp_peakeq *p)
+{
+    p->peakeq = malloc(sizeof(sk_peakeq));
+    sk_peakeq_init(p->peakeq, sp->sr);
+    p->freq = 1000;
+    p->bw = 125;
+    p->gain  = 2;
+
+    sk_peakeq_freq(p->peakeq, p->freq);
+    sk_peakeq_bandwidth(p->peakeq, p->bw);
+    sk_peakeq_gain(p->peakeq, p->gain);
+    return SP_OK;
+}
+
+int sp_peakeq_compute(sp_data *sp, sp_peakeq *p,
+                         SPFLOAT *in, SPFLOAT *out)
+{
+    sk_peakeq_freq(p->peakeq, p->freq);
+    sk_peakeq_bandwidth(p->peakeq, p->bw);
+    sk_peakeq_gain(p->peakeq, p->gain);
+    *out = sk_peakeq_tick(p->peakeq, *in);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/peaklim.c
@@ -1,0 +1,80 @@
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef dB
+/* if below -100dB, set to -100dB to prevent taking log of zero */
+#define dB(x) 20.0 * ((x) > 0.00001 ? log10(x) : log10(0.00001))
+#endif
+
+#ifndef dB2lin
+#define dB2lin(x)           pow( 10.0, (x) / 20.0 )
+#endif
+
+int sp_peaklim_create(sp_peaklim **p)
+{
+    *p = malloc(sizeof(sp_peaklim));
+    return SP_OK;
+}
+
+int sp_peaklim_destroy(sp_peaklim **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_peaklim_init(sp_data *sp, sp_peaklim *p)
+{
+    p->a1_r = 0;
+    p->b0_r = 1;
+    p->a1_a = 0;
+    p->b0_a = 1;
+    p->atk = 0.1;
+    p->rel = 0.1;
+    p->patk = -100;
+    p->prel = -100;
+    p->level = 0;
+    return SP_OK;
+}
+
+int sp_peaklim_compute(sp_data *sp, sp_peaklim *p, SPFLOAT *in, SPFLOAT *out)
+{
+
+    SPFLOAT db_gain = 0;
+    SPFLOAT gain = 0;
+
+    /* change coefficients, if needed */
+
+    if (p->patk != p->atk) {
+        p->patk = p->atk;
+		p->a1_a = exp( -1.0 / ( p->rel * sp->sr ) );
+		p->b0_a = 1 - p->a1_a;
+    }
+
+    if (p->prel != p->rel) {
+        p->prel = p->rel;
+		p->a1_r = exp( -1.0 / ( p->rel * sp->sr ) );
+		p->b0_r = 1 - p->a1_r;
+    }
+
+
+    if ( fabs(*in) > p->level)
+        p->level += p->b0_a * ( fabs(*in) - p->level);
+    else
+        p->level += p->b0_r * ( fabs(*in) - p->level);
+
+    db_gain = min(0.0, dB(dB2lin(p->thresh)/p->level));
+    gain = dB2lin(db_gain);
+
+    *out = *in * gain;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/phaser.c
@@ -1,0 +1,367 @@
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+static float faustpower2_f(float value) {
+	return (value * value);
+
+}
+static float faustpower3_f(float value) {
+	return ((value * value) * value);
+
+}
+static float faustpower4_f(float value) {
+	return (((value * value) * value) * value);
+
+}
+
+typedef struct {
+
+	float fRec4[3];
+	float fRec3[3];
+	float fRec2[3];
+	float fRec1[3];
+	float fRec11[3];
+	float fRec10[3];
+	float fRec9[3];
+	float fRec8[3];
+	int iVec0[2];
+	float fRec5[2];
+	float fRec6[2];
+	float fRec0[2];
+	float fRec7[2];
+	FAUSTFLOAT fHslider0;
+	FAUSTFLOAT fCheckbox0;
+	FAUSTFLOAT fHslider1;
+	int fSamplingFreq;
+	int iConst0;
+	float fConst1;
+	FAUSTFLOAT fHslider2;
+	FAUSTFLOAT fHslider3;
+	FAUSTFLOAT fHslider4;
+	FAUSTFLOAT fHslider5;
+	float fConst2;
+	FAUSTFLOAT fHslider6;
+	FAUSTFLOAT fHslider7;
+	FAUSTFLOAT fCheckbox1;
+
+} phaser;
+
+phaser* newphaser() {
+	phaser* dsp = (phaser*)malloc(sizeof(phaser));
+	return dsp;
+}
+
+void deletephaser(phaser* dsp) {
+	free(dsp);
+}
+
+void instanceInitphaser(phaser* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->fHslider0 = (FAUSTFLOAT)0.;
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 2); i0 = (i0 + 1)) {
+			dsp->iVec0[i0] = 0;
+
+		}
+
+	}
+	dsp->fCheckbox0 = (FAUSTFLOAT)0.;
+	dsp->fHslider1 = (FAUSTFLOAT)1.;
+	dsp->iConst0 = min(192000, max(1, dsp->fSamplingFreq));
+	dsp->fConst1 = (1.f / (float)dsp->iConst0);
+	dsp->fHslider2 = (FAUSTFLOAT)1000.;
+	dsp->fHslider3 = (FAUSTFLOAT)1.5;
+	dsp->fHslider4 = (FAUSTFLOAT)100.;
+	dsp->fHslider5 = (FAUSTFLOAT)800.;
+	dsp->fConst2 = (0.10472f / (float)dsp->iConst0);
+	dsp->fHslider6 = (FAUSTFLOAT)30.;
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec5[i1] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 2); i2 = (i2 + 1)) {
+			dsp->fRec6[i2] = 0.f;
+
+		}
+
+	}
+	dsp->fHslider7 = (FAUSTFLOAT)0.;
+	/* C99 loop */
+	{
+		int i3;
+		for (i3 = 0; (i3 < 3); i3 = (i3 + 1)) {
+			dsp->fRec4[i3] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i4;
+		for (i4 = 0; (i4 < 3); i4 = (i4 + 1)) {
+			dsp->fRec3[i4] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i5;
+		for (i5 = 0; (i5 < 3); i5 = (i5 + 1)) {
+			dsp->fRec2[i5] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i6;
+		for (i6 = 0; (i6 < 3); i6 = (i6 + 1)) {
+			dsp->fRec1[i6] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i7;
+		for (i7 = 0; (i7 < 2); i7 = (i7 + 1)) {
+			dsp->fRec0[i7] = 0.f;
+
+		}
+
+	}
+	dsp->fCheckbox1 = (FAUSTFLOAT)0.;
+	/* C99 loop */
+	{
+		int i8;
+		for (i8 = 0; (i8 < 3); i8 = (i8 + 1)) {
+			dsp->fRec11[i8] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i9;
+		for (i9 = 0; (i9 < 3); i9 = (i9 + 1)) {
+			dsp->fRec10[i9] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i10;
+		for (i10 = 0; (i10 < 3); i10 = (i10 + 1)) {
+			dsp->fRec9[i10] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i11;
+		for (i11 = 0; (i11 < 3); i11 = (i11 + 1)) {
+			dsp->fRec8[i11] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i12;
+		for (i12 = 0; (i12 < 2); i12 = (i12 + 1)) {
+			dsp->fRec7[i12] = 0.f;
+
+		}
+
+	}
+
+}
+
+void initphaser(phaser* dsp, int samplingFreq) {
+	instanceInitphaser(dsp, samplingFreq);
+}
+
+void buildUserInterfacephaser(phaser* dsp, UIGlue* interface) {
+	interface->addHorizontalSlider(interface->uiInterface, "MaxNotch1Freq", &dsp->fHslider5, 800.f, 20.f, 10000.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "MinNotch1Freq", &dsp->fHslider4, 100.f, 20.f, 5000.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "Notch width", &dsp->fHslider2, 1000.f, 10.f, 5000.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "NotchFreq", &dsp->fHslider3, 1.5f, 1.1f, 4.f, 0.01f);
+	interface->addCheckButton(interface->uiInterface, "VibratoMode", &dsp->fCheckbox0);
+	interface->addHorizontalSlider(interface->uiInterface, "depth", &dsp->fHslider1, 1.f, 0.f, 1.f, 0.01f);
+	interface->addHorizontalSlider(interface->uiInterface, "feedback gain", &dsp->fHslider7, 0.f, 0.f, 1.f, 0.01f);
+	interface->addCheckButton(interface->uiInterface, "invert", &dsp->fCheckbox1);
+	interface->addHorizontalSlider(interface->uiInterface, "level", &dsp->fHslider0, 0.f, -60.f, 10.f, 0.1f);
+	interface->addHorizontalSlider(interface->uiInterface, "lfobpm", &dsp->fHslider6, 30.f, 24.f, 360.f, 1.f);
+}
+
+void computephaser(phaser* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* input0 = inputs[0];
+	FAUSTFLOAT* input1 = inputs[1];
+	FAUSTFLOAT* output0 = outputs[0];
+	FAUSTFLOAT* output1 = outputs[1];
+	float fSlow0 = pow(10.f, (0.05f * (float)dsp->fHslider0));
+	float fSlow1 = (0.5f * ((int)(float)dsp->fCheckbox0?2.f:(float)dsp->fHslider1));
+	float fSlow2 = (1.f - fSlow1);
+	float fSlow3 = exp((dsp->fConst1 * (0.f - (3.14159f * (float)dsp->fHslider2))));
+	float fSlow4 = faustpower2_f(fSlow3);
+	float fSlow5 = (0.f - (2.f * fSlow3));
+	float fSlow6 = (float)dsp->fHslider3;
+	float fSlow7 = (dsp->fConst1 * fSlow6);
+	float fSlow8 = (float)dsp->fHslider4;
+	float fSlow9 = (6.28319f * fSlow8);
+	float fSlow10 = (0.5f * ((6.28319f * max(fSlow8, (float)dsp->fHslider5)) - fSlow9));
+	float fSlow11 = (dsp->fConst2 * (float)dsp->fHslider6);
+	float fSlow12 = sin(fSlow11);
+	float fSlow13 = cos(fSlow11);
+	float fSlow14 = (0.f - fSlow12);
+	float fSlow15 = (float)dsp->fHslider7;
+	float fSlow16 = (dsp->fConst1 * faustpower2_f(fSlow6));
+	float fSlow17 = (dsp->fConst1 * faustpower3_f(fSlow6));
+	float fSlow18 = (dsp->fConst1 * faustpower4_f(fSlow6));
+	float fSlow19 = ((int)(float)dsp->fCheckbox1?(0.f - fSlow1):fSlow1);
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			dsp->iVec0[0] = 1;
+			float fTemp0 = (float)input0[i];
+			dsp->fRec5[0] = ((fSlow12 * dsp->fRec6[1]) + (fSlow13 * dsp->fRec5[1]));
+			dsp->fRec6[0] = ((1.f + ((fSlow13 * dsp->fRec6[1]) + (fSlow14 * dsp->fRec5[1]))) - (float)dsp->iVec0[1]);
+			float fTemp1 = ((fSlow10 * (1.f - dsp->fRec5[0])) + fSlow9);
+			float fTemp2 = (dsp->fRec4[1] * cos((fSlow7 * fTemp1)));
+			dsp->fRec4[0] = (0.f - (((fSlow5 * fTemp2) + (fSlow4 * dsp->fRec4[2])) - ((fSlow0 * fTemp0) + (fSlow15 * dsp->fRec0[1]))));
+			float fTemp3 = (dsp->fRec3[1] * cos((fSlow16 * fTemp1)));
+			dsp->fRec3[0] = ((fSlow5 * (fTemp2 - fTemp3)) + (dsp->fRec4[2] + (fSlow4 * (dsp->fRec4[0] - dsp->fRec3[2]))));
+			float fTemp4 = (dsp->fRec2[1] * cos((fSlow17 * fTemp1)));
+			dsp->fRec2[0] = ((fSlow5 * (fTemp3 - fTemp4)) + (dsp->fRec3[2] + (fSlow4 * (dsp->fRec3[0] - dsp->fRec2[2]))));
+			float fTemp5 = (dsp->fRec1[1] * cos((fSlow18 * fTemp1)));
+			dsp->fRec1[0] = ((fSlow5 * (fTemp4 - fTemp5)) + (dsp->fRec2[2] + (fSlow4 * (dsp->fRec2[0] - dsp->fRec1[2]))));
+			dsp->fRec0[0] = ((fSlow4 * dsp->fRec1[0]) + ((fSlow5 * fTemp5) + dsp->fRec1[2]));
+			output0[i] = (FAUSTFLOAT)((fSlow0 * (fSlow2 * fTemp0)) + (dsp->fRec0[0] * fSlow19));
+			float fTemp6 = (float)input1[i];
+			float fTemp7 = ((fSlow10 * (1.f - dsp->fRec6[0])) + fSlow9);
+			float fTemp8 = (dsp->fRec11[1] * cos((fSlow7 * fTemp7)));
+			dsp->fRec11[0] = (0.f - (((fSlow5 * fTemp8) + (fSlow4 * dsp->fRec11[2])) - ((fSlow0 * fTemp6) + (fSlow15 * dsp->fRec7[1]))));
+			float fTemp9 = (dsp->fRec10[1] * cos((fSlow16 * fTemp7)));
+			dsp->fRec10[0] = ((fSlow5 * (fTemp8 - fTemp9)) + (dsp->fRec11[2] + (fSlow4 * (dsp->fRec11[0] - dsp->fRec10[2]))));
+			float fTemp10 = (dsp->fRec9[1] * cos((fSlow17 * fTemp7)));
+			dsp->fRec9[0] = ((fSlow5 * (fTemp9 - fTemp10)) + (dsp->fRec10[2] + (fSlow4 * (dsp->fRec10[0] - dsp->fRec9[2]))));
+			float fTemp11 = (dsp->fRec8[1] * cos((fSlow18 * fTemp7)));
+			dsp->fRec8[0] = ((fSlow5 * (fTemp10 - fTemp11)) + (dsp->fRec9[2] + (fSlow4 * (dsp->fRec9[0] - dsp->fRec8[2]))));
+			dsp->fRec7[0] = ((fSlow4 * dsp->fRec8[0]) + ((fSlow5 * fTemp11) + dsp->fRec8[2]));
+			output1[i] = (FAUSTFLOAT)((fSlow0 * (fSlow2 * fTemp6)) + (dsp->fRec7[0] * fSlow19));
+			dsp->iVec0[1] = dsp->iVec0[0];
+			dsp->fRec5[1] = dsp->fRec5[0];
+			dsp->fRec6[1] = dsp->fRec6[0];
+			dsp->fRec4[2] = dsp->fRec4[1];
+			dsp->fRec4[1] = dsp->fRec4[0];
+			dsp->fRec3[2] = dsp->fRec3[1];
+			dsp->fRec3[1] = dsp->fRec3[0];
+			dsp->fRec2[2] = dsp->fRec2[1];
+			dsp->fRec2[1] = dsp->fRec2[0];
+			dsp->fRec1[2] = dsp->fRec1[1];
+			dsp->fRec1[1] = dsp->fRec1[0];
+			dsp->fRec0[1] = dsp->fRec0[0];
+			dsp->fRec11[2] = dsp->fRec11[1];
+			dsp->fRec11[1] = dsp->fRec11[0];
+			dsp->fRec10[2] = dsp->fRec10[1];
+			dsp->fRec10[1] = dsp->fRec10[0];
+			dsp->fRec9[2] = dsp->fRec9[1];
+			dsp->fRec9[1] = dsp->fRec9[0];
+			dsp->fRec8[2] = dsp->fRec8[1];
+			dsp->fRec8[1] = dsp->fRec8[0];
+			dsp->fRec7[1] = dsp->fRec7[0];
+
+		}
+
+	}
+
+}
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_phaser *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+static void addCheckButton (void* ui_interface, const char* label, FAUSTFLOAT* zone)
+{
+    sp_phaser *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_phaser_create(sp_phaser **p)
+{
+    *p = malloc(sizeof(sp_phaser));
+    return SP_OK;
+}
+
+int sp_phaser_destroy(sp_phaser **p)
+{
+    sp_phaser *pp = *p;
+    phaser *dsp = pp->faust;
+    deletephaser (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_phaser_init(sp_data *sp, sp_phaser *p)
+{
+    phaser *dsp = newphaser();
+    UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.addCheckButton = addCheckButton;
+    UI.uiInterface = p;
+    buildUserInterfacephaser(dsp, &UI);
+    initphaser(dsp, sp->sr);
+
+
+    p->MaxNotch1Freq = p->args[0];
+    p->MinNotch1Freq = p->args[1];
+    p->Notch_width = p->args[2];
+    p->NotchFreq = p->args[3];
+    p->VibratoMode = p->args[4];
+    p->depth = p->args[5];
+    p->feedback_gain = p->args[6];
+    p->invert = p->args[7];
+    p->level = p->args[8];
+    p->lfobpm = p->args[9];
+
+    p->faust = dsp;
+    return SP_OK;
+}
+
+int sp_phaser_compute(sp_data *sp, sp_phaser *p,
+	SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out1, SPFLOAT *out2)
+{
+    phaser *dsp = p->faust;
+    SPFLOAT *faust_out[] = {out1, out2};
+    SPFLOAT *faust_in[] = {in1, in2};
+    computephaser(dsp, 1, faust_in, faust_out);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/phasewarp.c
@@ -1,0 +1,31 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#include "tangled/phasewarp.h"
+#include "soundpipe.h"
+
+int sp_phasewarp_create(sp_phasewarp **p)
+{
+    *p = malloc(sizeof(sp_phasewarp));
+    return SP_OK;
+}
+
+int sp_phasewarp_destroy(sp_phasewarp **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_phasewarp_init(sp_data *sp, sp_phasewarp *p)
+{
+    return SP_OK;
+}
+
+int sp_phasewarp_compute(sp_data *sp, sp_phasewarp *p,
+                         SPFLOAT *in, SPFLOAT *out)
+{
+    *out = sk_phasewarp_tick(*in, p->amount);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/phasor.c
@@ -1,0 +1,52 @@
+/*
+ * Phasor
+ *
+ * A phasor produces a non-bandlimited sawtooth wave,
+ * normalized to be in range 0-1. Phasors are most
+ * frequently used to create table-lookup oscillators.
+ */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_phasor_create(sp_phasor **p)
+{
+    *p = malloc(sizeof(sp_phasor));
+    return SP_OK;
+}
+
+int sp_phasor_destroy(sp_phasor **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_phasor_init(sp_data *sp, sp_phasor *p, SPFLOAT iphs)
+{
+    p->freq = 440;
+    p->phs = iphs;
+    p->onedsr = 1.0 / sp->sr;
+    return SP_OK;
+}
+
+int sp_phasor_compute(sp_data *sp, sp_phasor *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT phs;
+    SPFLOAT incr;
+
+    phs = p->phs;
+    incr = p->freq * p->onedsr;
+
+    *out = phs;
+
+    phs += incr;
+
+    if (phs >= 1.0) {
+        phs -= 1.0;
+    } else if (phs < 0.0) {
+        phs += 1.0;
+    }
+
+    p->phs = phs;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/pinknoise.c
@@ -1,0 +1,71 @@
+/*
+ * Pinknoise
+ *
+ * This code has been extracted the pink noise synthesizer from Protrekkr
+ * It has been modified to work as a Soundpipe module.
+ *
+ * Original Author(s): McCartney, Juan Antonio Arguelles
+ * Location: release/distrib/replay/lib/replay.cpp
+ *
+ */
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+
+static uint32_t ctz[64] =
+{
+    6, 0, 1, 0, 2, 0, 1, 0,
+    3, 0, 1, 0, 2, 0, 1, 0,
+    4, 0, 1, 0, 2, 0, 1, 0,
+    3, 0, 1, 0, 2, 0, 1, 0,
+    5, 0, 1, 0, 2, 0, 1, 0,
+    3, 0, 1, 0, 2, 0, 1, 0,
+    4, 0, 1, 0, 2, 0, 1, 0,
+    3, 0, 1, 0, 2, 0, 1, 0,
+};
+
+int sp_pinknoise_create(sp_pinknoise **p)
+{
+    *p = malloc(sizeof(sp_pinknoise));
+    return SP_OK;
+}
+
+int sp_pinknoise_destroy(sp_pinknoise **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_pinknoise_init(sp_data *sp, sp_pinknoise *p)
+{
+    int i;
+
+    p->amp = 1.0;
+    p->seed = sp_rand(sp);
+    p->total = 0;
+    p->counter = 0;
+
+    for (i = 0; i < 7; i++) p->dice[i] = 0;
+
+    return SP_OK;
+}
+
+int sp_pinknoise_compute(sp_data *sp, sp_pinknoise *p, SPFLOAT *in, SPFLOAT *out)
+{
+    short tmp;
+    uint32_t k;
+    k = ctz[p->counter & 63];
+    p->prevrand = p->dice[k];
+    p->seed = 1664525 * p->seed + 1013904223;
+    p->newrand = p->seed >> 3;
+    p->dice[k] = p->newrand;
+    p->total += (p->newrand - p->prevrand);
+    p->seed = 1103515245 * p->seed + 12345;
+    p->newrand = p->seed >> 3;
+    tmp = (short) ((((p->total + p->newrand) * (1.0f / (3 << 29)) - 1) - .25f) * 16384.0f);
+
+    *out = ((SPFLOAT) tmp / 32767) * p->amp;
+    p->counter = (p->counter + 1) % 0xFFFFFFFF;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/prop.c
@@ -1,0 +1,573 @@
+/*
+ * Tinyprop
+ * By Paul Batchelor
+ *
+ * A tiny C implementation of prop, a proportional rhythmic notation system
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+typedef struct {
+    uint32_t size;
+    prop_list **ar;
+} prop_slice;
+
+static int prop_create(prop_data **pd);
+static int prop_parse(prop_data *pd, const char *str);
+static prop_event prop_next(sp_data *sp, prop_data *pd);
+static float prop_time(prop_data *pd, prop_event evt);
+static int prop_destroy(prop_data **pd);
+
+static int prop_val_free(prop_val val);
+static int prop_list_init(prop_list *lst);
+static int prop_list_destroy(prop_list *lst);
+static int prop_list_append(prop_list *lst, prop_val val);
+static void prop_list_reset(prop_list *lst);
+static int prop_list_copy(prop_list *src, prop_list **dst);
+
+static void mode_insert_event(prop_data *pd, char type);
+static void mode_insert_slice(prop_data *pd);
+static void mode_list_start(prop_data *pd);
+static void mode_list_end(prop_data *pd);
+static void prop_slice_encap(prop_data *pd);
+static void prop_slice_append(prop_data *pd);
+static void reset(prop_data *pd);
+static void back_to_top(prop_data *pd);
+
+enum {
+PTYPE_SLICE,
+PTYPE_LIST,
+PTYPE_EVENT,
+PTYPE_OFF,
+PTYPE_ON,
+PTYPE_MAYBE,
+PMODE_INSERT,
+PMODE_SETDIV,
+PMODE_SETMUL,
+PMODE_UNSETMUL,
+PMODE_INIT,
+PSTATUS_NOTOK,
+PSTATUS_OK,
+PTYPE_NULL
+};
+
+int sp_prop_create(sp_prop **p)
+{
+    *p = malloc(sizeof(sp_prop));
+    return SP_OK;
+}
+
+int sp_prop_destroy(sp_prop **p)
+{
+    sp_prop *pp = *p;
+    prop_destroy(&pp->prp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_prop_init(sp_data *sp, sp_prop *p, const char *str)
+{
+    p->count = 0;
+
+    prop_create(&p->prp);
+
+    if (prop_parse(p->prp, str) == PSTATUS_NOTOK) {
+        fprintf(stderr,"There was an error parsing the string.\n");
+        return SP_NOT_OK;
+    }
+
+    p->bpm = 60;
+    p->lbpm = 60;
+    return SP_OK;
+}
+
+int sp_prop_compute(sp_data *sp, sp_prop *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (p->count == 0) {
+        if (p->bpm != p->lbpm) {
+            p->prp->scale = (SPFLOAT) 60.0 / p->bpm;
+            p->lbpm = p->bpm;
+        }
+
+        p->evt = prop_next(sp, p->prp);
+        p->count = prop_time(p->prp, p->evt) * sp->sr;
+
+        switch (p->evt.type) {
+            case PTYPE_ON:
+                *out = 1.0;
+                break;
+            case PTYPE_MAYBE:
+                if (((SPFLOAT) sp_rand(sp) / SP_RANDMAX) > 0.5) *out = 1.0;
+                else *out = 0.0;
+                break;
+            default:
+                *out = 0.0;
+                break;
+        }
+        return SP_OK;
+    }
+
+    *out = 0;
+    p->count--;
+
+    return SP_OK;
+}
+
+static int stack_push(prop_stack *ps, uint32_t val)
+{
+    if (ps->pos++ < 16) {
+        ps->stack[ps->pos] = val;
+    }
+    return SP_OK;
+}
+
+static void stack_init(prop_stack *ps)
+{
+    int n;
+    ps->pos = -1;
+    for (n = 0; n < 16; n++) ps->stack[n] = 1;
+}
+
+static uint32_t stack_pop(prop_stack *ps)
+{
+    if (ps->pos >= 0) {
+        return ps->stack[ps->pos--];
+    }
+    return 1;
+}
+
+static void mode_insert_event(prop_data *pd, char type)
+{
+    prop_val val;
+    prop_event *evt;
+#ifdef DEBUG_PROP
+    if (type == PTYPE_ON) {
+        printf("mode_insert: PTYPE_ON\n");
+    } else {
+        printf("mode_insert: PTYPE_OFF\n");
+    }
+    printf("\tval/mul = %d, pos = %d, cons = %d, div = %d\n",
+            pd->mul, pd->num, pd->cons_mul, pd->div);
+#endif
+
+    val.type = PTYPE_EVENT;
+    evt = malloc(sizeof(prop_event));
+    evt->type = type;
+    evt->val = pd->mul;
+    evt->cons = pd->cons_mul;
+    val.ud = evt;
+    prop_list_append(pd->main, val);
+}
+
+static void mode_setdiv(prop_data *pd, char n)
+{
+    if (pd->tmp == 0 && n == 0) n = 1;
+    pd->tmp *= 10;
+    pd->tmp += n;
+}
+
+static void mode_setmul(prop_data *pd)
+{
+    pd->mul *= pd->tmp;
+    pd->div = pd->tmp;
+    stack_push(&pd->mstack, pd->tmp);
+    pd->tmp = 0;
+}
+
+static void mode_unsetmul(prop_data *pd)
+{
+    uint32_t div = stack_pop(&pd->mstack);
+#ifdef DEBUG_PROP
+    printf("mul / div = %d / %d\n", pd->mul, div);
+#endif
+    pd->mul /= div;
+}
+
+static void mode_setcons(prop_data *pd)
+{
+    pd->cons_mul *= pd->tmp;
+    pd->cons_div = pd->tmp;
+    stack_push(&pd->cstack, pd->tmp);
+    pd->tmp = 0;
+}
+
+static void mode_unsetcons(prop_data *pd)
+{
+    uint32_t div = stack_pop(&pd->cstack);
+#ifdef DEBUG_PROP
+    printf("mul / div = %d / %d\n", pd->cons_mul, div);
+#endif
+    pd->cons_mul /= div;
+}
+
+static int prop_create(prop_data **pd)
+{
+    prop_data *pdp;
+    *pd = malloc(sizeof(prop_data));
+    pdp = *pd;
+
+    pdp->mul = 1;
+    pdp->div = 0;
+    pdp->scale = 1;
+    pdp->cons_mul = 1;
+    pdp->cons_div = 0;
+    pdp->mode = PMODE_INIT;
+    pdp->pos = 1;
+    pdp->main = &pdp->top;
+    pdp->main->lvl = 0;
+    pdp->tmp = 0;
+
+    stack_init(&pdp->mstack);
+    stack_init(&pdp->cstack);
+    prop_list_init(pdp->main);
+
+    return PSTATUS_OK;
+}
+
+static int prop_parse(prop_data *pd, const char *str)
+{
+    char c;
+
+    while (*str != 0) {
+        c = str[0];
+
+        switch(c) {
+            case '+':
+                mode_insert_event(pd, PTYPE_ON);
+                break;
+            case '?':
+                mode_insert_event(pd, PTYPE_MAYBE);
+                break;
+            case '-':
+                mode_insert_event(pd, PTYPE_OFF);
+                break;
+
+            case '0':
+                mode_setdiv(pd, 0);
+                break;
+            case '1':
+                mode_setdiv(pd, 1);
+                break;
+            case '2':
+                mode_setdiv(pd, 2);
+                break;
+            case '3':
+                mode_setdiv(pd, 3);
+                break;
+            case '4':
+                mode_setdiv(pd, 4);
+                break;
+            case '5':
+                mode_setdiv(pd, 5);
+                break;
+            case '6':
+                mode_setdiv(pd, 6);
+                break;
+            case '7':
+                mode_setdiv(pd, 7);
+                break;
+            case '8':
+                mode_setdiv(pd, 8);
+                break;
+            case '9':
+                mode_setdiv(pd, 9);
+                break;
+            case '(':
+                mode_setmul(pd);
+                break;
+            case ')':
+                mode_unsetmul(pd);
+                break;
+            case '[':
+                mode_setcons(pd);
+                break;
+            case ']':
+                mode_unsetcons(pd);
+                break;
+            case '|':
+                mode_insert_slice(pd);
+                break;
+            case '{':
+                mode_list_start(pd);
+                break;
+            case '}':
+                mode_list_end(pd);
+                break;
+            case ' ': break;
+            case '\n': break;
+            case '\t': break;
+
+            default:
+                return PSTATUS_NOTOK;
+        }
+        pd->pos++;
+        str++;
+    }
+    prop_list_reset(&pd->top);
+    pd->main = &pd->top;
+    return PSTATUS_OK;
+}
+
+prop_val prop_list_iterate(prop_list *lst)
+{
+    prop_val val;
+    if (lst->pos >= lst->size) {
+        prop_list_reset(lst);
+    }
+    val = lst->last->val;
+    lst->last = lst->last->next;
+    lst->pos++;
+    return val;
+}
+
+static void back_to_top(prop_data *pd)
+{
+    prop_list *lst = pd->main;
+    prop_list_reset(lst);
+    pd->main = lst->top;
+    reset(pd);
+}
+
+static void reset(prop_data *pd)
+{
+    prop_list *lst = pd->main;
+    if (lst->pos >= lst->size) {
+        back_to_top(pd);
+    }
+}
+
+prop_event prop_next(sp_data *sp, prop_data *pd)
+{
+/*
+    prop_list *lst = pd->main;
+
+    if(lst->pos >= lst->size) {
+        //prop_list_reset(lst);
+        pd->main = lst->top;
+    }
+*/
+    prop_list *lst;
+    prop_event *p;
+    prop_val val;
+
+    reset(pd);
+    lst = pd->main;
+    val = lst->last->val;
+
+    lst->last = lst->last->next;
+    lst->pos++;
+
+    switch (val.type) {
+        case PTYPE_SLICE: {
+            prop_slice *slice = (prop_slice *)val.ud;
+
+            uint32_t pos = floor(
+                ((SPFLOAT)sp_rand(sp) / SP_RANDMAX)
+                * slice->size);
+
+            pd->main = slice->ar[pos];
+            prop_list_reset(pd->main);
+            return prop_next(sp, pd);
+            break;
+        }
+        case PTYPE_LIST: {
+            prop_list *lst = (prop_list *)val.ud;
+            pd->main = lst;
+            prop_list_reset(pd->main);
+            return prop_next(sp, pd);
+            break;
+        }
+        default:
+            break;
+    }
+    p = (prop_event *)val.ud;
+    return *p;
+}
+
+static float prop_time(prop_data *pd, prop_event evt)
+{
+    float val = evt.cons * (pd->scale / evt.val);
+    return val;
+}
+
+static int prop_destroy(prop_data **pd)
+{
+    prop_data *pdp = *pd;
+
+    prop_list_destroy(&pdp->top);
+
+    free(*pd);
+    return PSTATUS_OK;
+}
+
+static int prop_list_init(prop_list *lst)
+{
+    lst->last = &lst->root;
+    lst->size = 0;
+    lst->pos = 0;
+    lst->root.val.type = PTYPE_NULL;
+    lst->top = lst;
+    return PSTATUS_OK;
+}
+
+static int prop_list_append(prop_list *lst, prop_val val)
+{
+    prop_entry *new;
+    new = malloc(sizeof(prop_entry));
+    new->val = val;
+    lst->last->next = new;
+    lst->last = new;
+    lst->size++;
+    return PSTATUS_OK;
+}
+
+static int prop_slice_free(prop_slice *slice)
+{
+    uint32_t i;
+    for (i = 0; i < slice->size; i++) {
+        prop_list_destroy(slice->ar[i]);
+        free(slice->ar[i]);
+    }
+    free(slice->ar);
+    return PSTATUS_OK;
+}
+
+static int prop_val_free(prop_val val)
+{
+    switch (val.type) {
+        case PTYPE_SLICE:
+            prop_slice_free((prop_slice *)val.ud);
+            free(val.ud);
+            break;
+        case PTYPE_LIST:
+            prop_list_destroy((prop_list *)val.ud);
+            free(val.ud);
+            break;
+        default:
+            free(val.ud);
+            break;
+    }
+    return PSTATUS_OK;
+}
+
+static int prop_list_destroy(prop_list *lst)
+{
+    prop_entry *entry = lst->root.next;
+    prop_entry *next;
+    uint32_t i;
+
+    for (i = 0; i < lst->size; i++) {
+        next = entry->next;
+        prop_val_free(entry->val);
+        free(entry);
+        entry = next;
+    }
+    return PSTATUS_OK;
+}
+
+static void prop_list_reset(prop_list *lst)
+{
+    lst->last = lst->root.next;
+    lst->pos = 0;
+}
+
+static void mode_insert_slice(prop_data *pd)
+{
+    prop_entry *entry;
+
+    entry = pd->main->top->last;
+    if (entry->val.type != PTYPE_SLICE) {
+        prop_slice_encap(pd);
+    } else {
+        prop_slice_append(pd);
+    }
+}
+
+static void prop_slice_encap(prop_data *pd)
+{
+    prop_val val;
+    prop_list *lst, *new;
+    prop_list *top;
+    prop_slice *slice;
+
+    top = pd->main->top;
+    val.type = PTYPE_SLICE;
+    slice = malloc(sizeof(prop_slice));
+    val.ud = slice;
+    prop_list_copy(pd->main, &lst);
+    new = malloc(sizeof(prop_list));
+    new->lvl = pd->main->lvl;
+    slice->size = 2;
+    slice->ar =
+        (prop_list **)malloc(sizeof(prop_list *) * slice->size);
+    slice->ar[0] = lst;
+    /* reinit main list */
+    prop_list_init(pd->main);
+    prop_list_append(pd->main, val);
+    slice->ar[1] = new;
+    prop_list_init(slice->ar[1]);
+    pd->main = slice->ar[1];
+
+    slice->ar[0]->top = top;
+    slice->ar[1]->top = top;
+}
+
+static void prop_slice_append(prop_data *pd)
+{
+    prop_entry *entry;
+    prop_slice *slice;
+    prop_list *new;
+
+    entry = pd->main->top->last;
+    slice = (prop_slice *)entry->val.ud;
+    new = malloc(sizeof(prop_list));
+    prop_list_init(new);
+    slice->size++;
+    slice->ar = (prop_list **)
+        realloc(slice->ar, sizeof(prop_list *) * slice->size);
+    slice->ar[slice->size - 1] = new;
+    new->top = pd->main->top;
+    pd->main = new;
+}
+
+static int prop_list_copy(prop_list *src, prop_list **dst)
+{
+    prop_list *pdst;
+    *dst = malloc(sizeof(prop_list));
+    pdst = *dst;
+    pdst->root = src->root;
+    pdst->last = src->last;
+    pdst->size = src->size;
+    pdst->pos = src->pos;
+    pdst->lvl = src->lvl;
+    return PSTATUS_OK;
+}
+
+static void mode_list_start(prop_data *pd)
+{
+    prop_val val;
+    prop_list *new;
+    val.type = PTYPE_LIST;
+    new = malloc(sizeof(prop_list));
+    prop_list_init(new);
+    new->lvl = pd->main->lvl + 1;
+    val.ud = new;
+    prop_list_append(pd->main, val);
+    new->top = pd->main;
+    pd->main = new;
+}
+
+static void mode_list_end(prop_data *pd)
+{
+    pd->main = pd->main->top;
+}
+
+int sp_prop_reset(sp_data *sp, sp_prop *p)
+{
+    back_to_top(p->prp);
+    p->count = 0;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/pshift.c
@@ -1,0 +1,153 @@
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT SPFLOAT
+#endif
+
+
+float powf(float dummy0, float dummy1);
+float fmodf(float dummy0, float dummy1);
+
+typedef struct {
+	float fVec0[65536];
+	float fRec0[2];
+	int IOTA;
+	FAUSTFLOAT fHslider0;
+	FAUSTFLOAT fHslider1;
+	FAUSTFLOAT fHslider2;
+	int fSamplingFreq;
+} pshift;
+
+static pshift* newpshift() {
+	pshift* dsp = (pshift*)malloc(sizeof(pshift));
+	return dsp;
+}
+
+static void deletepshift(pshift* dsp) {
+	free(dsp);
+}
+
+static void instanceInitpshift(pshift* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->IOTA = 0;
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 65536); i0 = (i0 + 1)) {
+			dsp->fVec0[i0] = 0.f;
+
+		}
+
+	}
+	dsp->fHslider0 = (FAUSTFLOAT)1000.;
+	dsp->fHslider1 = (FAUSTFLOAT)0.;
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec0[i1] = 0.f;
+
+		}
+
+	}
+	dsp->fHslider2 = (FAUSTFLOAT)10.;
+}
+
+static void initpshift(pshift* dsp, int samplingFreq) {
+	instanceInitpshift(dsp, samplingFreq);
+}
+
+static void buildUserInterfacepshift(pshift* dsp, UIGlue* interface) {
+	interface->addHorizontalSlider(interface->uiInterface, "shift", &dsp->fHslider1, 0.f, -24.f, 24.f, 0.1f);
+	interface->addHorizontalSlider(interface->uiInterface, "window", &dsp->fHslider0, 1000.f, 50.f, 10000.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "xfade", &dsp->fHslider2, 10.f, 1.f, 10000.f, 1.f);
+}
+
+static void computepshift(pshift* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* input0 = inputs[0];
+	FAUSTFLOAT* output0 = outputs[0];
+	float fSlow0 = (float)dsp->fHslider0;
+	float fSlow1 = ((1.f + fSlow0) - powf(2.f, (0.0833333f * (float)dsp->fHslider1)));
+	float fSlow2 = (1.f / (float)dsp->fHslider2);
+	float fSlow3 = (fSlow0 - 1.f);
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			float fTemp0 = (float)input0[i];
+			dsp->fVec0[(dsp->IOTA & 65535)] = fTemp0;
+			dsp->fRec0[0] = fmodf((dsp->fRec0[1] + fSlow1), fSlow0);
+			int iTemp1 = (int)dsp->fRec0[0];
+			int iTemp2 = (1 + iTemp1);
+			float fTemp3 = min((fSlow2 * dsp->fRec0[0]), 1.f);
+			float fTemp4 = (dsp->fRec0[0] + fSlow0);
+			int iTemp5 = (int)fTemp4;
+			output0[i] = (FAUSTFLOAT)((((dsp->fVec0[((dsp->IOTA - (iTemp1 & 65535)) & 65535)] * ((float)iTemp2 - dsp->fRec0[0])) + ((dsp->fRec0[0] - (float)iTemp1) * dsp->fVec0[((dsp->IOTA - (iTemp2 & 65535)) & 65535)])) * fTemp3) + (((dsp->fVec0[((dsp->IOTA - (iTemp5 & 65535)) & 65535)] * (0.f - ((dsp->fRec0[0] + fSlow3) - (float)iTemp5))) + ((fTemp4 - (float)iTemp5) * dsp->fVec0[((dsp->IOTA - ((1 + iTemp5) & 65535)) & 65535)])) * (1.f - fTemp3)));
+			dsp->IOTA = (dsp->IOTA + 1);
+			dsp->fRec0[1] = dsp->fRec0[0];
+
+		}
+
+	}
+
+}
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_pshift *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_pshift_create(sp_pshift **p)
+{
+    *p = malloc(sizeof(sp_pshift));
+    return SP_OK;
+}
+
+int sp_pshift_destroy(sp_pshift **p)
+{
+    sp_pshift *pp = *p;
+    pshift *dsp = pp->faust;
+    deletepshift (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_pshift_init(sp_data *sp, sp_pshift *p)
+{
+    pshift *dsp = newpshift();
+    UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.uiInterface = p;
+    buildUserInterfacepshift(dsp, &UI);
+    initpshift(dsp, sp->sr);
+
+
+    p->shift = p->args[0];
+    p->window = p->args[1];
+    p->xfade = p->args[2];
+
+    p->faust = dsp;
+    return SP_OK;
+}
+
+int sp_pshift_compute(sp_data *sp, sp_pshift *p, SPFLOAT *in, SPFLOAT *out)
+{
+
+    pshift *dsp = p->faust;
+    SPFLOAT out1 = 0;
+    SPFLOAT *faust_out[] = {&out1};
+    SPFLOAT *faust_in[] = {in};
+    computepshift(dsp, 1, faust_in, faust_out);
+
+    *out = out1;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/randh.c
@@ -1,0 +1,46 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_randh_create(sp_randh **p)
+{
+    *p = malloc(sizeof(sp_randh));
+    return SP_OK;
+}
+
+int sp_randh_destroy(sp_randh **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_randh_init(sp_data *sp, sp_randh *p)
+{
+    p->counter = 0;
+    p->freq = 10;
+    p->dur = (sp->sr / p->freq);
+    p->min = 0;
+    p->max = 1;
+    p->val = 0;
+    return SP_OK;
+}
+
+int sp_randh_compute(sp_data *sp, sp_randh *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (p->counter == 0) {
+        p->val = p->min + ((SPFLOAT) sp_rand(sp) / SP_RANDMAX) * (p->max - p->min);
+
+        if (p->freq == 0) {
+            p->dur = 1;
+        } else {
+            p->dur = (sp->sr / p->freq) + 1;
+        }
+
+        *out = p->val;
+    } else {
+        *out = p->val;
+    }
+    p->counter = (p->counter + 1) % p->dur;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/randmt.c
@@ -1,0 +1,133 @@
+/*
+   A C-program for MT19937, with initialisation improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote
+        products derived from this software without specific prior written
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.
+   IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+   ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+   IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+   POSSIBILITY OF SUCH DAMAGE.
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+#include "soundpipe.h"
+#define N           (624)
+#define M           (397)
+#define MATRIX_A    0x9908B0DFU     /* constant vector a */
+#define UPPER_MASK  0x80000000U     /* most significant w-r bits */
+#define LOWER_MASK  0x7FFFFFFFU     /* least significant r bits */
+
+static void MT_update_state(uint32_t *mt)
+{
+    /* mag01[x] = x * MATRIX_A  for x=0,1 */
+    const uint32_t  mag01[2] = { (uint32_t) 0, (uint32_t) MATRIX_A };
+    int       i;
+    uint32_t  y;
+
+    for (i = 0; i < (N - M); i++) {
+      y = (mt[i] & UPPER_MASK) | (mt[i + 1] & LOWER_MASK);
+      mt[i] = mt[i + M] ^ (y >> 1) ^ mag01[y & (uint32_t) 1];
+    }
+    for ( ; i < (N - 1); i++) {
+      y = (mt[i] & UPPER_MASK) | (mt[i + 1] & LOWER_MASK);
+      mt[i] = mt[i + (M - N)] ^ (y >> 1) ^ mag01[y & (uint32_t) 1];
+    }
+    y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
+    mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & (uint32_t) 1];
+}
+
+/* generates a random number on [0,0xffffffff]-interval */
+
+uint32_t sp_randmt_compute(sp_randmt *p)
+{
+    int       i = p->mti;
+    uint32_t  y;
+
+    if (i >= N) {                   /* generate N words at one time */
+      MT_update_state(&(p->mt[0]));
+      i = 0;
+    }
+    y = p->mt[i];
+    p->mti = i + 1;
+    /* Tempering */
+    y ^= (y >> 11);
+    y ^= (y << 7) & (uint32_t) 0x9D2C5680U;
+    y ^= (y << 15) & (uint32_t) 0xEFC60000U;
+    y ^= (y >> 18);
+
+    return y;
+}
+
+void sp_randmt_seed(sp_randmt *p,
+    const uint32_t *initKey, uint32_t keyLength)
+{
+    int       i, j, k;
+    uint32_t  x;
+
+    /* if array is NULL, use length parameter as simple 32 bit seed */
+    x = (initKey == NULL ? keyLength : (uint32_t) 19650218);
+    p->mt[0] = x;
+    for (i = 1; i < N; i++) {
+      /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+      /* In the previous versions, MSBs of the seed affect   */
+      /* only MSBs of the array mt[].                        */
+      /* 2002/01/09 modified by Makoto Matsumoto             */
+      x = ((uint32_t) 1812433253 * (x ^ (x >> 30)) + (uint32_t) i);
+      p->mt[i] = x;
+    }
+    p->mti = N;
+    if (initKey == NULL)
+      return;
+    i = 0; j = 0;
+    k = (N > (int) keyLength ? N : (int) keyLength);
+    for ( ; k; k--) {
+      x = p->mt[i++];
+      p->mt[i] = (p->mt[i] ^ ((x ^ (x >> 30)) * (uint32_t) 1664525))
+                 + initKey[j] + (uint32_t) j;   /* non linear */
+      if (i == (N - 1)) {
+        p->mt[0] = p->mt[N - 1];
+        i = 0;
+      }
+      if (++j >= (int) keyLength)
+        j = 0;
+    }
+    for (k = (N - 1); k; k--) {
+      x = p->mt[i++];
+      p->mt[i] = (p->mt[i] ^ ((x ^ (x >> 30)) * (uint32_t) 1566083941))
+                 - (uint32_t) i;                /* non linear */
+      if (i == (N - 1)) {
+        p->mt[0] = p->mt[N - 1];
+        i = 0;
+      }
+    }
+    /* MSB is 1; assuring non-zero initial array */
+    p->mt[0] = (uint32_t) 0x80000000U;
+}
--- /dev/null
+++ b/modules/random.c
@@ -1,0 +1,33 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_random_create(sp_random **p)
+{
+    *p = malloc(sizeof(sp_random));
+    return SP_OK;
+}
+
+int sp_random_destroy(sp_random **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_random_init(sp_data *sp, sp_random *p)
+{
+    p->min = -1;
+    p->max = 1;
+    return SP_OK;
+}
+
+int sp_random_compute(sp_data *sp, sp_random *p, SPFLOAT *in, SPFLOAT *out)
+{
+    /* Send the signal's input to the output */
+    SPFLOAT rnd = ((sp_rand(sp) % RAND_MAX) / (RAND_MAX * 1.0));
+    rnd *= (p->max - p->min);
+    rnd += p->min;
+    *out = rnd;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/reverse.c
@@ -1,0 +1,37 @@
+/* This code is placed in the public domain. */
+
+#include <string.h>
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_reverse_create(sp_reverse **p)
+{
+    *p = malloc(sizeof(sp_reverse));
+    return SP_OK;
+}
+
+int sp_reverse_destroy(sp_reverse **p)
+{
+    sp_reverse *pp = *p;
+    sp_auxdata_free(&pp->buf);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_reverse_init(sp_data *sp, sp_reverse *p, SPFLOAT delay)
+{
+    size_t size = delay * sp->sr * sizeof(SPFLOAT) * 2;
+    p->bufpos = 0;
+    sp_auxdata_alloc(&p->buf, size);
+    p->bufsize = (uint32_t)p->buf.size / sizeof(SPFLOAT);
+    return SP_OK;
+}
+
+int sp_reverse_compute(sp_data *sp, sp_reverse *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT *buf = (SPFLOAT *)p->buf.ptr;
+    *out = buf[p->bufpos];
+    buf[(p->bufsize - 1) - p->bufpos] = *in;
+    p->bufpos = (p->bufpos + 1) % p->bufsize;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/rline.c
@@ -1,0 +1,47 @@
+/* this file is placed in the public domain */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdint.h>
+#define SK_RLINE_PRIV
+#include "tangled/rline.h"
+#include "soundpipe.h"
+
+int sp_rline_create(sp_rline **p)
+{
+    *p = malloc(sizeof(sp_rline));
+    return SP_OK;
+}
+
+int sp_rline_destroy(sp_rline **p)
+{
+    sp_rline *pp;
+    pp = *p;
+    free(pp->rline);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_rline_init(sp_data *sp, sp_rline *p)
+{
+    p->rline = malloc(sizeof(sk_rline));
+    sk_rline_init(p->rline, sp->sr, sp_rand(sp));
+    p->min = 0;
+    p->max = 1;
+    p->cps = 3;
+
+    sk_rline_min(p->rline, p->min);
+    sk_rline_max(p->rline, p->max);
+    sk_rline_rate(p->rline, p->cps);
+    return SP_OK;
+}
+
+int sp_rline_compute(sp_data *sp, sp_rline *p,
+                         SPFLOAT *in, SPFLOAT *out)
+{
+    sk_rline_min(p->rline, p->min);
+    sk_rline_max(p->rline, p->max);
+    sk_rline_rate(p->rline, p->cps);
+    *out = sk_rline_tick(p->rline);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/rpt.c
@@ -1,0 +1,92 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+static int sp_rpt_set(sp_rpt *p, SPFLOAT bpm, int div, int rep);
+
+int sp_rpt_create(sp_rpt **p)
+{
+    *p = malloc(sizeof(sp_rpt));
+    return SP_OK;
+}
+
+int sp_rpt_destroy(sp_rpt **p)
+{
+    sp_rpt *pp = *p;
+    sp_auxdata_free(&pp->aux);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_rpt_init(sp_data *sp, sp_rpt *p, SPFLOAT maxdur)
+{
+    sp_auxdata_alloc(&p->aux, sizeof(SPFLOAT) * (uint32_t)maxdur * sp->sr);
+    p->playpos = 0;
+    p->bufpos = 0;
+    p->running = 0;
+    p->reps = 4;
+    p->count = p->reps;
+    p->size = (int)p->aux.size;
+    p->sr = sp->sr;
+    p->bpm = 130;
+    p->div = 4;
+    p->rep = 4;
+    p->rc = SP_OK;
+    return SP_OK;
+}
+
+int sp_rpt_compute(sp_data *sp, sp_rpt *p, SPFLOAT *trig,
+        SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT *buf = (SPFLOAT *)p->aux.ptr;
+
+    if (p->rc == SP_NOT_OK) {
+        *out = 0;
+        return SP_NOT_OK;
+    }
+
+    if (*trig > 0) {
+        p->rc = sp_rpt_set(p, p->bpm, p->div, p->rep);
+        p->running = 1;
+        p->playpos = 0;
+        p->bufpos = 0;
+        p->count = p->reps + 1;
+    }
+
+    if (p->bufpos * sizeof(SPFLOAT) < p->aux.size) {
+        p->rc = sp_rpt_set(p, p->bpm, p->div, p->rep);
+        buf[p->bufpos] = *in;
+        p->bufpos++;
+    } else {
+        p->running = 0;
+    }
+
+    if(p->running && p->count > 0) {
+        if (p->playpos == 0) {
+            p->count--;
+        }
+        *out = buf[p->playpos];
+        p->playpos = (p->playpos + 1) % p->size;
+    } else {
+        *out = *in;
+    }
+
+    return SP_OK;
+}
+
+static int sp_rpt_set(sp_rpt *p, SPFLOAT bpm, int div, int rep)
+{
+    uint32_t size = (p->sr * (60.0 / bpm)) / (SPFLOAT) div;
+    p->reps = rep;
+    if (size * sizeof(SPFLOAT) > p->aux.size) {
+        fprintf(stderr, "Error: not enough memory allocated for buffer.\n");
+        return SP_NOT_OK;
+    } else if(size <= 0) {
+        fprintf(stderr, "Error: Size cannot be zero.\n");
+        return SP_NOT_OK;
+    } else {
+        p->size = size;
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/samphold.c
@@ -1,0 +1,31 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_samphold_create(sp_samphold **p)
+{
+    *p = malloc(sizeof(sp_samphold));
+    return SP_OK;
+}
+
+int sp_samphold_destroy(sp_samphold **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_samphold_init(sp_data *sp, sp_samphold *p)
+{
+    p->val = 0;
+    return SP_OK;
+}
+
+int sp_samphold_compute(sp_data *sp, sp_samphold *p, SPFLOAT *trig, SPFLOAT *in, SPFLOAT *out)
+{
+    if(*trig != 0) {
+        p->val = *in;
+    }
+    *out = p->val;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/saturator.c
@@ -1,0 +1,109 @@
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+#ifndef M_PI
+#define M_PI    3.14159265358979323846
+#endif
+
+static void bilinear_transform(SPFLOAT acoefs[], SPFLOAT dcoefs[], SPFLOAT fs)
+{
+    SPFLOAT b0, b1, b2, a0, a1, a2;
+    SPFLOAT bz0, bz1, bz2, az0, az1, az2;
+
+    b0 = acoefs[0]; b1 = acoefs[1]; b2 = acoefs[2];
+    a0 = acoefs[3]; a1 = acoefs[4]; a2 = acoefs[5];
+
+    bz0 = 1.0; bz1 = 0.0; bz2 = 0.0;
+    az0 = 1.0; az1 = 0.0; az2 = 0.0;
+
+    az0 = a2*4*fs*fs + a1*2*fs + a0;
+
+    bz2 = (b2*4*fs*fs - b1*2*fs + b0) / az0;
+    bz1 = (-b2*8*fs*fs + 2*b0) / az0;
+    bz0 = (b2*4*fs*fs+ b1*2*fs + b0) / az0;
+    az2 = (a2*4*fs*fs - a1*2*fs + a0) / az0;
+    az1 = (-a2*8*fs*fs + 2*a0) / az0;
+
+    dcoefs[0] = bz0; dcoefs[1] = bz1; dcoefs[2] = bz2;
+    dcoefs[3] = az1; dcoefs[4] = az2;
+}
+
+int sp_saturator_create(sp_saturator **p)
+{
+    *p = malloc(sizeof(sp_saturator));
+    return SP_OK;
+}
+
+int sp_saturator_destroy(sp_saturator **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_saturator_init(sp_data *sp, sp_saturator *p)
+{
+    int i, j;
+    const SPFLOAT aacoefs[6][7] =
+    {
+        {2.60687e-05, 2.98697e-05, 2.60687e-05, -1.31885, 0.437162, 0.0, 0.0},
+        {1, -0.800256, 1, -1.38301, 0.496576, 0.0, 0.0},
+        {1, -1.42083, 1, -1.48787, 0.594413, 0.0, 0.0},
+        {1, -1.6374, 1, -1.60688, 0.707142, 0.0, 0.0},
+        {1, -1.7261, 1, -1.7253, 0.822156, 0.0, 0.0},
+        {1, -1.75999, 1, -1.84111, 0.938811, 0.0, 0.0}
+    };
+
+    SPFLOAT wc_dc = 5*2*M_PI;
+    SPFLOAT scoeffs[6] = {  0, 1, 0, wc_dc, 1, 0 };
+    SPFLOAT zcoeffs[5];
+    p->drive = 1;
+    p->dcoffset = 0;
+
+    for(i = 0; i < 6; i++){
+        for(j = 0; j < 7; j++){
+            p->aa[i][j] =  aacoefs[i][j];
+            p->ai[i][j] =  aacoefs[i][j];
+        }
+    }
+    bilinear_transform(scoeffs, zcoeffs, sp->sr*8);
+    for(i = 0; i < 2; i++){
+        for(j = 0; j < 5; j++)
+            p->dcblocker[i][j] = zcoeffs[j];
+        p->dcblocker[i][5] = 0.0;
+        p->dcblocker[i][6] = 0.0;
+    }
+        return SP_OK;
+}
+
+static int quad_compute(SPFLOAT p[7],  SPFLOAT *input, SPFLOAT* output)
+{
+    SPFLOAT in = *input;
+    *output = p[5] + in * p[0];
+    p[5] = p[6] + in * p[1] - *output*p[3];
+    p[6] = in * p[2] - *output*p[4];
+    return SP_OK;
+}
+
+
+int sp_saturator_compute(sp_data *sp, sp_saturator *p, SPFLOAT *in, SPFLOAT *out)
+{
+    int i, j;
+    SPFLOAT fsignal, usignal, dsignal;
+
+    fsignal = p->drive * *in;
+    for(i = 0; i < 8; i++){
+        usignal = (i == 0) ? 8 *fsignal : 0.0;
+        for(j = 0; j < 6; j++)
+            quad_compute(p->ai[j], &usignal, &usignal);
+
+        dsignal = (usignal + p->dcoffset) / (1.0 + fabs(usignal + p->dcoffset));
+
+        quad_compute(p->dcblocker[0], &dsignal, &dsignal);
+        quad_compute(p->dcblocker[1], &dsignal, &dsignal);
+
+        for(j = 0; j < 6; j++)
+            quad_compute(p->aa[j], &dsignal, out);
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/scale.c
@@ -1,0 +1,29 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_scale_create(sp_scale **p)
+{
+    *p = malloc(sizeof(sp_scale));
+    return SP_OK;
+}
+
+int sp_scale_destroy(sp_scale **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_scale_init(sp_data *sp, sp_scale *p)
+{
+    p->min = -1;
+    p->max = 1;
+    return SP_OK;
+}
+
+int sp_scale_compute(sp_data *sp, sp_scale *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out =  *in * (p->max - p->min) + p->min;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/scrambler.c
@@ -1,0 +1,65 @@
+/* This code is placed in the public domain. */
+
+#include <math.h>
+#include "soundpipe.h"
+#include "kiss_fftr.h"
+
+#ifndef M_PI
+#define M_PI		3.14159265358979323846
+#endif
+
+int sp_gen_scrambler(sp_data *sp, sp_ftbl *src, sp_ftbl **dest)
+{
+
+    uint32_t size;
+    sp_ftbl *dst;
+    kiss_fftr_cfg fft, ifft;
+    kiss_fft_cpx *tmp;
+    uint32_t i;
+    SPFLOAT mag, phs;
+    SPFLOAT max;
+    SPFLOAT val;
+
+    size = (src->size % 2 == 0) ? src->size : src->size - 1;
+    sp_ftbl_create(sp, &dst, size);
+
+    /* set up kissfft */
+    fft = kiss_fftr_alloc(size, 0, NULL, NULL);
+    ifft = kiss_fftr_alloc(size, 1, NULL, NULL);
+    tmp = malloc(sizeof(kiss_fft_cpx) * size);
+    memset(tmp, 0, sizeof(SPFLOAT) * size);
+    kiss_fftr(fft, src->tbl, tmp);
+
+    for(i = 0; i < size / 2; i++) {
+        mag = sqrt(tmp[i].r * tmp[i].r + tmp[i].i * tmp[i].i) / size;
+        phs = ((SPFLOAT)sp_rand(sp) / SP_RANDMAX) * 2 * M_PI;
+        tmp[i].r = mag * cos(phs);
+        tmp[i].i = mag * sin(phs);
+    }
+
+    tmp[0].r = 0;
+    tmp[0].i = 0;
+    tmp[size / 2 - 1].r = 0;
+    tmp[size / 2 - 1].i = 0;
+
+    kiss_fftri(ifft, tmp, dst->tbl);
+    max = -1;
+    val = 0;
+    for(i = 0; i < size; i++) {
+        val = fabs(dst->tbl[i]);
+        if(val > max) {
+            max = val;
+        }
+    }
+
+    for(i = 0; i < size; i++) {
+       dst->tbl[i] /= max;
+    }
+
+    kiss_fftr_free(fft);
+    kiss_fftr_free(ifft);
+    KISS_FFT_FREE(tmp);
+
+    *dest = dst;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/sdelay.c
@@ -1,0 +1,43 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_sdelay_create(sp_sdelay **p)
+{
+    sp_sdelay *pp;
+    *p = malloc(sizeof(sp_sdelay));
+    pp = *p;
+    pp->size = 0;
+    return SP_OK;
+}
+
+int sp_sdelay_destroy(sp_sdelay **p)
+{
+    sp_sdelay *pp = *p;
+
+    if(pp->size > 0) {
+        free(pp->buf);
+    }
+
+    free(*p);
+    return SP_OK;
+}
+
+int sp_sdelay_init(sp_data *sp, sp_sdelay *p, int size)
+{
+    int n;
+    p->size = size;
+    p->buf = malloc(size * sizeof(SPFLOAT));
+    for(n = 0; n < p->size; n++) p->buf[n] = 0;
+    p->pos = 0;
+    return SP_OK;
+}
+
+int sp_sdelay_compute(sp_data *sp, sp_sdelay *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = p->buf[p->pos];
+    p->buf[p->pos] = *in;
+    p->pos = (p->pos + 1) % p->size;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/slice.c
@@ -1,0 +1,48 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_slice_create(sp_slice **p)
+{
+    *p = malloc(sizeof(sp_slice));
+    return SP_OK;
+}
+
+int sp_slice_destroy(sp_slice **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_slice_init(sp_data *sp, sp_slice *p, sp_ftbl *vals, sp_ftbl *buf)
+{
+    p->vals = vals;
+    p->buf = buf;
+    p->pos = 0;
+    p->nextpos = 0;
+    p->id = 0;
+    return SP_OK;
+}
+
+int sp_slice_compute(sp_data *sp, sp_slice *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = 0;
+    if(*in != 0) {
+        if(p->id < p->vals->size) {
+            p->pos = p->vals->tbl[p->id];
+            if(p->id == p->vals->size - 1) {
+                p->nextpos = p->buf->size;
+            } else {
+                p->nextpos = p->vals->tbl[p->id + 1];
+            }
+        }
+    }
+
+    if(p->pos < p->nextpos) {
+        *out = p->buf->tbl[p->pos];
+        p->pos++;
+    }
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/smoothdelay.c
@@ -1,0 +1,122 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+#ifndef max
+#define max(a, b) ((a > b) ? a : b)
+#endif
+
+#ifndef min
+#define min(a, b) ((a < b) ? a : b)
+#endif
+
+
+int sp_smoothdelay_create(sp_smoothdelay **p)
+{
+    *p = malloc(sizeof(sp_smoothdelay));
+    return SP_OK;
+}
+
+int sp_smoothdelay_destroy(sp_smoothdelay **p)
+{
+    sp_smoothdelay *pp = *p;
+    sp_auxdata_free(&pp->buf1);
+    sp_auxdata_free(&pp->buf2);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_smoothdelay_init(sp_data *sp, sp_smoothdelay *p,
+        SPFLOAT maxdel, uint32_t interp)
+{
+    uint32_t n = (int32_t)(maxdel * sp->sr)+1;
+    p->sr = sp->sr;
+    p->del = maxdel * 0.5;
+    p->pdel = -1;
+    p->maxdel = maxdel;
+    p->feedback = 0;
+    p->maxbuf = n - 1;
+    p->maxcount = interp;
+
+    sp_auxdata_alloc(&p->buf1, n * sizeof(SPFLOAT));
+    p->bufpos1 = 0;
+    p->deltime1 = (uint32_t) (p->del * sp->sr);
+
+    sp_auxdata_alloc(&p->buf2, n * sizeof(SPFLOAT));
+    p->bufpos2 = 0;
+    p->deltime2 = p->deltime1;
+
+    p->counter = 0;
+    p->curbuf = 0;
+    return SP_OK;
+}
+
+static SPFLOAT delay_sig(SPFLOAT *buf,
+        uint32_t *bufpos,
+        uint32_t deltime,
+        SPFLOAT fdbk,
+        SPFLOAT in)
+{
+    SPFLOAT delay = buf[*bufpos];
+    SPFLOAT sig = (delay * fdbk) + in;
+    buf[*bufpos] = sig;
+    *bufpos = (*bufpos + 1) % deltime;
+    return delay;
+}
+
+int sp_smoothdelay_compute(sp_data *sp, sp_smoothdelay *p, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT *buf1;
+    SPFLOAT *buf2;
+    SPFLOAT it;
+    SPFLOAT del1;
+    SPFLOAT del2;
+
+    *out = 0;
+    if (p->del != p->pdel && p->counter == 0) {
+        uint32_t dels = min((uint32_t)(p->del * sp->sr), p->maxbuf);
+
+        /* initial delay time sets time for both buffers */
+
+        if(p->pdel < 0) {
+            p->deltime1 = dels;
+            p->deltime2 = dels;
+        }
+
+        p->pdel = p->del;
+
+        if(dels == 0) dels = 1;
+
+        if(p->curbuf == 0) {
+            p->curbuf = 1;
+            p->deltime2 = dels;
+        } else {
+            p->curbuf = 0;
+            p->deltime1 = dels;
+        }
+        p->counter = p->maxcount;
+    }
+
+
+
+    buf1 = (SPFLOAT *)p->buf1.ptr;
+    buf2 = (SPFLOAT *)p->buf2.ptr;
+    it = (SPFLOAT)p->counter / p->maxcount;
+    if (p->counter != 0) p->counter--;
+
+    del1 = delay_sig(buf1, &p->bufpos1,
+            p->deltime1, p->feedback, *in);
+
+    del2 = delay_sig(buf2, &p->bufpos2,
+            p->deltime2, p->feedback, *in);
+
+    if (p->curbuf == 0) {
+        /* 1 to 2 */
+        *out = (del1 * it) + (del2 * (1 - it));
+    } else {
+        /* 2 to 1 */
+        *out = (del2 * it) + (del1 * (1 - it));
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/smoother.c
@@ -1,0 +1,66 @@
+/*
+ * Smoother
+ *
+ * Smoother is a one-pole smoothing filter, typically used on
+ * control signals to create a "smootheramenteau" effect.
+ *
+ * This filter design uses the difference equation:
+ *
+ * y(n) = b0*x(n) - a1*y(n - 1)
+ *
+ * Where a1 is (0.5^(1/(t * sr))), and b0 is (1 - a1).
+ *
+ * More information on one-pole smoothers can be found here:
+ * https://ccrma.stanford.edu/~jos/filters/One_Pole.html
+ */
+
+
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "soundpipe.h"
+
+int sp_smoother_create(sp_smoother **p)
+{
+    *p = malloc(sizeof(sp_smoother));
+    return SP_OK;
+}
+
+int sp_smoother_destroy(sp_smoother **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_smoother_init(sp_data *sp, sp_smoother *p)
+{
+    p->y0 = 0;
+    p->b0 = 0;
+    p->a1 = 0;
+    p->psmooth = -100.0;
+    p->smooth = 0.01;
+
+    /* using this constant shaves off a multiply operation */
+    p->onedsr = 1.0/sp->sr;
+    return SP_OK;
+}
+
+int sp_smoother_compute(sp_data *sp, sp_smoother *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (p->psmooth != p->smooth) {
+        p->a1 = pow(0.5, p->onedsr/p->smooth);
+        p->b0 = 1.0 - p->a1;
+        p->psmooth = p->smooth;
+    }
+
+    p->y0 = p->b0 * (*in) + p->a1 * p->y0;
+    *out = p->y0;
+    return SP_OK;
+}
+
+int sp_smoother_reset(sp_data *sp, sp_smoother *p, SPFLOAT *in)
+{
+    p->y0 = *in;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/spa.c
@@ -1,0 +1,57 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+#define SPA_BUFSIZE 4096
+
+int sp_spa_create(sp_spa **p)
+{
+    *p = malloc(sizeof(sp_spa));
+    return SP_OK;
+}
+
+int sp_spa_destroy(sp_spa **p)
+{
+    sp_spa *pp = *p;
+    sp_auxdata_free(&pp->aux);
+    spa_close(&pp->spa);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_spa_init(sp_data *sp, sp_spa *p, const char *filename)
+{
+    if(spa_open(sp, &p->spa, filename, SPA_READ) != SP_OK) {
+        return SP_NOT_OK;
+    }
+
+    p->pos = 0;
+
+    p->bufsize = SPA_BUFSIZE;
+    sp_auxdata_alloc(&p->aux, sizeof(SPFLOAT) * p->bufsize);
+
+    p->buf = p->aux.ptr;
+
+    return SP_OK;
+}
+
+int sp_spa_compute(sp_data *sp, sp_spa *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if(p->bufsize == 0) {
+        *out = 0.0;
+        return SP_OK;
+    }
+
+    if(p->pos == 0) {
+        p->bufsize = spa_read_buf(sp, &p->spa, p->buf, SPA_BUFSIZE);
+        if(p->bufsize == 0) {
+            *out = 0.0;
+            return SP_OK;
+        }
+    }
+
+    *out = p->buf[p->pos];
+    p->pos = (p->pos + 1) % p->bufsize;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/sparec.c
@@ -1,0 +1,59 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+#define SPA_BUFSIZE 4096
+
+int sp_sparec_create(sp_sparec **p)
+{
+    *p = malloc(sizeof(sp_sparec));
+    return SP_OK;
+}
+
+int sp_sparec_destroy(sp_sparec **p)
+{
+    sp_sparec *pp = *p;
+    sp_auxdata_free(&pp->aux);
+    spa_close(&pp->spa);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_sparec_init(sp_data *sp, sp_sparec *p, const char *filename)
+{
+    if(spa_open(sp, &p->spa, filename, SPA_WRITE) != SP_OK) {
+        return SP_NOT_OK;
+    }
+
+    p->pos = SPA_BUFSIZE;
+
+    p->bufsize = SPA_BUFSIZE;
+    sp_auxdata_alloc(&p->aux, sizeof(SPFLOAT) * p->bufsize);
+
+    p->buf = p->aux.ptr;
+    return SP_OK;
+}
+
+int sp_sparec_compute(sp_data *sp, sp_sparec *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if(p->pos == 0) {
+        p->pos = p->bufsize;
+        spa_write_buf(sp, &p->spa, p->buf, p->bufsize);
+    }
+
+    p->buf[p->bufsize - p->pos] = *in;
+
+    p->pos--;
+    *out = *in;
+    return SP_OK;
+}
+
+/* call this to close sparec. will write the rest of the buffer */
+int sp_sparec_close(sp_data *sp, sp_sparec *p)
+{
+    if(p->pos < p->bufsize - 1) {
+        spa_write_buf(sp, &p->spa, p->buf, p->bufsize - p->pos);
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/switch.c
@@ -1,0 +1,38 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_switch_create(sp_switch **p)
+{
+    *p = malloc(sizeof(sp_switch));
+    return SP_OK;
+}
+
+int sp_switch_destroy(sp_switch **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_switch_init(sp_data *sp, sp_switch *p)
+{
+    p->mode = 0;
+    return SP_OK;
+}
+
+int sp_switch_compute(sp_data *sp, sp_switch *p, SPFLOAT *trig,
+    SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out)
+{
+    if (*trig) {
+        p->mode = p->mode == 0 ? 1 : 0;
+    }
+
+    if(p->mode == 0) {
+        *out = *in1;
+    } else {
+        *out = *in2;
+    }
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tadsr.c
@@ -1,0 +1,152 @@
+/*
+ * TADSR
+ *
+ * This module uses modified code from Perry Cook's ADSR STK module.
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+enum{ ATTACK, DECAY, SUSTAIN, RELEASE, CLEAR, KEY_ON, KEY_OFF };
+
+static void make_Envelope(sp_tadsr *e)
+{
+    e->target = 0.0;
+    e->value = 0.0;
+    e->rate = 0.001;
+    e->state = 1;
+}
+
+static void make_ADSR(sp_tadsr *a)
+{
+    make_Envelope(a);
+    a->target = 0.0;
+    a->value = 0.0;
+    a->attackRate = 0.001;
+    a->decayRate = 0.001;
+    a->sustainLevel = 0.0;
+    a->releaseRate = 0.01;
+    a->state = CLEAR;
+}
+
+static void ADSR_keyOn(sp_tadsr *a)
+{
+    a->target = 1.0;
+    a->rate = a->attackRate;
+    a->state = ATTACK;
+}
+
+static void ADSR_keyOff(sp_tadsr *a)
+{
+    a->target = 0.0;
+    a->rate = a->releaseRate;
+    a->state = RELEASE;
+}
+
+static void ADSR_setSustainLevel(sp_data *sp, sp_tadsr *a, SPFLOAT aLevel)
+{
+   a->sustainLevel = aLevel;
+}
+
+static void ADSR_setAttackTime(sp_data *sp, sp_tadsr *a, SPFLOAT aTime)
+{
+    a->attackRate = 1.0 / (aTime * sp->sr);
+}
+
+static void ADSR_setDecayTime(sp_data *sp, sp_tadsr *a, SPFLOAT aTime)
+{
+    a->decayRate = 1.0 / (aTime * sp->sr);
+}
+
+static void ADSR_setReleaseTime(sp_data *sp, sp_tadsr *a, SPFLOAT aTime)
+{
+    a->releaseRate = 1.0 / (aTime * sp->sr);
+}
+
+static void ADSR_setAllTimes(sp_data *sp, sp_tadsr *a, SPFLOAT attTime, SPFLOAT decTime,
+                      SPFLOAT susLevel, SPFLOAT relTime)
+{
+    ADSR_setAttackTime(sp, a, attTime);
+    ADSR_setDecayTime(sp, a, decTime);
+    ADSR_setSustainLevel(sp, a, susLevel);
+    ADSR_setReleaseTime(sp, a, relTime);
+}
+
+static SPFLOAT ADSR_tick(sp_tadsr *a)
+{
+    SPFLOAT out = 0;
+    if (a->state == ATTACK) {
+        a->value += a->rate;
+        if (a->value >= a->target) {
+            a->value = a->target;
+            a->rate = a->decayRate;
+            a->target = a->sustainLevel;
+            a->state = DECAY;
+        }
+        out = a->value;
+    } else if (a->state == DECAY) {
+        a->value -= a->decayRate;
+        out = a->value;
+        if (a->value <= a->sustainLevel) {
+            a->value = a->sustainLevel;
+            out = a->sustainLevel;
+            a->rate = 0.0;
+            a->state = SUSTAIN;
+        }
+    } else if (a->state == RELEASE)  {
+        a->value -= a->releaseRate;
+        if (a->value <= 0.0) {
+            a->value = 0.0;
+            a->state = CLEAR;
+        }
+        out = a->value;
+    } else if (a->state == SUSTAIN)  {
+        out = a->sustainLevel;
+    }
+    return out;
+}
+
+int sp_tadsr_create(sp_tadsr **p)
+{
+    *p = malloc(sizeof(sp_tadsr));
+    return SP_OK;
+}
+
+int sp_tadsr_destroy(sp_tadsr **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tadsr_init(sp_data *sp, sp_tadsr *p)
+{
+    make_ADSR(p);
+    p->atk = 0.5;
+    p->dec = 0.5;
+    p->sus = 0.0;
+    p->rel = 0.5;
+    p->mode = KEY_OFF;
+    return SP_OK;
+}
+
+int sp_tadsr_compute(sp_data *sp, sp_tadsr *p, SPFLOAT *trig, SPFLOAT *out)
+{
+    if(*trig != 0) {
+
+        if(*trig == 2) {
+            ADSR_keyOff(p);
+            p->mode = KEY_OFF;
+        }else if(p->mode == KEY_OFF) {
+            ADSR_setAllTimes(sp, p, p->atk, p->dec, p->sus, p->rel);
+            ADSR_keyOn(p);
+            p->mode = KEY_ON;
+        } else {
+            ADSR_keyOff(p);
+            p->mode = KEY_OFF;
+        }
+    }
+    *out = ADSR_tick(p);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/talkbox.c
@@ -1,0 +1,206 @@
+/*
+ * Talkbox
+ *
+ * This module is ported from the mdaTalkbox plugin by Paul Kellet
+ * (maxim digital audio).
+ *
+ * More information on his plugins and the original code can be found here:
+ *
+ * http://mda.smartelectronix.com/
+ *
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "soundpipe.h"
+
+#ifndef TWO_PI
+#define TWO_PI 6.28318530717958647692528676655901
+#endif
+
+#define ORD_MAX 50
+
+static void lpc_durbin(SPFLOAT *r, int p, float *k, float *g)
+{
+  int i, j;
+  SPFLOAT a[ORD_MAX], at[ORD_MAX], e=r[0];
+
+  for(i=0; i<=p; i++) a[i] = at[i] = 0.0f;
+
+  for(i=1; i<=p; i++)
+  {
+    k[i] = -r[i];
+
+    for(j=1; j<i; j++)
+    {
+      at[j] = a[j];
+      k[i] -= a[j] * r[i-j];
+    }
+    if(fabs(e) < 1.0e-20f) { e = 0.0f;  break; }
+    k[i] /= e;
+
+    a[i] = k[i];
+    for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j];
+
+    e *= 1.0f - k[i] * k[i];
+  }
+
+  if(e < 1.0e-20f) e = 0.0f;
+  *g = (float)sqrt(e);
+}
+
+static void lpc(float *buf, float *car, uint32_t n, uint32_t o)
+{
+    SPFLOAT z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x;
+    uint32_t i, j, nn=n;
+    SPFLOAT min;
+
+    /* buf[] is already emphasized and windowed */
+    for(j=0; j<=o; j++, nn--) {
+        z[j] = r[j] = 0.0f;
+        for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; /* autocorrelation */
+    }
+
+    r[0] *= 1.001f;  /* stability fix */
+
+    min = 0.00001f;
+    if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; }
+
+    lpc_durbin(r, o, k, &G);  /* calc reflection coeffs */
+
+    for(i=1; i<=o; i++) {
+        if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f;
+    }
+
+    for(i=0; i<n; i++) {
+        x = G * car[i];
+        /* lattice filter */
+        for(j=o; j>0; j--) {
+            x -= k[j] * z[j-1];
+            z[j] = z[j-1] + k[j] * x;
+        }
+        buf[i] = z[0] = x;  /* output buf[] will be windowed elsewhere */
+    }
+}
+
+int sp_talkbox_create(sp_talkbox **p)
+{
+    *p = malloc(sizeof(sp_talkbox));
+    return SP_OK;
+}
+
+int sp_talkbox_destroy(sp_talkbox **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_talkbox_init(sp_data *sp, sp_talkbox *p)
+{
+    uint32_t n;
+    p->quality = 1.f;
+    p->N = 1;
+    p->K = 0;
+
+    n = (uint32_t)(0.01633f * sp->sr);
+    if(n > SP_TALKBOX_BUFMAX) n = SP_TALKBOX_BUFMAX;
+
+    /* calculate hanning window */
+    if(n != p->N) {
+        SPFLOAT dp;
+        SPFLOAT pos;
+        p->N = n;
+        dp = TWO_PI / (SPFLOAT)p->N;
+        pos = 0.0f;
+        for(n=0; n < p->N; n++) {
+            p->window[n] = 0.5f - 0.5f * (SPFLOAT)cos(pos);
+            pos += dp;
+        }
+    }
+
+    /* zero out variables and buffers */
+    p->pos = p->K = 0;
+    p->emphasis = 0.0f;
+    p->FX = 0;
+
+    p->u0 = p->u1 = p->u2 = p->u3 = p->u4 = 0.0f;
+    p->d0 = p->d1 = p->d2 = p->d3 = p->d4 = 0.0f;
+
+    memset(p->buf0, 0, SP_TALKBOX_BUFMAX * sizeof(SPFLOAT));
+    memset(p->buf1, 0, SP_TALKBOX_BUFMAX * sizeof(SPFLOAT));
+    memset(p->car0, 0, SP_TALKBOX_BUFMAX * sizeof(SPFLOAT));
+    memset(p->car1, 0, SP_TALKBOX_BUFMAX * sizeof(SPFLOAT));
+    return SP_OK;
+}
+
+int sp_talkbox_compute(sp_data *sp, sp_talkbox *t, SPFLOAT *src, SPFLOAT *exc, SPFLOAT *out)
+{
+    int32_t p0=t->pos, p1 = (t->pos + t->N/2) % t->N;
+    SPFLOAT e=t->emphasis, w, o, x, fx=t->FX;
+    SPFLOAT p, q, h0=0.3f, h1=0.77f;
+    SPFLOAT den;
+
+    t->O = (uint32_t)((0.0001f + 0.0004f * t->quality) * sp->sr);
+
+    o = *src;
+    x = *exc;
+
+    p = t->d0 + h0 * x;
+    t->d0 = t->d1;
+    t->d1 = x - h0 * p;
+
+    q = t->d2 + h1 * t->d4;
+    t->d2 = t->d3;
+    t->d3 = t->d4 - h1 * q;
+
+    t->d4 = x;
+
+    x = p + q;
+
+    if(t->K++) {
+        t->K = 0;
+
+        /* carrier input */
+        t->car0[p0] = t->car1[p1] = x;
+
+        /* 6dB/oct pre-emphasis */
+        x = o - e;  e = o;
+
+        /* 50% overlapping hanning windows */
+        w = t->window[p0]; fx = t->buf0[p0] * w;  t->buf0[p0] = x * w;
+        if(++p0 >= t->N) { lpc(t->buf0, t->car0, t->N, t->O);  p0 = 0; }
+
+        w = 1.0f - w;  fx += t->buf1[p1] * w;  t->buf1[p1] = x * w;
+        if(++p1 >= t->N) { lpc(t->buf1, t->car1, t->N, t->O);  p1 = 0; }
+    }
+
+    p = t->u0 + h0 * fx;
+    t->u0 = t->u1;
+    t->u1 = fx - h0 * p;
+
+    q = t->u2 + h1 * t->u4;
+    t->u2 = t->u3;
+    t->u3 = t->u4 - h1 * q;
+
+    t->u4 = fx;
+    x = p + q;
+
+    o = x * 0.5;
+    *out = o;
+    t->emphasis = e;
+    t->pos = p0;
+    t->FX = fx;
+
+    den = 1.0e-10f;
+    /* anti-denormal */
+    if(fabs(t->d0) < den) t->d0 = 0.0f;
+    if(fabs(t->d1) < den) t->d1 = 0.0f;
+    if(fabs(t->d2) < den) t->d2 = 0.0f;
+    if(fabs(t->d3) < den) t->d3 = 0.0f;
+    if(fabs(t->u0) < den) t->u0 = 0.0f;
+    if(fabs(t->u1) < den) t->u1 = 0.0f;
+    if(fabs(t->u2) < den) t->u2 = 0.0f;
+    if(fabs(t->u3) < den) t->u3 = 0.0f;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tblrec.c
@@ -1,0 +1,46 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <string.h>
+#include "soundpipe.h"
+
+int sp_tblrec_create(sp_tblrec **p)
+{
+    *p = malloc(sizeof(sp_tblrec));
+    return SP_OK;
+}
+
+int sp_tblrec_destroy(sp_tblrec **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tblrec_init(sp_data *sp, sp_tblrec *p, sp_ftbl *ft)
+{
+    p->index = 0;
+    p->record = 0;
+    p->ft = ft;
+    return SP_OK;
+}
+
+int sp_tblrec_compute(sp_data *sp, sp_tblrec *p, SPFLOAT *in, SPFLOAT *trig, SPFLOAT *out)
+{
+    if(*trig != 0) {
+        if(p->record == 1) {
+            p->record = 0;
+        } else {
+            p->record = 1;
+            p->index = 0;
+            memset(p->ft->tbl, 0, sizeof(SPFLOAT) * p->ft->size);
+        }
+    }
+
+    if(p->record) {
+        p->ft->tbl[p->index] = *in;
+        p->index = (p->index + 1) % p->ft->size;
+    }
+
+    *out = *in;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tdiv.c
@@ -1,0 +1,35 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_tdiv_create(sp_tdiv **p)
+{
+    *p = malloc(sizeof(sp_tdiv));
+    return SP_OK;
+}
+
+int sp_tdiv_destroy(sp_tdiv **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tdiv_init(sp_data *sp, sp_tdiv *p)
+{
+    p->num = 2;
+    p->counter = 0;
+    p->offset = 0;
+    return SP_OK;
+}
+
+int sp_tdiv_compute(sp_data *sp, sp_tdiv *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = 0.0;
+    if(*in != 0) {
+        if(p->counter == p->offset) *out = 1.0;
+        else *out = 0.0;
+        p->counter = (p->counter + 1) % p->num;
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tenv.c
@@ -1,0 +1,92 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_tenv_create(sp_tenv **p)
+{
+    *p = malloc(sizeof(sp_tenv));
+    return SP_OK;
+}
+
+int sp_tenv_destroy(sp_tenv **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+static void sp_tenv_reinit(void *ud)
+{
+    sp_tenv *env = ud;
+    env->pos = 0;
+    env->atk_end = env->sr * env->atk;
+    env->rel_start = env->sr * (env->atk + env->hold);
+    env->atk_slp = 1.0 / env->atk_end;
+    env->rel_slp = -1.0 / (env->sr * env->rel);
+    env->totaldur = env->sr * (env->atk + env->hold + env->rel);
+}
+
+static void sp_tenv_comp(void *ud, SPFLOAT *out)
+{
+    sp_tenv *env = ud;
+    SPFLOAT sig = 0;
+    uint32_t pos = env->pos;
+    *out = 0.0;
+
+    if (pos < env->atk_end) {
+        sig = env->last + env->atk_slp;
+    } else if (pos < env->rel_start) {
+        sig = 1.0;
+    } else if (pos < env->totaldur) {
+        sig = env->last + env->rel_slp;
+    } else{
+        sig = 0.0;
+    }
+
+    sig = (sig > 1.0) ? 1.0 : sig;
+    sig = (sig < 0.0) ? 0.0 : sig;
+
+    /* Internal input signal mode */
+    if (env->sigmode) {
+        *out = env->input * sig;
+    } else {
+        *out = sig;
+    }
+
+    env->pos++;
+    env->last = sig;
+}
+
+int sp_tenv_init(sp_data *sp, sp_tenv *p)
+{
+    p->pos = 0;
+    p->last = 0;
+    p->atk = 0.1;
+    p->hold = 0.3;
+    p->rel = 0.2;
+    p->sigmode = 0;
+    p->input = 0;
+
+    p->sr = sp->sr;
+    p->atk_end = p->sr * p->atk;
+    p->rel_start = p->sr * (p->atk + p->hold);
+    p->atk_slp = 1.0 / p->atk_end;
+    p->rel_slp = -1.0 / (p->sr * p->rel);
+    p->totaldur = p->sr * (p->atk + p->hold + p->rel);
+
+    p->started = 0;
+    return SP_OK;
+}
+
+int sp_tenv_compute(sp_data *sp, sp_tenv *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (*in) {
+        sp_tenv_reinit(p);
+        p->started = 1;
+    }
+
+    if (p->started) sp_tenv_comp(p, out);
+    else *out = 0;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tenv2.c
@@ -1,0 +1,69 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+enum {
+    T_ON,
+    T_OFF,
+    T_INIT
+};
+
+int sp_tenv2_create(sp_tenv2 **p)
+{
+    *p = malloc(sizeof(sp_tenv2));
+    return SP_OK;
+}
+
+int sp_tenv2_destroy(sp_tenv2 **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tenv2_init(sp_data *sp, sp_tenv2 *p)
+{
+    p->state = T_INIT;
+    p->atk = 0.1;
+    p->rel = 0.1;
+    p->slope = 0;
+    p->last = 0;
+    return SP_OK;
+}
+
+int sp_tenv2_compute(sp_data *sp, sp_tenv2 *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if(*in != 0) {
+        if(p->state == T_INIT || p->state == T_OFF) {
+            p->state = T_ON;
+            p->timer = (uint32_t)(sp->sr * p->atk);
+            p->totaltime = p->timer;
+            p->slope = 1.0 / p->totaltime;
+        } else if (p->state == T_ON) {
+            p->state = T_OFF;
+            p->timer = (uint32_t)(sp->sr * p->rel);
+            p->totaltime = p->timer;
+            p->slope = 1.0 / p->totaltime;
+        }
+    }
+    if(p->timer == 0) {
+        if(p->state == T_ON) *out = 1;
+        else *out = 0;
+        return SP_OK;
+    } else {
+        p->timer--;
+        if(p->state == T_ON)  {
+            *out = p->last + p->slope;
+        } else if (p->state == T_OFF) {
+            *out = p->last - p->slope;
+        }
+
+        if(*out > 1) *out = 1;
+        if(*out < 0) *out = 0;
+
+        p->last = *out;
+
+        return SP_OK;
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tenvx.c
@@ -1,0 +1,55 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+int sp_tenvx_create(sp_tenvx **p)
+{
+    *p = malloc(sizeof(sp_tenvx));
+    return SP_OK;
+}
+
+int sp_tenvx_destroy(sp_tenvx **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+
+int sp_tenvx_init(sp_data *sp, sp_tenvx *p)
+{
+    p->hold = 0.5;
+    p->atk = 0.5;
+    p->rel = 0.5;
+    p->a_a = p->b_a = 0;
+    p->a_r = p->b_r = 0;
+    p->y = 0;
+    p->count = (uint32_t) (p->hold * sp->sr);
+    return SP_OK;
+}
+
+
+int sp_tenvx_compute(sp_data *sp, sp_tenvx *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = 0;
+
+    if(*in != 0) {
+        p->a_a = exp(-1.0/(p->atk * sp->sr));
+        p->b_a = 1.0 - p->a_a;
+        p->a_r = exp(-1.0/(p->rel * sp->sr));
+        p->b_r = 1.0 - p->a_r;
+        p->count = (uint32_t) (p->hold * sp->sr);
+    }
+
+    if(p->count > 0) {
+        *out = p->b_a + p->a_a * p->y;
+        p->y = *out;
+        p->count--;
+    } else {
+        *out = p->a_r * p->y;
+        p->y = *out;
+    }
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tgate.c
@@ -1,0 +1,36 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_tgate_create(sp_tgate **p)
+{
+    *p = malloc(sizeof(sp_tgate));
+    return SP_OK;
+}
+
+int sp_tgate_destroy(sp_tgate **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tgate_init(sp_data *sp, sp_tgate *p)
+{
+    p->time = 0;
+    p->timer = 0;
+    return SP_OK;
+}
+
+int sp_tgate_compute(sp_data *sp, sp_tgate *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = 0;
+    if(*in != 0) {
+        p->timer = p->time * sp->sr;
+    }
+    if(p->timer != 0) {
+        *out = 1;
+        p->timer--;
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/thresh.c
@@ -1,0 +1,61 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_thresh_create(sp_thresh **p)
+{
+    *p = malloc(sizeof(sp_thresh));
+    return SP_OK;
+}
+
+int sp_thresh_destroy(sp_thresh **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_thresh_init(sp_data *sp, sp_thresh *p)
+{
+    /* Initalize variables here. */
+    p->init = 1;
+    p->mode = 0;
+    p->prev = 0;
+    p->thresh = 0;
+    return SP_OK;
+}
+
+int sp_thresh_compute(sp_data *sp, sp_thresh *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if(p->init) {
+        *out = 0;
+        p->prev = *in;
+        p->init = 0;
+        return SP_OK;
+    }
+
+    switch((int)p->mode) {
+        /* input signal goes above threshold */
+        case 0:
+            *out = (*in > p->thresh && p->prev <= p->thresh);
+            break;
+
+        /* input signal goes below threshold */
+        case 1:
+            *out = (*in < p->thresh && p->prev >= p->thresh);
+            break;
+
+        /* input signal goes below or above threshold */
+        case 2:
+            *out = (*in < p->thresh && p->prev >= p->thresh) ||
+                (*in > p->thresh && p->prev <= p->thresh);
+            break;
+
+        default:
+            return SP_NOT_OK;
+    }
+
+    p->prev = *in;
+
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/timer.c
@@ -1,0 +1,44 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_timer_create(sp_timer **p)
+{
+    *p = malloc(sizeof(sp_timer));
+    return SP_OK;
+}
+
+int sp_timer_destroy(sp_timer **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_timer_init(sp_data *sp, sp_timer *p)
+{
+    p->mode = 0;
+    p->pos = 0;
+    p->time = 0;
+    return SP_OK;
+}
+
+int sp_timer_compute(sp_data *sp, sp_timer *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if(*in != 0) {
+        if(p->mode == 0) {
+            p->pos = 0;
+            p->mode = 1;
+        } else if(p->mode == 1) {
+            p->time = (SPFLOAT) p->pos / sp->sr;
+            p->mode = 0;
+        }
+    }
+
+    if(p->mode == 1) {
+        p->pos++;
+    }
+
+    *out = p->time;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tin.c
@@ -1,0 +1,33 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_tin_create(sp_tin **p)
+{
+    *p = malloc(sizeof(sp_tin));
+    return SP_OK;
+}
+
+int sp_tin_destroy(sp_tin **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tin_init(sp_data *sp, sp_tin *p)
+{
+    p->fp = stdin;
+    p->val = 0;
+    return SP_OK;
+}
+
+int sp_tin_compute(sp_data *sp, sp_tin *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if(*in) {
+        fread(&p->val, sizeof(SPFLOAT), 1, p->fp);
+    }
+
+    *out = p->val;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/trand.c
@@ -1,0 +1,35 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_trand_create(sp_trand **p)
+{
+    *p = malloc(sizeof(sp_trand));
+    return SP_OK;
+}
+
+int sp_trand_destroy(sp_trand **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_trand_init(sp_data *sp, sp_trand *p)
+{
+    p->min = 0;
+    p->max = 1;
+    p->val = 0;
+    return SP_OK;
+}
+
+int sp_trand_compute(sp_data *sp, sp_trand *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if(*in != 0) {
+        p->val = p->min + ((SPFLOAT) sp_rand(sp) / SP_RANDMAX) * (p->max - p->min);
+        *out = p->val;
+    } else {
+        *out = p->val;
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tseg.c
@@ -1,0 +1,50 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+int sp_tseg_create(sp_tseg **p)
+{
+    *p = malloc(sizeof(sp_tseg));
+    return SP_OK;
+}
+
+int sp_tseg_destroy(sp_tseg **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tseg_init(sp_data *sp, sp_tseg *p, SPFLOAT ibeg)
+{
+    p->beg = ibeg;
+    p->end = 1.0;
+    p->val = ibeg;
+    p->type = -3;
+    p->slope = 1.0;
+    p->dur = 1.0;
+    p->tdivnsteps = 0.0;
+    p->count = 0;
+    p->steps = p->dur * sp->sr;
+    return SP_OK;
+}
+
+int sp_tseg_compute(sp_data *sp, sp_tseg *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = p->val;
+    if(*in != 0) {
+        p->slope = 1.0 / (1.0 - exp(p->type));
+        p->beg = p->val;
+        p->count = 0;
+        p->steps = p->dur * sp->sr;
+        p->tdivnsteps = (SPFLOAT)p->type / (p->steps - 1);
+    }
+    if(p->count < p->steps) {
+        *out = p->beg + (p->end - p->beg) *
+            ((1 - exp(p->count * p->tdivnsteps)) * p->slope);
+        p->val = *out;
+        p->count++;
+    }
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/tseq.c
@@ -1,0 +1,39 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+
+int sp_tseq_create(sp_tseq **p)
+{
+    *p = malloc(sizeof(sp_tseq));
+    return SP_OK;
+}
+
+int sp_tseq_destroy(sp_tseq **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_tseq_init(sp_data *sp, sp_tseq *p, sp_ftbl *ft)
+{
+    p->ft = ft;
+    p->pos = -1;
+    p->val = 0;
+    p->shuf = 0;
+    return SP_OK;
+}
+
+int sp_tseq_compute(sp_data *sp, sp_tseq *p, SPFLOAT *trig, SPFLOAT *val)
+{
+    if(*trig != 0){
+        if(p->shuf) {
+            p->pos = sp_rand(sp) % p->ft->size;
+        } else {
+            p->pos = (p->pos + 1) % p->ft->size;
+        }
+        p->val = p->ft->tbl[p->pos];
+    }
+    *val = p->val;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/vardelay.c
@@ -1,0 +1,51 @@
+/* this file is placed in the public domain */
+
+#include <math.h>
+#include <stdlib.h>
+#define SK_VARDELAY_PRIV
+#include "tangled/vardelay.h"
+#include "soundpipe.h"
+
+int sp_vardelay_create(sp_vardelay **p)
+{
+    *p = malloc(sizeof(sp_vardelay));
+    return SP_OK;
+}
+
+int sp_vardelay_destroy(sp_vardelay **p)
+{
+    sp_vardelay *pp;
+    pp = *p;
+    free(pp->v);
+    free(pp->buf);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_vardelay_init(sp_data *sp, sp_vardelay *p, SPFLOAT maxdel)
+{
+    unsigned long sz;
+
+    sz = floor(maxdel * sp->sr) + 1;
+    p->v = malloc(sizeof(sk_vardelay));
+    p->buf = calloc(1, sz * sizeof(SPFLOAT));
+
+    sk_vardelay_init(p->v, sp->sr, p->buf, sz);
+    p->feedback = 0;
+    p->del = maxdel * 0.5;
+
+    sk_vardelay_delay(p->v, p->del);
+    sk_vardelay_feedback(p->v, p->feedback);
+    return SP_OK;
+}
+
+int sp_vardelay_compute(sp_data *sp,
+                       sp_vardelay *p,
+                       SPFLOAT *in,
+                       SPFLOAT *out)
+{
+    sk_vardelay_delay(p->v, p->del);
+    sk_vardelay_feedback(p->v, p->feedback);
+    *out = sk_vardelay_tick(p->v, *in);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/voc.c
@@ -1,0 +1,789 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "soundpipe.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "voc.h"
+
+#ifndef MIN
+#define MIN(A,B) ((A) < (B) ? (A) : (B))
+#endif
+
+#ifndef MAX
+#define MAX(A,B) ((A) > (B) ? (A) : (B))
+#endif
+
+#define EPSILON 1.0e-38
+
+#define MAX_TRANSIENTS 4
+
+
+
+typedef struct {
+    SPFLOAT  freq;
+    SPFLOAT  tenseness;
+    SPFLOAT  Rd;
+    SPFLOAT  waveform_length;
+    SPFLOAT  time_in_waveform;
+
+    SPFLOAT  alpha;
+    SPFLOAT  E0;
+    SPFLOAT  epsilon;
+    SPFLOAT  shift;
+    SPFLOAT  delta;
+    SPFLOAT  Te;
+    SPFLOAT  omega;
+
+    SPFLOAT  T;
+} glottis;
+
+
+
+typedef struct transient {
+    int  position;
+    SPFLOAT  time_alive;
+    SPFLOAT  lifetime;
+    SPFLOAT  strength;
+    SPFLOAT  exponent;
+    char is_free;
+    unsigned int id;
+    struct transient *next;
+} transient;
+
+
+typedef struct {
+    transient pool[MAX_TRANSIENTS];
+    transient *root;
+    int size;
+    int next_free;
+} transient_pool;
+
+
+
+typedef struct {
+    int n;
+
+    SPFLOAT  diameter[44];
+    SPFLOAT  rest_diameter[44];
+    SPFLOAT  target_diameter[44];
+    SPFLOAT  new_diameter[44];
+    SPFLOAT  R[44];
+    SPFLOAT  L[44];
+    SPFLOAT  reflection[45];
+    SPFLOAT  new_reflection[45];
+    SPFLOAT  junction_outL[45];
+    SPFLOAT  junction_outR[45];
+    SPFLOAT  A[44];
+
+    int nose_length;
+
+
+    int nose_start;
+
+    int tip_start;
+    SPFLOAT  noseL[28];
+    SPFLOAT  noseR[28];
+    SPFLOAT  nose_junc_outL[29];
+    SPFLOAT  nose_junc_outR[29];
+    SPFLOAT  nose_reflection[29];
+    SPFLOAT  nose_diameter[28];
+    SPFLOAT  noseA[28];
+
+    SPFLOAT  reflection_left;
+    SPFLOAT  reflection_right;
+    SPFLOAT  reflection_nose;
+
+    SPFLOAT  new_reflection_left;
+    SPFLOAT  new_reflection_right;
+    SPFLOAT  new_reflection_nose;
+
+    SPFLOAT  velum_target;
+
+    SPFLOAT  glottal_reflection;
+    SPFLOAT  lip_reflection;
+    int  last_obstruction;
+    SPFLOAT  fade;
+    SPFLOAT  movement_speed;
+    SPFLOAT  lip_output;
+    SPFLOAT  nose_output;
+    SPFLOAT  block_time;
+
+    transient_pool tpool;
+    SPFLOAT  T;
+} tract;
+
+
+struct sp_voc {
+    glottis  glot; /*The Glottis*/
+    tract  tr; /*The Vocal Tract */
+    SPFLOAT  buf[512];
+    int counter;
+};
+
+
+
+
+
+static void glottis_setup_waveform(glottis *glot, SPFLOAT lambda)
+{
+
+    SPFLOAT Rd;
+    SPFLOAT Ra;
+    SPFLOAT Rk;
+    SPFLOAT Rg;
+
+    SPFLOAT Ta;
+    SPFLOAT Tp;
+    SPFLOAT Te;
+
+    SPFLOAT epsilon;
+    SPFLOAT shift;
+    SPFLOAT delta;
+    SPFLOAT rhs_integral;
+
+    SPFLOAT lower_integral;
+    SPFLOAT upper_integral;
+
+    SPFLOAT omega;
+    SPFLOAT s;
+    SPFLOAT y;
+    SPFLOAT z;
+
+    SPFLOAT alpha;
+    SPFLOAT E0;
+
+
+    glot->Rd = 3 * (1 - glot->tenseness);
+    glot->waveform_length = 1.0 / glot->freq;
+
+    Rd = glot->Rd;
+    if(Rd < 0.5) Rd = 0.5;
+    if(Rd > 2.7) Rd = 2.7;
+
+
+    Ra = -0.01 + 0.048*Rd;
+    Rk = 0.224 + 0.118*Rd;
+    Rg = (Rk/4)*(0.5 + 1.2*Rk)/(0.11*Rd-Ra*(0.5+1.2*Rk));
+
+
+    Ta = Ra;
+    Tp = (SPFLOAT)1.0 / (2*Rg);
+    Te = Tp + Tp*Rk;
+
+
+
+    epsilon = (SPFLOAT)1.0 / Ta;
+    shift = exp(-epsilon * (1 - Te));
+    delta = 1 - shift;
+
+
+
+    rhs_integral = (SPFLOAT)(1.0/epsilon) * (shift-1) + (1-Te)*shift;
+    rhs_integral = rhs_integral / delta;
+    lower_integral = - (Te - Tp) / 2 + rhs_integral;
+    upper_integral = -lower_integral;
+
+
+    omega = M_PI / Tp;
+    s = sin(omega * Te);
+
+    y = -M_PI * s * upper_integral / (Tp*2);
+    z = log(y);
+    alpha = z / (Tp/2 - Te);
+    E0 = -1 / (s * exp(alpha*Te));
+
+
+
+    glot->alpha = alpha;
+    glot->E0 = E0;
+    glot->epsilon = epsilon;
+    glot->shift = shift;
+    glot->delta = delta;
+    glot->Te = Te;
+    glot->omega = omega;
+}
+
+
+static void glottis_init(glottis *glot, SPFLOAT sr)
+{
+    glot->freq = 140; /* 140Hz frequency by default */
+    glot->tenseness = 0.6; /* value between 0 and 1 */
+    glot->T = 1.0/sr; /* big T */
+    glot->time_in_waveform = 0;
+    glottis_setup_waveform(glot, 0);
+}
+
+
+static SPFLOAT glottis_compute(sp_data *sp, glottis *glot, SPFLOAT lambda)
+{
+    SPFLOAT out;
+    SPFLOAT aspiration;
+    SPFLOAT noise;
+    SPFLOAT t;
+    SPFLOAT intensity;
+
+    out = 0;
+    intensity = 1.0;
+    glot->time_in_waveform += glot->T;
+
+    if(glot->time_in_waveform > glot->waveform_length) {
+        glot->time_in_waveform -= glot->waveform_length;
+        glottis_setup_waveform(glot, lambda);
+
+    }
+
+    t = (glot->time_in_waveform / glot->waveform_length);
+
+    if(t > glot->Te) {
+        out = (-exp(-glot->epsilon * (t-glot->Te)) + glot->shift) / glot->delta;
+    } else {
+        out = glot->E0 * exp(glot->alpha * t) * sin(glot->omega * t);
+    }
+
+
+
+
+    noise = 2.0 * ((SPFLOAT) sp_rand(sp) / SP_RANDMAX) - 1;
+
+
+    aspiration = intensity * (1 - sqrt(glot->tenseness)) * 0.3 * noise;
+
+    aspiration *= 0.2;
+
+    out += aspiration;
+
+    return out;
+}
+
+
+
+
+static void tract_calculate_reflections(tract *tr)
+{
+    int i;
+    SPFLOAT  sum;
+
+    for(i = 0; i < tr->n; i++) {
+        tr->A[i] = tr->diameter[i] * tr->diameter[i];
+        /* Calculate area from diameter squared*/
+    }
+
+    for(i = 1; i < tr->n; i++) {
+        tr->reflection[i] = tr->new_reflection[i];
+        if(tr->A[i] == 0) {
+            tr->new_reflection[i] = 0.999; /* to prevent bad behavior if 0 */
+        } else {
+            tr->new_reflection[i] =
+                (tr->A[i - 1] - tr->A[i]) / (tr->A[i - 1] + tr->A[i]);
+        }
+    }
+
+    tr->reflection_left = tr->new_reflection_left;
+    tr->reflection_right = tr->new_reflection_right;
+    tr->reflection_nose = tr->new_reflection_nose;
+
+    sum = tr->A[tr->nose_start] + tr->A[tr->nose_start + 1] + tr->noseA[0];
+    tr->new_reflection_left = (SPFLOAT)(2 * tr->A[tr->nose_start] - sum) / sum;
+    tr->new_reflection_right = (SPFLOAT)(2 * tr->A[tr->nose_start + 1] - sum) / sum;
+    tr->new_reflection_nose = (SPFLOAT)(2 * tr->noseA[0] - sum) / sum;
+}
+
+
+static void tract_calculate_nose_reflections(tract *tr)
+{
+    int i;
+
+    for(i = 0; i < tr->nose_length; i++) {
+        tr->noseA[i] = tr->nose_diameter[i] * tr->nose_diameter[i];
+    }
+
+    for(i = 1; i < tr->nose_length; i++) {
+        tr->nose_reflection[i] = (tr->noseA[i - 1] - tr->noseA[i]) /
+            (tr->noseA[i-1] + tr->noseA[i]);
+    }
+}
+
+
+
+static int append_transient(transient_pool *pool, int position)
+{
+    int i;
+    int free_id;
+    transient *t;
+
+    free_id = pool->next_free;
+    if(pool->size == MAX_TRANSIENTS) return 0;
+
+    if(free_id == -1) {
+        for(i = 0; i < MAX_TRANSIENTS; i++) {
+            if(pool->pool[i].is_free) {
+                free_id = i;
+                break;
+            }
+        }
+    }
+
+    if(free_id == -1) return 0;
+
+    t = &pool->pool[free_id];
+    t->next = pool->root;
+    pool->root = t;
+    pool->size++;
+    t->is_free = 0;
+    t->time_alive = 0;
+    t->lifetime = 0.2;
+    t->strength = 0.3;
+    t->exponent = 200;
+    t->position = position;
+    pool->next_free = -1;
+    return 0;
+}
+
+
+static void remove_transient(transient_pool *pool, unsigned int id)
+{
+    int i;
+    transient *n;
+
+    pool->next_free = id;
+    n = pool->root;
+    if(id == n->id) {
+        pool->root = n->next;
+        pool->size--;
+        return;
+    }
+
+    for(i = 0; i < pool->size; i++) {
+        if(n->next->id == id) {
+            pool->size--;
+            n->next->is_free = 1;
+            n->next = n->next->next;
+            break;
+        }
+        n = n->next;
+    }
+}
+
+
+
+static SPFLOAT move_towards(SPFLOAT current, SPFLOAT target,
+        SPFLOAT amt_up, SPFLOAT amt_down)
+{
+    SPFLOAT tmp;
+    if(current < target) {
+        tmp = current + amt_up;
+        return MIN(tmp, target);
+    } else {
+        tmp = current - amt_down;
+        return MAX(tmp, target);
+    }
+    return 0.0;
+}
+
+static void tract_reshape(tract *tr)
+{
+    SPFLOAT amount;
+    SPFLOAT slow_return;
+    SPFLOAT diameter;
+    SPFLOAT target_diameter;
+    int i;
+    int current_obstruction;
+
+    current_obstruction = -1;
+    amount = tr->block_time * tr->movement_speed;
+
+    for(i = 0; i < tr->n; i++) {
+        slow_return = 0;
+        diameter = tr->diameter[i];
+        target_diameter = tr->target_diameter[i];
+
+        if(diameter < 0.001) current_obstruction = i;
+
+        if(i < tr->nose_start) slow_return = 0.6;
+        else if(i >= tr->tip_start) slow_return = 1.0;
+        else {
+            slow_return =
+                0.6+0.4*(i - tr->nose_start)/(tr->tip_start - tr->nose_start);
+        }
+
+        tr->diameter[i] = move_towards(diameter, target_diameter,
+                slow_return * amount, 2 * amount);
+
+    }
+
+    if(tr->last_obstruction > -1 && current_obstruction == -1 &&
+            tr->noseA[0] < 0.05) {
+        append_transient(&tr->tpool, tr->last_obstruction);
+    }
+    tr->last_obstruction = current_obstruction;
+
+    tr->nose_diameter[0] = move_towards(tr->nose_diameter[0], tr->velum_target,
+            amount * 0.25, amount * 0.1);
+    tr->noseA[0] = tr->nose_diameter[0] * tr->nose_diameter[0];
+}
+
+
+static void tract_init(sp_data *sp, tract *tr)
+{
+    int i;
+    SPFLOAT diameter, d; /* needed to set up diameter arrays */
+
+    tr->n = 44;
+    tr->nose_length = 28;
+    tr->nose_start = 17;
+
+    tr->reflection_left = 0.0;
+    tr->reflection_right = 0.0;
+    tr->reflection_nose = 0.0;
+    tr->new_reflection_left = 0.0;
+    tr->new_reflection_right= 0.0;
+    tr->new_reflection_nose = 0.0;
+    tr->velum_target = 0.01;
+    tr->glottal_reflection = 0.75;
+    tr->lip_reflection = -0.85;
+    tr->last_obstruction = -1;
+    tr->movement_speed = 15;
+    tr->lip_output = 0;
+    tr->nose_output = 0;
+    tr->tip_start = 32;
+
+
+    memset(tr->diameter, 0, tr->n * sizeof(SPFLOAT));
+    memset(tr->rest_diameter, 0, tr->n * sizeof(SPFLOAT));
+    memset(tr->target_diameter, 0, tr->n * sizeof(SPFLOAT));
+    memset(tr->new_diameter, 0, tr->n * sizeof(SPFLOAT));
+    memset(tr->L, 0, tr->n * sizeof(SPFLOAT));
+    memset(tr->R, 0, tr->n * sizeof(SPFLOAT));
+    memset(tr->reflection, 0, (tr->n + 1) * sizeof(SPFLOAT));
+    memset(tr->new_reflection, 0, (tr->n + 1) * sizeof(SPFLOAT));
+    memset(tr->junction_outL, 0, (tr->n + 1) * sizeof(SPFLOAT));
+    memset(tr->junction_outR, 0, (tr->n + 1) * sizeof(SPFLOAT));
+    memset(tr->A, 0, tr->n * sizeof(SPFLOAT));
+    memset(tr->noseL, 0, tr->nose_length * sizeof(SPFLOAT));
+    memset(tr->noseR, 0, tr->nose_length * sizeof(SPFLOAT));
+    memset(tr->nose_junc_outL, 0, (tr->nose_length + 1) * sizeof(SPFLOAT));
+    memset(tr->nose_junc_outR, 0, (tr->nose_length + 1) * sizeof(SPFLOAT));
+    memset(tr->nose_diameter, 0, tr->nose_length * sizeof(SPFLOAT));
+    memset(tr->noseA, 0, tr->nose_length * sizeof(SPFLOAT));
+
+
+    for(i = 0; i < tr->n; i++) {
+        diameter = 0;
+        if(i < 7 * (SPFLOAT)tr->n / 44 - 0.5) {
+            diameter = 0.6;
+        } else if( i < 12 * (SPFLOAT)tr->n / 44) {
+            diameter = 1.1;
+        } else {
+            diameter = 1.5;
+        }
+
+        tr->diameter[i] =
+            tr->rest_diameter[i] =
+            tr->target_diameter[i] =
+            tr->new_diameter[i] = diameter;
+
+    }
+
+
+        for(i = 0; i < tr->nose_length; i++) {
+            d = 2 * ((SPFLOAT)i / tr->nose_length);
+            if(d < 1) {
+                diameter = 0.4 + 1.6 * d;
+            } else {
+                diameter = 0.5 + 1.5*(2-d);
+            }
+            diameter = MIN(diameter, 1.9);
+            tr->nose_diameter[i] = diameter;
+        }
+
+
+    tract_calculate_reflections(tr);
+    tract_calculate_nose_reflections(tr);
+    tr->nose_diameter[0] = tr->velum_target;
+
+    tr->block_time = 512.0 / (SPFLOAT)sp->sr;
+    tr->T = 1.0 / (SPFLOAT)sp->sr;
+
+    tr->tpool.size = 0;
+    tr->tpool.next_free = 0;
+    for(i = 0; i < MAX_TRANSIENTS; i++) {
+        tr->tpool.pool[i].is_free = 1;
+        tr->tpool.pool[i].id = i;
+        tr->tpool.pool[i].position = 0;
+        tr->tpool.pool[i].time_alive = 0;
+        tr->tpool.pool[i].strength = 0;
+        tr->tpool.pool[i].exponent = 0;
+    }
+}
+
+
+static void tract_compute(sp_data *sp, tract *tr,
+    SPFLOAT  in,
+    SPFLOAT  lambda)
+{
+     SPFLOAT  r, w;
+    int i;
+    SPFLOAT  amp;
+    int current_size;
+    transient_pool *pool;
+    transient *n;
+
+
+
+        pool = &tr->tpool;
+        current_size = pool->size;
+        n = pool->root;
+        for(i = 0; i < current_size; i++) {
+            amp = n->strength * pow(2, -1.0 * n->exponent * n->time_alive);
+            tr->L[n->position] += amp * 0.5;
+            tr->R[n->position] += amp * 0.5;
+            n->time_alive += tr->T * 0.5;
+            if(n->time_alive > n->lifetime) {
+                 remove_transient(pool, n->id);
+            }
+            n = n->next;
+        }
+
+
+    tr->junction_outR[0] = tr->L[0] * tr->glottal_reflection + in;
+    tr->junction_outL[tr->n] = tr->R[tr->n - 1] * tr->lip_reflection;
+
+    for(i = 1; i < tr->n; i++) {
+        r = tr->reflection[i] * (1 - lambda) + tr->new_reflection[i] * lambda;
+        w = r * (tr->R[i - 1] + tr->L[i]);
+        tr->junction_outR[i] = tr->R[i - 1] - w;
+        tr->junction_outL[i] = tr->L[i] + w;
+    }
+
+
+    i = tr->nose_start;
+    r = tr->new_reflection_left * (1-lambda) + tr->reflection_left*lambda;
+    tr->junction_outL[i] = r*tr->R[i-1] + (1+r)*(tr->noseL[0]+tr->L[i]);
+    r = tr->new_reflection_right * (1 - lambda) + tr->reflection_right * lambda;
+    tr->junction_outR[i] = r*tr->L[i] + (1+r)*(tr->R[i-1]+tr->noseL[0]);
+    r = tr->new_reflection_nose * (1 - lambda) + tr->reflection_nose * lambda;
+    tr->nose_junc_outR[0] = r * tr->noseL[0]+(1+r)*(tr->L[i]+tr->R[i-1]);
+
+
+    for(i = 0; i < tr->n; i++) {
+        tr->R[i] = tr->junction_outR[i]*0.999;
+        tr->L[i] = tr->junction_outL[i + 1]*0.999;
+    }
+    tr->lip_output = tr->R[tr->n - 1];
+
+
+    tr->nose_junc_outL[tr->nose_length] =
+        tr->noseR[tr->nose_length-1] * tr->lip_reflection;
+
+    for(i = 1; i < tr->nose_length; i++) {
+        w = tr->nose_reflection[i] * (tr->noseR[i-1] + tr->noseL[i]);
+        tr->nose_junc_outR[i] = tr->noseR[i - 1] - w;
+        tr->nose_junc_outL[i] = tr->noseL[i] + w;
+    }
+
+
+    for(i = 0; i < tr->nose_length; i++) {
+        tr->noseR[i] = tr->nose_junc_outR[i];
+        tr->noseL[i] = tr->nose_junc_outL[i + 1];
+    }
+    tr->nose_output = tr->noseR[tr->nose_length - 1];
+
+}
+
+
+
+
+int sp_voc_create(sp_voc **voc)
+{
+    *voc = malloc(sizeof(sp_voc));
+    return SP_OK;
+}
+
+
+int sp_voc_destroy(sp_voc **voc)
+{
+    free(*voc);
+    return SP_OK;
+}
+
+
+int sp_voc_init(sp_data *sp, sp_voc *voc)
+{
+    glottis_init(&voc->glot, sp->sr); /* initialize glottis */
+    tract_init(sp, &voc->tr); /* initialize vocal tract */
+    voc->counter = 0;
+    return SP_OK;
+}
+
+
+int sp_voc_compute(sp_data *sp, sp_voc *voc, SPFLOAT *out)
+{
+    SPFLOAT vocal_output, glot;
+    SPFLOAT lambda1, lambda2;
+    int i;
+
+
+
+    if(voc->counter == 0) {
+        tract_reshape(&voc->tr);
+        tract_calculate_reflections(&voc->tr);
+        for(i = 0; i < 512; i++) {
+            vocal_output = 0;
+            lambda1 = (SPFLOAT) i / 512;
+            lambda2 = (SPFLOAT) (i + 0.5) / 512;
+            glot = glottis_compute(sp, &voc->glot, lambda1);
+
+            tract_compute(sp, &voc->tr, glot, lambda1);
+            vocal_output += voc->tr.lip_output + voc->tr.nose_output;
+
+            tract_compute(sp, &voc->tr, glot, lambda2);
+            vocal_output += voc->tr.lip_output + voc->tr.nose_output;
+            voc->buf[i] = vocal_output * 0.125;
+        }
+    }
+
+
+    *out = voc->buf[voc->counter];
+    voc->counter = (voc->counter + 1) % 512;
+    return SP_OK;
+}
+
+
+int sp_voc_tract_compute(sp_data *sp, sp_voc *voc, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT vocal_output;
+    SPFLOAT lambda1, lambda2;
+
+    if(voc->counter == 0) {
+        tract_reshape(&voc->tr);
+        tract_calculate_reflections(&voc->tr);
+    }
+
+    vocal_output = 0;
+    lambda1 = (SPFLOAT) voc->counter / 512;
+    lambda2 = (SPFLOAT) (voc->counter + 0.5) / 512;
+
+    tract_compute(sp, &voc->tr, *in, lambda1);
+    vocal_output += voc->tr.lip_output + voc->tr.nose_output;
+    tract_compute(sp, &voc->tr, *in, lambda2);
+    vocal_output += voc->tr.lip_output + voc->tr.nose_output;
+
+
+    *out = vocal_output * 0.125;
+    voc->counter = (voc->counter + 1) % 512;
+    return SP_OK;
+}
+
+
+void sp_voc_set_frequency(sp_voc *voc, SPFLOAT freq)
+{
+    voc->glot.freq = freq;
+}
+
+
+SPFLOAT * sp_voc_get_frequency_ptr(sp_voc *voc)
+{
+    return &voc->glot.freq;
+}
+
+
+SPFLOAT* sp_voc_get_tract_diameters(sp_voc *voc)
+{
+    return voc->tr.target_diameter;
+}
+
+
+SPFLOAT* sp_voc_get_current_tract_diameters(sp_voc *voc)
+{
+    return voc->tr.diameter;
+}
+
+
+int sp_voc_get_tract_size(sp_voc *voc)
+{
+    return voc->tr.n;
+}
+
+
+SPFLOAT* sp_voc_get_nose_diameters(sp_voc *voc)
+{
+    return voc->tr.nose_diameter;
+}
+
+
+int sp_voc_get_nose_size(sp_voc *voc)
+{
+    return voc->tr.nose_length;
+}
+
+
+void sp_voc_set_diameters(sp_voc *voc,
+    int blade_start,
+    int lip_start,
+    int tip_start,
+    SPFLOAT tongue_index,
+    SPFLOAT tongue_diameter,
+    SPFLOAT *diameters) {
+
+    int i;
+    SPFLOAT t;
+    SPFLOAT fixed_tongue_diameter;
+    SPFLOAT curve;
+    int grid_offset = 0;
+
+    for(i = blade_start; i < lip_start; i++) {
+        t = 1.1 * M_PI *
+            (SPFLOAT)(tongue_index - i)/(tip_start - blade_start);
+        fixed_tongue_diameter = 2+(tongue_diameter-2)/1.5;
+        curve = (1.5 - fixed_tongue_diameter + grid_offset) * cos(t);
+        if(i == blade_start - 2 || i == lip_start - 1) curve *= 0.8;
+        if(i == blade_start || i == lip_start - 2) curve *= 0.94;
+        diameters[i] = 1.5 - curve;
+    }
+}
+
+
+void sp_voc_set_tongue_shape(sp_voc *voc,
+    SPFLOAT tongue_index,
+    SPFLOAT tongue_diameter) {
+    SPFLOAT *diameters;
+    diameters = sp_voc_get_tract_diameters(voc);
+    sp_voc_set_diameters(voc, 10, 39, 32,
+            tongue_index, tongue_diameter, diameters);
+}
+
+
+int sp_voc_get_counter(sp_voc *voc)
+{
+    return voc->counter;
+}
+
+
+void sp_voc_set_tenseness(sp_voc *voc, SPFLOAT tenseness)
+{
+    voc->glot.tenseness = tenseness;
+}
+
+
+SPFLOAT * sp_voc_get_tenseness_ptr(sp_voc *voc)
+{
+    return &voc->glot.tenseness;
+}
+
+
+void sp_voc_set_velum(sp_voc *voc, SPFLOAT velum)
+{
+    voc->tr.velum_target = velum;
+}
+
+
+SPFLOAT *sp_voc_get_velum_ptr(sp_voc *voc)
+{
+    return &voc->tr.velum_target;
+}
--- /dev/null
+++ b/modules/wavin.c
@@ -1,0 +1,105 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "lib/dr_wav/sp_dr_wav.h"
+
+#define WAVIN_BUFSIZE 1024
+
+struct sp_wavin {
+    SPFLOAT buf[WAVIN_BUFSIZE];
+    int count;
+    drwav *wav;
+    unsigned long pos;
+    unsigned long buf_start;
+    unsigned long buf_end;
+};
+
+int sp_wavin_create(sp_wavin **p)
+{
+    *p = malloc(sizeof(sp_wavin));
+    return SP_OK;
+}
+
+int sp_wavin_destroy(sp_wavin **p)
+{
+    sp_drwav_uninit((*p)->wav);
+    free((*p)->wav);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_wavin_init(sp_data *sp, sp_wavin *p, const char *filename)
+{
+    p->count = 0;
+    p->pos = 0;
+    p->buf_start = 0;
+    p->buf_end = 0;
+    p->wav = calloc(1, sp_drwav_size());
+    sp_drwav_init_file(p->wav, filename);
+    return SP_OK;
+}
+
+static void read_block(sp_data *sp, sp_wavin *p, unsigned long position)
+{
+    unsigned long samps_read;
+    sp_wavin_seek(sp, p, position);
+    samps_read = sp_drwav_read_f32(p->wav, WAVIN_BUFSIZE, p->buf);
+    p->buf_start = position;
+    p->buf_end = position + samps_read - 1;
+}
+
+int sp_wavin_compute(sp_data *sp, sp_wavin *p, SPFLOAT *in, SPFLOAT *out)
+{
+    if (p->pos > sp_drwav_sampcount(p->wav)) {
+        *out = 0;
+        return SP_OK;
+    }
+
+    if (p->count == 0) {
+        read_block(sp, p, p->pos);
+    }
+
+    *out = p->buf[p->count];
+    p->count = (p->count + 1) % WAVIN_BUFSIZE;
+    p->pos++;
+    return SP_OK;
+}
+
+int sp_wavin_get_sample(sp_data *sp, sp_wavin *p, SPFLOAT *out, SPFLOAT pos)
+{
+    unsigned long ipos;
+    float samp1, samp2;
+    float frac;
+    int buf_pos;
+
+    ipos = floor(pos);
+
+    if(!(ipos >= p->buf_start && ipos < (p->buf_end - 1))
+       || (p->buf_start == p->buf_end)) {
+        read_block(sp, p, ipos);
+    }
+
+    frac = pos - ipos;
+
+    buf_pos = (int)(ipos - p->buf_start);
+    samp1 = p->buf[buf_pos];
+    samp2 = p->buf[buf_pos + 1];
+
+    *out = samp1 + (samp2 - samp1) * frac;
+    return SP_OK;
+}
+
+
+int sp_wavin_reset_to_start(sp_data *sp, sp_wavin *p)
+{
+    sp_wavin_seek(sp, p, 0);
+    return SP_OK;
+}
+
+int sp_wavin_seek(sp_data *sp, sp_wavin *p, unsigned long sample)
+{
+    sp_drwav_seek_to_sample(p->wav, sample);
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/wavout.c
@@ -1,0 +1,49 @@
+/* This code is placed in the public domain. */
+
+#include <stdlib.h>
+#include "soundpipe.h"
+#include "lib/dr_wav/sp_dr_wav.h"
+
+#define WAVOUT_BUFSIZE 1024
+
+struct sp_wavout {
+    drwav *wav;
+    SPFLOAT buf[WAVOUT_BUFSIZE];
+    int count;
+};
+
+int sp_wavout_create(sp_wavout **p)
+{
+    *p = malloc(sizeof(sp_wavout));
+    return SP_OK;
+}
+
+int sp_wavout_destroy(sp_wavout **p)
+{
+    /* write any remaining samples */
+    if ((*p)->count != 0) {
+        sp_drwav_write((*p)->wav, (*p)->count, (*p)->buf);
+    }
+    sp_drwav_close((*p)->wav);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_wavout_init(sp_data *sp, sp_wavout *p, const char *filename)
+{
+    p->count = 0;
+    p->wav = sp_drwav_open_mono_write(filename, sp->sr);
+    return SP_OK;
+}
+
+int sp_wavout_compute(sp_data *sp, sp_wavout *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = *in;
+    if(p->count == WAVOUT_BUFSIZE) {
+        sp_drwav_write(p->wav, WAVOUT_BUFSIZE, p->buf);
+        p->count = 0;
+    }
+    p->buf[p->count] = *in;
+    p->count++;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/wpkorg35.c
@@ -1,0 +1,145 @@
+/*
+ * WPKorg35
+ *
+ * This is a filter based off of an implemenation the Korg35 filter by Will
+ * Pirke. It has been ported from the CCRMA chugin by the same name.
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+
+#ifndef M_PI
+#define M_PI		3.14159265358979323846
+#endif
+
+static void update(sp_data *sp, sp_wpkorg35 *wpk)
+{
+	/* prewarp for BZT */
+	SPFLOAT wd = 2*M_PI*wpk->cutoff;
+	SPFLOAT T  = 1.0/(SPFLOAT)sp->sr;
+	SPFLOAT wa = (2/T)*tan(wd*T/2);
+	SPFLOAT g  = wa*T/2.0;
+
+	/* the feedforward coeff in the VA One Pole */
+	SPFLOAT G = g/(1.0 + g);
+
+    /* set alphas */
+    wpk->lpf1_a = G;
+    wpk->lpf2_a = G;
+    wpk->hpf_a = G;
+
+    /* set betas */
+	wpk->lpf2_b = (wpk->res - wpk->res*G)/(1.0 + g);
+	wpk->hpf_b = -1.0/(1.0 + g);
+
+	wpk->alpha = 1.0/(1.0 - wpk->res*G + wpk->res*G*G); ;
+}
+
+SPFLOAT wpk_doFilter(sp_wpkorg35 *wpk)
+{
+    return 0.0;
+}
+
+int sp_wpkorg35_create(sp_wpkorg35 **p)
+{
+    *p = malloc(sizeof(sp_wpkorg35));
+    return SP_OK;
+}
+
+int sp_wpkorg35_destroy(sp_wpkorg35 **p)
+{
+    free(*p);
+    return SP_OK;
+}
+
+int sp_wpkorg35_init(sp_data *sp, sp_wpkorg35 *p)
+{
+    p->alpha = 0.0;
+    p->pcutoff = p->cutoff = 1000;
+    p->pres = p->res = 1.0;
+
+    /* reset memory for filters */
+    p->lpf1_z = 0;
+    p->lpf2_z = 0;
+    p->hpf_z = 0;
+
+
+    /* initialize LPF1 */
+
+    p->lpf1_a = 1.0;
+    p->lpf1_z = 0.0;
+
+    /* initialize LPF2 */
+
+    p->lpf2_a = 1.0;
+    p->lpf2_b = 1.0;
+    p->lpf2_z = 0.0;
+
+    p->nonlinear = 0;
+    p->saturation = 0;
+
+    /* update filters */
+    update(sp, p);
+    return SP_OK;
+}
+
+int sp_wpkorg35_compute(sp_data *sp, sp_wpkorg35 *p, SPFLOAT *in, SPFLOAT *out)
+{
+    /* initialize variables */
+    SPFLOAT y1;
+    SPFLOAT S35;
+    SPFLOAT u;
+    SPFLOAT y;
+    SPFLOAT vn;
+
+    if(p->pcutoff != p->cutoff || p->pres != p->res) update(sp, p);
+
+    y1 = 0.0;
+    S35 = 0.0;
+    u = 0.0;
+    y = 0.0;
+    vn = 0.0;
+
+    /* process input through LPF1 */
+    vn = (*in - p->lpf1_z) * p->lpf1_a;
+    y1 = vn + p->lpf1_z;
+    p->lpf1_z = y1 + vn;
+
+    /* form feedback value */
+
+    S35 = (p->hpf_z * p->hpf_b) + (p->lpf2_z * p->lpf2_b);
+
+    /* Calculate u */
+    u = p->alpha * (y1 + S35);
+
+    /* Naive NLP */
+
+    if(p->saturation > 0) {
+        u = tanh(p->saturation * u);
+    }
+
+    /* Feed it to LPF2 */
+    vn = (u - p->lpf2_z) * p->lpf2_a;
+    y = (vn + p->lpf2_z);
+    p->lpf2_z = y + vn;
+    y *= p->res;
+
+    /* Feed y to HPF2 */
+
+    vn = (y - p->hpf_z) * p->hpf_a;
+    p->hpf_z = vn + (vn + p->hpf_z);
+
+    /* Auto-normalize */
+
+    if(p->res > 0) {
+        y *= 1.0 / p->res;
+    }
+
+    *out = y;
+
+    p->pcutoff = p->cutoff;
+    p->pres = p->res;
+    return SP_OK;
+}
--- /dev/null
+++ b/modules/zitarev.c
@@ -1,0 +1,1062 @@
+/*
+ * Zitarev
+ *
+ * This code has been generated FAUST.
+ * It uses the zitarev module included in the FAUST
+ * standard library (FAUST port by Julius Smith).
+ * It has been modified to work as a Soundpipe module.
+ *
+ * Original Author: Fons Adriaensen
+ *
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include "soundpipe.h"
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+float powf(float dummy0, float dummy1);
+float sqrtf(float dummy0);
+float cosf(float dummy0);
+float floorf(float dummy0);
+float expf(float dummy0);
+static float faustpower2_f(float value) {
+	return (value * value);
+
+}
+float tanf(float dummy0);
+
+
+typedef struct {
+
+	float fVec1[32768];
+	float fVec4[32768];
+	float fVec8[32768];
+	float fVec6[16384];
+	float fVec10[16384];
+	float fVec12[16384];
+	float fVec14[16384];
+	float fVec16[16384];
+	float fVec0[8192];
+	float fVec2[8192];
+	float fVec5[4096];
+	float fVec7[4096];
+	float fVec9[4096];
+	float fVec13[4096];
+	float fVec15[4096];
+	float fVec3[2048];
+	float fVec11[2048];
+	float fVec17[2048];
+	float fRec4[3];
+	float fRec5[3];
+	float fRec6[3];
+	float fRec7[3];
+	float fRec8[3];
+	float fRec9[3];
+	float fRec10[3];
+	float fRec11[3];
+	float fRec3[3];
+	float fRec2[3];
+	float fRec45[3];
+	float fRec44[3];
+	float fRec0[2];
+	float fRec1[2];
+	float fRec15[2];
+	float fRec14[2];
+	float fRec12[2];
+	float fRec19[2];
+	float fRec18[2];
+	float fRec16[2];
+	float fRec23[2];
+	float fRec22[2];
+	float fRec20[2];
+	float fRec27[2];
+	float fRec26[2];
+	float fRec24[2];
+	float fRec31[2];
+	float fRec30[2];
+	float fRec28[2];
+	float fRec35[2];
+	float fRec34[2];
+	float fRec32[2];
+	float fRec39[2];
+	float fRec38[2];
+	float fRec36[2];
+	float fRec43[2];
+	float fRec42[2];
+	float fRec40[2];
+	FAUSTFLOAT fHslider0;
+	FAUSTFLOAT fHslider1;
+	int IOTA;
+	int fSamplingFreq;
+	int iConst0;
+	float fConst1;
+	FAUSTFLOAT fHslider2;
+	FAUSTFLOAT fHslider3;
+	FAUSTFLOAT fHslider4;
+	FAUSTFLOAT fHslider5;
+	float fConst2;
+	float fConst3;
+	FAUSTFLOAT fHslider6;
+	float fConst4;
+	FAUSTFLOAT fHslider7;
+	FAUSTFLOAT fHslider8;
+	float fConst5;
+	FAUSTFLOAT fHslider9;
+	float fConst6;
+	int iConst7;
+	float fConst8;
+	FAUSTFLOAT fHslider10;
+	int iConst9;
+	float fConst10;
+	float fConst11;
+	float fConst12;
+	int iConst13;
+	int iConst14;
+	float fConst15;
+	float fConst16;
+	float fConst17;
+	int iConst18;
+	int iConst19;
+	float fConst20;
+	float fConst21;
+	float fConst22;
+	int iConst23;
+	int iConst24;
+	float fConst25;
+	float fConst26;
+	float fConst27;
+	int iConst28;
+	int iConst29;
+	float fConst30;
+	float fConst31;
+	float fConst32;
+	int iConst33;
+	int iConst34;
+	float fConst35;
+	float fConst36;
+	float fConst37;
+	int iConst38;
+	int iConst39;
+	float fConst40;
+	float fConst41;
+	float fConst42;
+	int iConst43;
+	int iConst44;
+
+} zitarev;
+
+static zitarev* newzitarev() {
+	zitarev* dsp = (zitarev*)malloc(sizeof(zitarev));
+	return dsp;
+}
+
+static void deletezitarev(zitarev* dsp) {
+	free(dsp);
+}
+
+static void instanceInitzitarev(zitarev* dsp, int samplingFreq) {
+	dsp->fSamplingFreq = samplingFreq;
+	dsp->fHslider0 = (FAUSTFLOAT)-20.;
+	/* C99 loop */
+	{
+		int i0;
+		for (i0 = 0; (i0 < 2); i0 = (i0 + 1)) {
+			dsp->fRec0[i0] = 0.f;
+
+		}
+
+	}
+	dsp->fHslider1 = (FAUSTFLOAT)1.;
+	/* C99 loop */
+	{
+		int i1;
+		for (i1 = 0; (i1 < 2); i1 = (i1 + 1)) {
+			dsp->fRec1[i1] = 0.f;
+
+		}
+
+	}
+	dsp->IOTA = 0;
+	/* C99 loop */
+	{
+		int i2;
+		for (i2 = 0; (i2 < 8192); i2 = (i2 + 1)) {
+			dsp->fVec0[i2] = 0.f;
+
+		}
+
+	}
+	dsp->iConst0 = min(192000, max(1, dsp->fSamplingFreq));
+	dsp->fConst1 = (6.28319f / (float)dsp->iConst0);
+	dsp->fHslider2 = (FAUSTFLOAT)1500.;
+	dsp->fHslider3 = (FAUSTFLOAT)0.;
+	dsp->fHslider4 = (FAUSTFLOAT)315.;
+	dsp->fHslider5 = (FAUSTFLOAT)0.;
+	dsp->fConst2 = floorf((0.5f + (0.219991f * (float)dsp->iConst0)));
+	dsp->fConst3 = ((0.f - (6.90776f * dsp->fConst2)) / (float)dsp->iConst0);
+	dsp->fHslider6 = (FAUSTFLOAT)2.;
+	dsp->fConst4 = (6.28319f / (float)dsp->iConst0);
+	dsp->fHslider7 = (FAUSTFLOAT)6000.;
+	dsp->fHslider8 = (FAUSTFLOAT)3.;
+	dsp->fConst5 = (3.14159f / (float)dsp->iConst0);
+	dsp->fHslider9 = (FAUSTFLOAT)200.;
+	/* C99 loop */
+	{
+		int i3;
+		for (i3 = 0; (i3 < 2); i3 = (i3 + 1)) {
+			dsp->fRec15[i3] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i4;
+		for (i4 = 0; (i4 < 2); i4 = (i4 + 1)) {
+			dsp->fRec14[i4] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i5;
+		for (i5 = 0; (i5 < 32768); i5 = (i5 + 1)) {
+			dsp->fVec1[i5] = 0.f;
+
+		}
+
+	}
+	dsp->fConst6 = floorf((0.5f + (0.019123f * (float)dsp->iConst0)));
+	dsp->iConst7 = (int)((int)(dsp->fConst2 - dsp->fConst6) & 32767);
+	/* C99 loop */
+	{
+		int i6;
+		for (i6 = 0; (i6 < 8192); i6 = (i6 + 1)) {
+			dsp->fVec2[i6] = 0.f;
+
+		}
+
+	}
+	dsp->fConst8 = (0.001f * (float)dsp->iConst0);
+	dsp->fHslider10 = (FAUSTFLOAT)60.;
+	/* C99 loop */
+	{
+		int i7;
+		for (i7 = 0; (i7 < 2048); i7 = (i7 + 1)) {
+			dsp->fVec3[i7] = 0.f;
+
+		}
+
+	}
+	dsp->iConst9 = (int)((int)(dsp->fConst6 - 1.f) & 2047);
+	/* C99 loop */
+	{
+		int i8;
+		for (i8 = 0; (i8 < 2); i8 = (i8 + 1)) {
+			dsp->fRec12[i8] = 0.f;
+
+		}
+
+	}
+	dsp->fConst10 = floorf((0.5f + (0.256891f * (float)dsp->iConst0)));
+	dsp->fConst11 = ((0.f - (6.90776f * dsp->fConst10)) / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i9;
+		for (i9 = 0; (i9 < 2); i9 = (i9 + 1)) {
+			dsp->fRec19[i9] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i10;
+		for (i10 = 0; (i10 < 2); i10 = (i10 + 1)) {
+			dsp->fRec18[i10] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i11;
+		for (i11 = 0; (i11 < 32768); i11 = (i11 + 1)) {
+			dsp->fVec4[i11] = 0.f;
+
+		}
+
+	}
+	dsp->fConst12 = floorf((0.5f + (0.027333f * (float)dsp->iConst0)));
+	dsp->iConst13 = (int)((int)(dsp->fConst10 - dsp->fConst12) & 32767);
+	/* C99 loop */
+	{
+		int i12;
+		for (i12 = 0; (i12 < 4096); i12 = (i12 + 1)) {
+			dsp->fVec5[i12] = 0.f;
+
+		}
+
+	}
+	dsp->iConst14 = (int)((int)(dsp->fConst12 - 1.f) & 4095);
+	/* C99 loop */
+	{
+		int i13;
+		for (i13 = 0; (i13 < 2); i13 = (i13 + 1)) {
+			dsp->fRec16[i13] = 0.f;
+
+		}
+
+	}
+	dsp->fConst15 = floorf((0.5f + (0.192303f * (float)dsp->iConst0)));
+	dsp->fConst16 = ((0.f - (6.90776f * dsp->fConst15)) / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i14;
+		for (i14 = 0; (i14 < 2); i14 = (i14 + 1)) {
+			dsp->fRec23[i14] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i15;
+		for (i15 = 0; (i15 < 2); i15 = (i15 + 1)) {
+			dsp->fRec22[i15] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i16;
+		for (i16 = 0; (i16 < 16384); i16 = (i16 + 1)) {
+			dsp->fVec6[i16] = 0.f;
+
+		}
+
+	}
+	dsp->fConst17 = floorf((0.5f + (0.029291f * (float)dsp->iConst0)));
+	dsp->iConst18 = (int)((int)(dsp->fConst15 - dsp->fConst17) & 16383);
+	/* C99 loop */
+	{
+		int i17;
+		for (i17 = 0; (i17 < 4096); i17 = (i17 + 1)) {
+			dsp->fVec7[i17] = 0.f;
+
+		}
+
+	}
+	dsp->iConst19 = (int)((int)(dsp->fConst17 - 1.f) & 4095);
+	/* C99 loop */
+	{
+		int i18;
+		for (i18 = 0; (i18 < 2); i18 = (i18 + 1)) {
+			dsp->fRec20[i18] = 0.f;
+
+		}
+
+	}
+	dsp->fConst20 = floorf((0.5f + (0.210389f * (float)dsp->iConst0)));
+	dsp->fConst21 = ((0.f - (6.90776f * dsp->fConst20)) / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i19;
+		for (i19 = 0; (i19 < 2); i19 = (i19 + 1)) {
+			dsp->fRec27[i19] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i20;
+		for (i20 = 0; (i20 < 2); i20 = (i20 + 1)) {
+			dsp->fRec26[i20] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i21;
+		for (i21 = 0; (i21 < 32768); i21 = (i21 + 1)) {
+			dsp->fVec8[i21] = 0.f;
+
+		}
+
+	}
+	dsp->fConst22 = floorf((0.5f + (0.024421f * (float)dsp->iConst0)));
+	dsp->iConst23 = (int)((int)(dsp->fConst20 - dsp->fConst22) & 32767);
+	/* C99 loop */
+	{
+		int i22;
+		for (i22 = 0; (i22 < 4096); i22 = (i22 + 1)) {
+			dsp->fVec9[i22] = 0.f;
+
+		}
+
+	}
+	dsp->iConst24 = (int)((int)(dsp->fConst22 - 1.f) & 4095);
+	/* C99 loop */
+	{
+		int i23;
+		for (i23 = 0; (i23 < 2); i23 = (i23 + 1)) {
+			dsp->fRec24[i23] = 0.f;
+
+		}
+
+	}
+	dsp->fConst25 = floorf((0.5f + (0.125f * (float)dsp->iConst0)));
+	dsp->fConst26 = ((0.f - (6.90776f * dsp->fConst25)) / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i24;
+		for (i24 = 0; (i24 < 2); i24 = (i24 + 1)) {
+			dsp->fRec31[i24] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i25;
+		for (i25 = 0; (i25 < 2); i25 = (i25 + 1)) {
+			dsp->fRec30[i25] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i26;
+		for (i26 = 0; (i26 < 16384); i26 = (i26 + 1)) {
+			dsp->fVec10[i26] = 0.f;
+
+		}
+
+	}
+	dsp->fConst27 = floorf((0.5f + (0.013458f * (float)dsp->iConst0)));
+	dsp->iConst28 = (int)((int)(dsp->fConst25 - dsp->fConst27) & 16383);
+	/* C99 loop */
+	{
+		int i27;
+		for (i27 = 0; (i27 < 2048); i27 = (i27 + 1)) {
+			dsp->fVec11[i27] = 0.f;
+
+		}
+
+	}
+	dsp->iConst29 = (int)((int)(dsp->fConst27 - 1.f) & 2047);
+	/* C99 loop */
+	{
+		int i28;
+		for (i28 = 0; (i28 < 2); i28 = (i28 + 1)) {
+			dsp->fRec28[i28] = 0.f;
+
+		}
+
+	}
+	dsp->fConst30 = floorf((0.5f + (0.127837f * (float)dsp->iConst0)));
+	dsp->fConst31 = ((0.f - (6.90776f * dsp->fConst30)) / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i29;
+		for (i29 = 0; (i29 < 2); i29 = (i29 + 1)) {
+			dsp->fRec35[i29] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i30;
+		for (i30 = 0; (i30 < 2); i30 = (i30 + 1)) {
+			dsp->fRec34[i30] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i31;
+		for (i31 = 0; (i31 < 16384); i31 = (i31 + 1)) {
+			dsp->fVec12[i31] = 0.f;
+
+		}
+
+	}
+	dsp->fConst32 = floorf((0.5f + (0.031604f * (float)dsp->iConst0)));
+	dsp->iConst33 = (int)((int)(dsp->fConst30 - dsp->fConst32) & 16383);
+	/* C99 loop */
+	{
+		int i32;
+		for (i32 = 0; (i32 < 4096); i32 = (i32 + 1)) {
+			dsp->fVec13[i32] = 0.f;
+
+		}
+
+	}
+	dsp->iConst34 = (int)((int)(dsp->fConst32 - 1.f) & 4095);
+	/* C99 loop */
+	{
+		int i33;
+		for (i33 = 0; (i33 < 2); i33 = (i33 + 1)) {
+			dsp->fRec32[i33] = 0.f;
+
+		}
+
+	}
+	dsp->fConst35 = floorf((0.5f + (0.174713f * (float)dsp->iConst0)));
+	dsp->fConst36 = ((0.f - (6.90776f * dsp->fConst35)) / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i34;
+		for (i34 = 0; (i34 < 2); i34 = (i34 + 1)) {
+			dsp->fRec39[i34] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i35;
+		for (i35 = 0; (i35 < 2); i35 = (i35 + 1)) {
+			dsp->fRec38[i35] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i36;
+		for (i36 = 0; (i36 < 16384); i36 = (i36 + 1)) {
+			dsp->fVec14[i36] = 0.f;
+
+		}
+
+	}
+	dsp->fConst37 = floorf((0.5f + (0.022904f * (float)dsp->iConst0)));
+	dsp->iConst38 = (int)((int)(dsp->fConst35 - dsp->fConst37) & 16383);
+	/* C99 loop */
+	{
+		int i37;
+		for (i37 = 0; (i37 < 4096); i37 = (i37 + 1)) {
+			dsp->fVec15[i37] = 0.f;
+
+		}
+
+	}
+	dsp->iConst39 = (int)((int)(dsp->fConst37 - 1.f) & 4095);
+	/* C99 loop */
+	{
+		int i38;
+		for (i38 = 0; (i38 < 2); i38 = (i38 + 1)) {
+			dsp->fRec36[i38] = 0.f;
+
+		}
+
+	}
+	dsp->fConst40 = floorf((0.5f + (0.153129f * (float)dsp->iConst0)));
+	dsp->fConst41 = ((0.f - (6.90776f * dsp->fConst40)) / (float)dsp->iConst0);
+	/* C99 loop */
+	{
+		int i39;
+		for (i39 = 0; (i39 < 2); i39 = (i39 + 1)) {
+			dsp->fRec43[i39] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i40;
+		for (i40 = 0; (i40 < 2); i40 = (i40 + 1)) {
+			dsp->fRec42[i40] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i41;
+		for (i41 = 0; (i41 < 16384); i41 = (i41 + 1)) {
+			dsp->fVec16[i41] = 0.f;
+
+		}
+
+	}
+	dsp->fConst42 = floorf((0.5f + (0.020346f * (float)dsp->iConst0)));
+	dsp->iConst43 = (int)((int)(dsp->fConst40 - dsp->fConst42) & 16383);
+	/* C99 loop */
+	{
+		int i42;
+		for (i42 = 0; (i42 < 2048); i42 = (i42 + 1)) {
+			dsp->fVec17[i42] = 0.f;
+
+		}
+
+	}
+	dsp->iConst44 = (int)((int)(dsp->fConst42 - 1.f) & 2047);
+	/* C99 loop */
+	{
+		int i43;
+		for (i43 = 0; (i43 < 2); i43 = (i43 + 1)) {
+			dsp->fRec40[i43] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i44;
+		for (i44 = 0; (i44 < 3); i44 = (i44 + 1)) {
+			dsp->fRec4[i44] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i45;
+		for (i45 = 0; (i45 < 3); i45 = (i45 + 1)) {
+			dsp->fRec5[i45] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i46;
+		for (i46 = 0; (i46 < 3); i46 = (i46 + 1)) {
+			dsp->fRec6[i46] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i47;
+		for (i47 = 0; (i47 < 3); i47 = (i47 + 1)) {
+			dsp->fRec7[i47] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i48;
+		for (i48 = 0; (i48 < 3); i48 = (i48 + 1)) {
+			dsp->fRec8[i48] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i49;
+		for (i49 = 0; (i49 < 3); i49 = (i49 + 1)) {
+			dsp->fRec9[i49] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i50;
+		for (i50 = 0; (i50 < 3); i50 = (i50 + 1)) {
+			dsp->fRec10[i50] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i51;
+		for (i51 = 0; (i51 < 3); i51 = (i51 + 1)) {
+			dsp->fRec11[i51] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i52;
+		for (i52 = 0; (i52 < 3); i52 = (i52 + 1)) {
+			dsp->fRec3[i52] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i53;
+		for (i53 = 0; (i53 < 3); i53 = (i53 + 1)) {
+			dsp->fRec2[i53] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i54;
+		for (i54 = 0; (i54 < 3); i54 = (i54 + 1)) {
+			dsp->fRec45[i54] = 0.f;
+
+		}
+
+	}
+	/* C99 loop */
+	{
+		int i55;
+		for (i55 = 0; (i55 < 3); i55 = (i55 + 1)) {
+			dsp->fRec44[i55] = 0.f;
+
+		}
+
+	}
+
+}
+
+static void initzitarev(zitarev* dsp, int samplingFreq) {
+	instanceInitzitarev(dsp, samplingFreq);
+}
+
+static void buildUserInterfacezitarev(zitarev* dsp, UIGlue* interface) {
+	interface->addHorizontalSlider(interface->uiInterface, "in_delay", &dsp->fHslider10, 60.f, 10.f, 100.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "lf_x", &dsp->fHslider9, 200.f, 50.f, 1000.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "rt60_low", &dsp->fHslider8, 3.f, 1.f, 8.f, 0.1f);
+	interface->addHorizontalSlider(interface->uiInterface, "rt60_mid", &dsp->fHslider6, 2.f, 1.f, 8.f, 0.1f);
+	interface->addHorizontalSlider(interface->uiInterface, "hf_damping", &dsp->fHslider7, 6000.f, 1500.f, 47040.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "eq1_freq", &dsp->fHslider4, 315.f, 40.f, 2500.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "eq1_level", &dsp->fHslider5, 0.f, -15.f, 15.f, 0.1f);
+	interface->addHorizontalSlider(interface->uiInterface, "eq2_freq", &dsp->fHslider2, 1500.f, 160.f, 10000.f, 1.f);
+	interface->addHorizontalSlider(interface->uiInterface, "eq2_level", &dsp->fHslider3, 0.f, -15.f, 15.f, 0.1f);
+	interface->addHorizontalSlider(interface->uiInterface, "mix", &dsp->fHslider1, 1.f, 0.f, 1.f, 0.001f);
+	interface->addHorizontalSlider(interface->uiInterface, "level", &dsp->fHslider0, -20.f, -70.f, 40.f, 0.1f);
+}
+
+static void computezitarev(zitarev* dsp, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+	FAUSTFLOAT* input0 = inputs[0];
+	FAUSTFLOAT* input1 = inputs[1];
+	FAUSTFLOAT* output0 = outputs[0];
+	FAUSTFLOAT* output1 = outputs[1];
+	float fSlow0 = (0.001f * powf(10.f, (0.05f * (float)dsp->fHslider0)));
+	float fSlow1 = (0.001f * (float)dsp->fHslider1);
+	float fSlow2 = (float)dsp->fHslider2;
+	float fSlow3 = powf(10.f, (0.05f * (float)dsp->fHslider3));
+	float fSlow4 = (dsp->fConst1 * (fSlow2 / sqrtf(max(0.f, fSlow3))));
+	float fSlow5 = ((1.f - fSlow4) / (1.f + fSlow4));
+	float fSlow6 = ((0.f - cosf((dsp->fConst1 * fSlow2))) * (1.f + fSlow5));
+	float fSlow7 = (float)dsp->fHslider4;
+	float fSlow8 = powf(10.f, (0.05f * (float)dsp->fHslider5));
+	float fSlow9 = (dsp->fConst1 * (fSlow7 / sqrtf(max(0.f, fSlow8))));
+	float fSlow10 = ((1.f - fSlow9) / (1.f + fSlow9));
+	float fSlow11 = ((0.f - cosf((dsp->fConst1 * fSlow7))) * (1.f + fSlow10));
+	float fSlow12 = (float)dsp->fHslider6;
+	float fSlow13 = expf((dsp->fConst3 / fSlow12));
+	float fSlow14 = faustpower2_f(fSlow13);
+	float fSlow15 = cosf((dsp->fConst4 * (float)dsp->fHslider7));
+	float fSlow16 = (1.f - (fSlow14 * fSlow15));
+	float fSlow17 = (1.f - fSlow14);
+	float fSlow18 = (fSlow16 / fSlow17);
+	float fSlow19 = sqrtf(max(0.f, ((faustpower2_f(fSlow16) / faustpower2_f(fSlow17)) - 1.f)));
+	float fSlow20 = (fSlow18 - fSlow19);
+	float fSlow21 = (((1.f + fSlow19) - fSlow18) * fSlow13);
+	float fSlow22 = (float)dsp->fHslider8;
+	float fSlow23 = ((expf((dsp->fConst3 / fSlow22)) / fSlow13) - 1.f);
+	float fSlow24 = (1.f / tanf((dsp->fConst5 * (float)dsp->fHslider9)));
+	float fSlow25 = (1.f + fSlow24);
+	float fSlow26 = (0.f - ((1.f - fSlow24) / fSlow25));
+	float fSlow27 = (1.f / fSlow25);
+	int iSlow28 = (int)((int)(dsp->fConst8 * (float)dsp->fHslider10) & 8191);
+	float fSlow29 = expf((dsp->fConst11 / fSlow12));
+	float fSlow30 = faustpower2_f(fSlow29);
+	float fSlow31 = (1.f - (fSlow15 * fSlow30));
+	float fSlow32 = (1.f - fSlow30);
+	float fSlow33 = (fSlow31 / fSlow32);
+	float fSlow34 = sqrtf(max(0.f, ((faustpower2_f(fSlow31) / faustpower2_f(fSlow32)) - 1.f)));
+	float fSlow35 = (fSlow33 - fSlow34);
+	float fSlow36 = (((1.f + fSlow34) - fSlow33) * fSlow29);
+	float fSlow37 = ((expf((dsp->fConst11 / fSlow22)) / fSlow29) - 1.f);
+	float fSlow38 = expf((dsp->fConst16 / fSlow12));
+	float fSlow39 = faustpower2_f(fSlow38);
+	float fSlow40 = (1.f - (fSlow15 * fSlow39));
+	float fSlow41 = (1.f - fSlow39);
+	float fSlow42 = (fSlow40 / fSlow41);
+	float fSlow43 = sqrtf(max(0.f, ((faustpower2_f(fSlow40) / faustpower2_f(fSlow41)) - 1.f)));
+	float fSlow44 = (fSlow42 - fSlow43);
+	float fSlow45 = (((1.f + fSlow43) - fSlow42) * fSlow38);
+	float fSlow46 = ((expf((dsp->fConst16 / fSlow22)) / fSlow38) - 1.f);
+	float fSlow47 = expf((dsp->fConst21 / fSlow12));
+	float fSlow48 = faustpower2_f(fSlow47);
+	float fSlow49 = (1.f - (fSlow15 * fSlow48));
+	float fSlow50 = (1.f - fSlow48);
+	float fSlow51 = (fSlow49 / fSlow50);
+	float fSlow52 = sqrtf(max(0.f, ((faustpower2_f(fSlow49) / faustpower2_f(fSlow50)) - 1.f)));
+	float fSlow53 = (fSlow51 - fSlow52);
+	float fSlow54 = (((1.f + fSlow52) - fSlow51) * fSlow47);
+	float fSlow55 = ((expf((dsp->fConst21 / fSlow22)) / fSlow47) - 1.f);
+	float fSlow56 = expf((dsp->fConst26 / fSlow12));
+	float fSlow57 = faustpower2_f(fSlow56);
+	float fSlow58 = (1.f - (fSlow15 * fSlow57));
+	float fSlow59 = (1.f - fSlow57);
+	float fSlow60 = (fSlow58 / fSlow59);
+	float fSlow61 = sqrtf(max(0.f, ((faustpower2_f(fSlow58) / faustpower2_f(fSlow59)) - 1.f)));
+	float fSlow62 = (fSlow60 - fSlow61);
+	float fSlow63 = (((1.f + fSlow61) - fSlow60) * fSlow56);
+	float fSlow64 = ((expf((dsp->fConst26 / fSlow22)) / fSlow56) - 1.f);
+	float fSlow65 = expf((dsp->fConst31 / fSlow12));
+	float fSlow66 = faustpower2_f(fSlow65);
+	float fSlow67 = (1.f - (fSlow15 * fSlow66));
+	float fSlow68 = (1.f - fSlow66);
+	float fSlow69 = (fSlow67 / fSlow68);
+	float fSlow70 = sqrtf(max(0.f, ((faustpower2_f(fSlow67) / faustpower2_f(fSlow68)) - 1.f)));
+	float fSlow71 = (fSlow69 - fSlow70);
+	float fSlow72 = (((1.f + fSlow70) - fSlow69) * fSlow65);
+	float fSlow73 = ((expf((dsp->fConst31 / fSlow22)) / fSlow65) - 1.f);
+	float fSlow74 = expf((dsp->fConst36 / fSlow12));
+	float fSlow75 = faustpower2_f(fSlow74);
+	float fSlow76 = (1.f - (fSlow15 * fSlow75));
+	float fSlow77 = (1.f - fSlow75);
+	float fSlow78 = (fSlow76 / fSlow77);
+	float fSlow79 = sqrtf(max(0.f, ((faustpower2_f(fSlow76) / faustpower2_f(fSlow77)) - 1.f)));
+	float fSlow80 = (fSlow78 - fSlow79);
+	float fSlow81 = (((1.f + fSlow79) - fSlow78) * fSlow74);
+	float fSlow82 = ((expf((dsp->fConst36 / fSlow22)) / fSlow74) - 1.f);
+	float fSlow83 = expf((dsp->fConst41 / fSlow12));
+	float fSlow84 = faustpower2_f(fSlow83);
+	float fSlow85 = (1.f - (fSlow15 * fSlow84));
+	float fSlow86 = (1.f - fSlow84);
+	float fSlow87 = (fSlow85 / fSlow86);
+	float fSlow88 = sqrtf(max(0.f, ((faustpower2_f(fSlow85) / faustpower2_f(fSlow86)) - 1.f)));
+	float fSlow89 = (fSlow87 - fSlow88);
+	float fSlow90 = (((1.f + fSlow88) - fSlow87) * fSlow83);
+	float fSlow91 = ((expf((dsp->fConst41 / fSlow22)) / fSlow83) - 1.f);
+	/* C99 loop */
+	{
+		int i;
+		for (i = 0; (i < count); i = (i + 1)) {
+			dsp->fRec0[0] = ((0.999f * dsp->fRec0[1]) + fSlow0);
+			dsp->fRec1[0] = ((0.999f * dsp->fRec1[1]) + fSlow1);
+			float fTemp0 = (1.f - dsp->fRec1[0]);
+			float fTemp1 = (float)input0[i];
+			dsp->fVec0[(dsp->IOTA & 8191)] = fTemp1;
+			float fTemp2 = (fSlow6 * dsp->fRec2[1]);
+			float fTemp3 = (fSlow11 * dsp->fRec3[1]);
+			dsp->fRec15[0] = ((fSlow26 * dsp->fRec15[1]) + (fSlow27 * (dsp->fRec11[1] + dsp->fRec11[2])));
+			dsp->fRec14[0] = ((fSlow20 * dsp->fRec14[1]) + (fSlow21 * (dsp->fRec11[1] + (fSlow23 * dsp->fRec15[0]))));
+			dsp->fVec1[(dsp->IOTA & 32767)] = ((0.353553f * dsp->fRec14[0]) + 1e-20f);
+			float fTemp4 = (float)input1[i];
+			dsp->fVec2[(dsp->IOTA & 8191)] = fTemp4;
+			float fTemp5 = (0.3f * dsp->fVec2[((dsp->IOTA - iSlow28) & 8191)]);
+			float fTemp6 = (((0.6f * dsp->fRec12[1]) + dsp->fVec1[((dsp->IOTA - dsp->iConst7) & 32767)]) - fTemp5);
+			dsp->fVec3[(dsp->IOTA & 2047)] = fTemp6;
+			dsp->fRec12[0] = dsp->fVec3[((dsp->IOTA - dsp->iConst9) & 2047)];
+			float fRec13 = (0.f - (0.6f * fTemp6));
+			dsp->fRec19[0] = ((fSlow26 * dsp->fRec19[1]) + (fSlow27 * (dsp->fRec7[1] + dsp->fRec7[2])));
+			dsp->fRec18[0] = ((fSlow35 * dsp->fRec18[1]) + (fSlow36 * (dsp->fRec7[1] + (fSlow37 * dsp->fRec19[0]))));
+			dsp->fVec4[(dsp->IOTA & 32767)] = ((0.353553f * dsp->fRec18[0]) + 1e-20f);
+			float fTemp7 = (((0.6f * dsp->fRec16[1]) + dsp->fVec4[((dsp->IOTA - dsp->iConst13) & 32767)]) - fTemp5);
+			dsp->fVec5[(dsp->IOTA & 4095)] = fTemp7;
+			dsp->fRec16[0] = dsp->fVec5[((dsp->IOTA - dsp->iConst14) & 4095)];
+			float fRec17 = (0.f - (0.6f * fTemp7));
+			dsp->fRec23[0] = ((fSlow26 * dsp->fRec23[1]) + (fSlow27 * (dsp->fRec9[1] + dsp->fRec9[2])));
+			dsp->fRec22[0] = ((fSlow44 * dsp->fRec22[1]) + (fSlow45 * (dsp->fRec9[1] + (fSlow46 * dsp->fRec23[0]))));
+			dsp->fVec6[(dsp->IOTA & 16383)] = ((0.353553f * dsp->fRec22[0]) + 1e-20f);
+			float fTemp8 = (dsp->fVec6[((dsp->IOTA - dsp->iConst18) & 16383)] + (fTemp5 + (0.6f * dsp->fRec20[1])));
+			dsp->fVec7[(dsp->IOTA & 4095)] = fTemp8;
+			dsp->fRec20[0] = dsp->fVec7[((dsp->IOTA - dsp->iConst19) & 4095)];
+			float fRec21 = (0.f - (0.6f * fTemp8));
+			dsp->fRec27[0] = ((fSlow26 * dsp->fRec27[1]) + (fSlow27 * (dsp->fRec5[1] + dsp->fRec5[2])));
+			dsp->fRec26[0] = ((fSlow53 * dsp->fRec26[1]) + (fSlow54 * (dsp->fRec5[1] + (fSlow55 * dsp->fRec27[0]))));
+			dsp->fVec8[(dsp->IOTA & 32767)] = ((0.353553f * dsp->fRec26[0]) + 1e-20f);
+			float fTemp9 = (fTemp5 + ((0.6f * dsp->fRec24[1]) + dsp->fVec8[((dsp->IOTA - dsp->iConst23) & 32767)]));
+			dsp->fVec9[(dsp->IOTA & 4095)] = fTemp9;
+			dsp->fRec24[0] = dsp->fVec9[((dsp->IOTA - dsp->iConst24) & 4095)];
+			float fRec25 = (0.f - (0.6f * fTemp9));
+			dsp->fRec31[0] = ((fSlow26 * dsp->fRec31[1]) + (fSlow27 * (dsp->fRec10[1] + dsp->fRec10[2])));
+			dsp->fRec30[0] = ((fSlow62 * dsp->fRec30[1]) + (fSlow63 * (dsp->fRec10[1] + (fSlow64 * dsp->fRec31[0]))));
+			dsp->fVec10[(dsp->IOTA & 16383)] = ((0.353553f * dsp->fRec30[0]) + 1e-20f);
+			float fTemp10 = (0.3f * dsp->fVec0[((dsp->IOTA - iSlow28) & 8191)]);
+			float fTemp11 = (dsp->fVec10[((dsp->IOTA - dsp->iConst28) & 16383)] - (fTemp10 + (0.6f * dsp->fRec28[1])));
+			dsp->fVec11[(dsp->IOTA & 2047)] = fTemp11;
+			dsp->fRec28[0] = dsp->fVec11[((dsp->IOTA - dsp->iConst29) & 2047)];
+			float fRec29 = (0.6f * fTemp11);
+			dsp->fRec35[0] = ((fSlow26 * dsp->fRec35[1]) + (fSlow27 * (dsp->fRec6[1] + dsp->fRec6[2])));
+			dsp->fRec34[0] = ((fSlow71 * dsp->fRec34[1]) + (fSlow72 * (dsp->fRec6[1] + (fSlow73 * dsp->fRec35[0]))));
+			dsp->fVec12[(dsp->IOTA & 16383)] = ((0.353553f * dsp->fRec34[0]) + 1e-20f);
+			float fTemp12 = (dsp->fVec12[((dsp->IOTA - dsp->iConst33) & 16383)] - (fTemp10 + (0.6f * dsp->fRec32[1])));
+			dsp->fVec13[(dsp->IOTA & 4095)] = fTemp12;
+			dsp->fRec32[0] = dsp->fVec13[((dsp->IOTA - dsp->iConst34) & 4095)];
+			float fRec33 = (0.6f * fTemp12);
+			dsp->fRec39[0] = ((fSlow26 * dsp->fRec39[1]) + (fSlow27 * (dsp->fRec8[1] + dsp->fRec8[2])));
+			dsp->fRec38[0] = ((fSlow80 * dsp->fRec38[1]) + (fSlow81 * (dsp->fRec8[1] + (fSlow82 * dsp->fRec39[0]))));
+			dsp->fVec14[(dsp->IOTA & 16383)] = ((0.353553f * dsp->fRec38[0]) + 1e-20f);
+			float fTemp13 = ((fTemp10 + dsp->fVec14[((dsp->IOTA - dsp->iConst38) & 16383)]) - (0.6f * dsp->fRec36[1]));
+			dsp->fVec15[(dsp->IOTA & 4095)] = fTemp13;
+			dsp->fRec36[0] = dsp->fVec15[((dsp->IOTA - dsp->iConst39) & 4095)];
+			float fRec37 = (0.6f * fTemp13);
+			dsp->fRec43[0] = ((fSlow26 * dsp->fRec43[1]) + (fSlow27 * (dsp->fRec4[1] + dsp->fRec4[2])));
+			dsp->fRec42[0] = ((fSlow89 * dsp->fRec42[1]) + (fSlow90 * (dsp->fRec4[1] + (fSlow91 * dsp->fRec43[0]))));
+			dsp->fVec16[(dsp->IOTA & 16383)] = ((0.353553f * dsp->fRec42[0]) + 1e-20f);
+			float fTemp14 = ((dsp->fVec16[((dsp->IOTA - dsp->iConst43) & 16383)] + fTemp10) - (0.6f * dsp->fRec40[1]));
+			dsp->fVec17[(dsp->IOTA & 2047)] = fTemp14;
+			dsp->fRec40[0] = dsp->fVec17[((dsp->IOTA - dsp->iConst44) & 2047)];
+			float fRec41 = (0.6f * fTemp14);
+			float fTemp15 = (fRec41 + fRec37);
+			float fTemp16 = (fRec29 + (fRec33 + fTemp15));
+			dsp->fRec4[0] = (dsp->fRec12[1] + (dsp->fRec16[1] + (dsp->fRec20[1] + (dsp->fRec24[1] + (dsp->fRec28[1] + (dsp->fRec32[1] + (dsp->fRec36[1] + (dsp->fRec40[1] + (fRec13 + (fRec17 + (fRec21 + (fRec25 + fTemp16))))))))))));
+			dsp->fRec5[0] = (0.f - ((dsp->fRec12[1] + (dsp->fRec16[1] + (dsp->fRec20[1] + (dsp->fRec24[1] + (fRec13 + (fRec17 + (fRec25 + fRec21))))))) - (dsp->fRec28[1] + (dsp->fRec32[1] + (dsp->fRec36[1] + (dsp->fRec40[1] + fTemp16))))));
+			float fTemp17 = (fRec33 + fRec29);
+			dsp->fRec6[0] = (0.f - ((dsp->fRec12[1] + (dsp->fRec16[1] + (dsp->fRec28[1] + (dsp->fRec32[1] + (fRec13 + (fRec17 + fTemp17)))))) - (dsp->fRec20[1] + (dsp->fRec24[1] + (dsp->fRec36[1] + (dsp->fRec40[1] + (fRec21 + (fRec25 + fTemp15))))))));
+			dsp->fRec7[0] = (0.f - ((dsp->fRec20[1] + (dsp->fRec24[1] + (dsp->fRec28[1] + (dsp->fRec32[1] + (fRec21 + (fRec25 + fTemp17)))))) - (dsp->fRec12[1] + (dsp->fRec16[1] + (dsp->fRec36[1] + (dsp->fRec40[1] + (fRec13 + (fRec17 + fTemp15))))))));
+			float fTemp18 = (fRec37 + fRec29);
+			float fTemp19 = (fRec41 + fRec33);
+			dsp->fRec8[0] = (0.f - ((dsp->fRec12[1] + (dsp->fRec20[1] + (dsp->fRec28[1] + (dsp->fRec36[1] + (fRec13 + (fRec21 + fTemp18)))))) - (dsp->fRec16[1] + (dsp->fRec24[1] + (dsp->fRec32[1] + (dsp->fRec40[1] + (fRec17 + (fRec25 + fTemp19))))))));
+			dsp->fRec9[0] = (0.f - ((dsp->fRec16[1] + (dsp->fRec24[1] + (dsp->fRec28[1] + (dsp->fRec36[1] + (fRec17 + (fRec25 + fTemp18)))))) - (dsp->fRec12[1] + (dsp->fRec20[1] + (dsp->fRec32[1] + (dsp->fRec40[1] + (fRec13 + (fRec21 + fTemp19))))))));
+			float fTemp20 = (fRec37 + fRec33);
+			float fTemp21 = (fRec41 + fRec29);
+			dsp->fRec10[0] = (0.f - ((dsp->fRec16[1] + (dsp->fRec20[1] + (dsp->fRec32[1] + (dsp->fRec36[1] + (fRec17 + (fRec21 + fTemp20)))))) - (dsp->fRec12[1] + (dsp->fRec24[1] + (dsp->fRec28[1] + (dsp->fRec40[1] + (fRec13 + (fRec25 + fTemp21))))))));
+			dsp->fRec11[0] = (0.f - ((dsp->fRec12[1] + (dsp->fRec24[1] + (dsp->fRec32[1] + (dsp->fRec36[1] + (fRec13 + (fRec25 + fTemp20)))))) - (dsp->fRec16[1] + (dsp->fRec20[1] + (dsp->fRec28[1] + (dsp->fRec40[1] + (fRec17 + (fRec21 + fTemp21))))))));
+			float fTemp22 = (0.37f * (dsp->fRec5[0] + dsp->fRec6[0]));
+			dsp->fRec3[0] = (0.f - ((fTemp3 + (fSlow10 * dsp->fRec3[2])) - fTemp22));
+			float fTemp23 = (fSlow10 * dsp->fRec3[0]);
+			float fTemp24 = (0.5f * ((fTemp23 + (dsp->fRec3[2] + (fTemp22 + fTemp3))) + (fSlow8 * ((fTemp23 + (fTemp3 + dsp->fRec3[2])) - fTemp22))));
+			dsp->fRec2[0] = (0.f - ((fTemp2 + (fSlow5 * dsp->fRec2[2])) - fTemp24));
+			float fTemp25 = (fSlow5 * dsp->fRec2[0]);
+			output0[i] = (FAUSTFLOAT)(dsp->fRec0[0] * ((fTemp0 * fTemp1) + (0.5f * (dsp->fRec1[0] * ((fTemp25 + (dsp->fRec2[2] + (fTemp24 + fTemp2))) + (fSlow3 * ((fTemp25 + (fTemp2 + dsp->fRec2[2])) - fTemp24)))))));
+			float fTemp26 = (fSlow6 * dsp->fRec44[1]);
+			float fTemp27 = (fSlow11 * dsp->fRec45[1]);
+			float fTemp28 = (0.37f * (dsp->fRec5[0] - dsp->fRec6[0]));
+			dsp->fRec45[0] = (0.f - ((fTemp27 + (fSlow10 * dsp->fRec45[2])) - fTemp28));
+			float fTemp29 = (fSlow10 * dsp->fRec45[0]);
+			float fTemp30 = (0.5f * ((fTemp29 + (dsp->fRec45[2] + (fTemp28 + fTemp27))) + (fSlow8 * ((fTemp29 + (fTemp27 + dsp->fRec45[2])) - fTemp28))));
+			dsp->fRec44[0] = (0.f - ((fTemp26 + (fSlow5 * dsp->fRec44[2])) - fTemp30));
+			float fTemp31 = (fSlow5 * dsp->fRec44[0]);
+			output1[i] = (FAUSTFLOAT)(dsp->fRec0[0] * ((fTemp0 * fTemp4) + (0.5f * (dsp->fRec1[0] * ((fTemp31 + (dsp->fRec44[2] + (fTemp30 + fTemp26))) + (fSlow3 * ((fTemp31 + (fTemp26 + dsp->fRec44[2])) - fTemp30)))))));
+			dsp->fRec0[1] = dsp->fRec0[0];
+			dsp->fRec1[1] = dsp->fRec1[0];
+			dsp->IOTA = (dsp->IOTA + 1);
+			dsp->fRec15[1] = dsp->fRec15[0];
+			dsp->fRec14[1] = dsp->fRec14[0];
+			dsp->fRec12[1] = dsp->fRec12[0];
+			dsp->fRec19[1] = dsp->fRec19[0];
+			dsp->fRec18[1] = dsp->fRec18[0];
+			dsp->fRec16[1] = dsp->fRec16[0];
+			dsp->fRec23[1] = dsp->fRec23[0];
+			dsp->fRec22[1] = dsp->fRec22[0];
+			dsp->fRec20[1] = dsp->fRec20[0];
+			dsp->fRec27[1] = dsp->fRec27[0];
+			dsp->fRec26[1] = dsp->fRec26[0];
+			dsp->fRec24[1] = dsp->fRec24[0];
+			dsp->fRec31[1] = dsp->fRec31[0];
+			dsp->fRec30[1] = dsp->fRec30[0];
+			dsp->fRec28[1] = dsp->fRec28[0];
+			dsp->fRec35[1] = dsp->fRec35[0];
+			dsp->fRec34[1] = dsp->fRec34[0];
+			dsp->fRec32[1] = dsp->fRec32[0];
+			dsp->fRec39[1] = dsp->fRec39[0];
+			dsp->fRec38[1] = dsp->fRec38[0];
+			dsp->fRec36[1] = dsp->fRec36[0];
+			dsp->fRec43[1] = dsp->fRec43[0];
+			dsp->fRec42[1] = dsp->fRec42[0];
+			dsp->fRec40[1] = dsp->fRec40[0];
+			dsp->fRec4[2] = dsp->fRec4[1];
+			dsp->fRec4[1] = dsp->fRec4[0];
+			dsp->fRec5[2] = dsp->fRec5[1];
+			dsp->fRec5[1] = dsp->fRec5[0];
+			dsp->fRec6[2] = dsp->fRec6[1];
+			dsp->fRec6[1] = dsp->fRec6[0];
+			dsp->fRec7[2] = dsp->fRec7[1];
+			dsp->fRec7[1] = dsp->fRec7[0];
+			dsp->fRec8[2] = dsp->fRec8[1];
+			dsp->fRec8[1] = dsp->fRec8[0];
+			dsp->fRec9[2] = dsp->fRec9[1];
+			dsp->fRec9[1] = dsp->fRec9[0];
+			dsp->fRec10[2] = dsp->fRec10[1];
+			dsp->fRec10[1] = dsp->fRec10[0];
+			dsp->fRec11[2] = dsp->fRec11[1];
+			dsp->fRec11[1] = dsp->fRec11[0];
+			dsp->fRec3[2] = dsp->fRec3[1];
+			dsp->fRec3[1] = dsp->fRec3[0];
+			dsp->fRec2[2] = dsp->fRec2[1];
+			dsp->fRec2[1] = dsp->fRec2[0];
+			dsp->fRec45[2] = dsp->fRec45[1];
+			dsp->fRec45[1] = dsp->fRec45[0];
+			dsp->fRec44[2] = dsp->fRec44[1];
+			dsp->fRec44[1] = dsp->fRec44[0];
+
+		}
+
+	}
+
+}
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_zitarev *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_zitarev_create(sp_zitarev **p)
+{
+    *p = malloc(sizeof(sp_zitarev));
+    return SP_OK;
+}
+
+int sp_zitarev_destroy(sp_zitarev **p)
+{
+    sp_zitarev *pp = *p;
+    zitarev *dsp = pp->faust;
+    deletezitarev (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_zitarev_init(sp_data *sp, sp_zitarev *p)
+{
+    zitarev *dsp = newzitarev();
+    UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.uiInterface = p;
+    buildUserInterfacezitarev(dsp, &UI);
+    initzitarev(dsp, sp->sr);
+
+    p->in_delay = p->args[0];
+    p->lf_x = p->args[1];
+    p->rt60_low = p->args[2];
+    p->rt60_mid = p->args[3];
+    p->hf_damping = p->args[4];
+    p->eq1_freq = p->args[5];
+    p->eq1_level = p->args[6];
+    p->eq2_freq = p->args[7];
+    p->eq2_level = p->args[8];
+    p->mix = p->args[9];
+    p->level = p->args[10];
+
+    p->faust = dsp;
+    return SP_OK;
+}
+
+int sp_zitarev_compute(sp_data *sp, sp_zitarev *p, SPFLOAT *in1, SPFLOAT *in2, SPFLOAT *out1, SPFLOAT *out2)
+{
+
+    zitarev *dsp = p->faust;
+    SPFLOAT *faust_out[] = {out1, out2};
+    SPFLOAT *faust_in[] = {in1, in2};
+    computezitarev(dsp, 1, faust_in, faust_out);
+    return SP_OK;
+}
--- /dev/null
+++ b/tangled/bigverb.c
@@ -1,0 +1,348 @@
+#line 93 "bigverb.org"
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#define SK_BIGVERB_PRIV
+#include "bigverb.h"
+#line 56 "bigverb.org"
+struct bigverb_paramset {
+    int delay; /* in samples, 44.1 kHz */
+    int drift; /* 1/10 milliseconds */
+    int randfreq; /* Hertz * 1000 */
+    int seed;
+};
+
+static const struct bigverb_paramset params[8] = {
+    {0x09a9, 0x0a, 0xc1c, 0x07ae},
+    {0x0acf, 0x0b, 0xdac, 0x7333},
+    {0x0c91, 0x11, 0x456, 0x5999},
+    {0x0de5, 0x06, 0xf85, 0x2666},
+    {0x0f43, 0x0a, 0x925, 0x50a3},
+    {0x101f, 0x0b, 0x769, 0x5999},
+    {0x085f, 0x11, 0x37b, 0x7333},
+    {0x078d, 0x06, 0xc95, 0x3851}
+};
+#line 93 "bigverb.org"
+#line 851 "bigverb.org"
+#define FRACSCALE 0x10000000
+#line 861 "bigverb.org"
+#define FRACMASK 0xFFFFFFF
+#line 869 "bigverb.org"
+#define FRACNBITS 28
+#line 93 "bigverb.org"
+#line 434 "bigverb.org"
+static int get_delay_size(const struct bigverb_paramset *p, int sr);
+#line 511 "bigverb.org"
+static void delay_init(sk_bigverb_delay *d,
+                       const struct bigverb_paramset *p,
+                       SKFLT *buf,
+                       size_t sz,
+                       int sr);
+#line 619 "bigverb.org"
+static SKFLT delay_compute(sk_bigverb_delay *d,
+                           SKFLT in,
+                           SKFLT fdbk,
+                           SKFLT filt,
+                           int sr);
+#line 896 "bigverb.org"
+static void generate_next_line(sk_bigverb_delay *d, int sr);
+#line 93 "bigverb.org"
+#line 148 "bigverb.org"
+sk_bigverb * sk_bigverb_new(int sr)
+{
+    sk_bigverb *bv;
+
+    bv = calloc(1, sizeof(sk_bigverb));
+
+    bv->sr = sr;
+#line 207 "bigverb.org"
+sk_bigverb_size(bv, 0.93);
+#line 233 "bigverb.org"
+sk_bigverb_cutoff(bv, 10000.0);
+#line 252 "bigverb.org"
+bv->pcutoff = -1;
+#line 272 "bigverb.org"
+bv->filt = 1.0;
+#line 402 "bigverb.org"
+bv->buf = NULL;
+#line 148 "bigverb.org"
+#line 407 "bigverb.org"
+{
+unsigned long total_size;
+int i;
+SKFLT *buf;
+
+total_size = 0;
+buf = NULL;
+#line 449 "bigverb.org"
+for (i = 0; i < 8; i++) {
+    total_size += get_delay_size(&params[i], sr);
+}
+#line 407 "bigverb.org"
+#line 460 "bigverb.org"
+buf = calloc(1, sizeof(SKFLT) * total_size);
+bv->buf = buf;
+#line 407 "bigverb.org"
+#line 476 "bigverb.org"
+{
+    unsigned long bufpos;
+    bufpos = 0;
+    for (i = 0; i < 8; i++) {
+        unsigned int sz;
+        sz = get_delay_size(&params[i], sr);
+
+        delay_init(&bv->delay[i], &params[i],
+                   &buf[bufpos], sz, sr);
+        bufpos += sz;
+    }
+}
+#line 417 "bigverb.org"
+}
+#line 157 "bigverb.org"
+
+    return bv;
+}
+#line 172 "bigverb.org"
+void sk_bigverb_del(sk_bigverb *bv)
+{
+#line 466 "bigverb.org"
+free(bv->buf);
+#line 175 "bigverb.org"
+    free(bv);
+    bv = NULL;
+}
+#line 212 "bigverb.org"
+void sk_bigverb_size(sk_bigverb *bv, SKFLT size)
+{
+    bv->size = size;
+}
+#line 257 "bigverb.org"
+void sk_bigverb_cutoff(sk_bigverb *bv, SKFLT cutoff)
+{
+    bv->cutoff = cutoff;
+}
+#line 296 "bigverb.org"
+void sk_bigverb_tick(sk_bigverb *bv,
+                     SKFLT inL, SKFLT inR,
+                     SKFLT *outL, SKFLT *outR)
+{
+    /* TODO: implement */
+    SKFLT lsum, rsum;
+
+    lsum = 0;
+    rsum = 0;
+
+#line 329 "bigverb.org"
+if (bv->pcutoff != bv->cutoff) {
+    bv->pcutoff = bv->cutoff;
+    bv->filt = 2.0 - cos(bv->pcutoff * 2 * M_PI / bv->sr);
+    bv->filt = bv->filt - sqrt(bv->filt * bv->filt - 1.0);
+}
+#line 296 "bigverb.org"
+#line 344 "bigverb.org"
+{
+    int i;
+    SKFLT jp;
+
+    jp = 0;
+
+    for (i = 0; i < 8; i++) {
+        jp += bv->delay[i].y;
+    }
+
+    jp *= 0.25;
+
+    inL = jp + inL;
+    inR = jp + inR;
+}
+#line 296 "bigverb.org"
+#line 370 "bigverb.org"
+{
+    int i;
+    for (i = 0; i < 8; i++) {
+        if (i & 1) {
+            rsum += delay_compute(&bv->delay[i],
+                                  inR,
+                                  bv->size,
+                                  bv->filt,
+                                  bv->sr);
+        } else {
+            lsum += delay_compute(&bv->delay[i],
+                                  inL,
+                                  bv->size,
+                                  bv->filt,
+                                  bv->sr);
+        }
+    }
+}
+rsum *= 0.35f;
+lsum *= 0.35f;
+#line 309 "bigverb.org"
+
+    *outL = lsum;
+    *outR = rsum;
+}
+#line 439 "bigverb.org"
+static int get_delay_size(const struct bigverb_paramset *p, int sr)
+{
+    SKFLT sz;
+    sz = (SKFLT)p->delay/44100 + (p->drift * 0.0001) * 1.125;
+    return floor(16 + sz*sr);
+}
+#line 520 "bigverb.org"
+static void delay_init(sk_bigverb_delay *d,
+                       const struct bigverb_paramset *p,
+                       SKFLT *buf,
+                       size_t sz,
+                       int sr)
+{
+    SKFLT readpos;
+#line 541 "bigverb.org"
+d->buf = buf;
+d->sz = sz;
+#line 554 "bigverb.org"
+d->wpos = 0;
+#line 578 "bigverb.org"
+d->rng = p->seed;
+#line 592 "bigverb.org"
+readpos = ((SKFLT)p->delay / 44100);
+readpos += d->rng * (p->drift * 0.0001) / 32768.0;
+readpos = sz - (readpos * sr);
+d->irpos = floor(readpos);
+d->frpos = floor((readpos - d->irpos) * FRACSCALE);
+#line 578 "bigverb.org"
+#line 592 "bigverb.org"
+#line 886 "bigverb.org"
+d->inc = 0;
+d->counter = 0;
+#line 935 "bigverb.org"
+d->maxcount = round((sr / ((SKFLT)p->randfreq * 0.001)));
+#line 973 "bigverb.org"
+d->dels = p->delay / 44100.0;
+#line 983 "bigverb.org"
+d->drift = p->drift;
+#line 604 "bigverb.org"
+generate_next_line(d, sr);
+#line 1034 "bigverb.org"
+d->y = 0.0;
+#line 528 "bigverb.org"
+}
+#line 628 "bigverb.org"
+static SKFLT delay_compute(sk_bigverb_delay *del,
+                           SKFLT in,
+                           SKFLT fdbk,
+                           SKFLT filt,
+                           int sr)
+{
+    SKFLT out;
+    SKFLT frac_norm;
+    SKFLT a, b, c, d;
+    SKFLT s[4];
+    out = 0;
+#line 666 "bigverb.org"
+del->buf[del->wpos] = in - del->y;
+#line 628 "bigverb.org"
+#line 674 "bigverb.org"
+del->wpos++;
+if (del->wpos >= del->sz) del->wpos -= del->sz;
+#line 628 "bigverb.org"
+#line 686 "bigverb.org"
+if (del->frpos >= FRACSCALE) {
+    del->irpos += del->frpos >> FRACNBITS;
+    del->frpos &= FRACMASK;
+}
+#line 628 "bigverb.org"
+#line 696 "bigverb.org"
+if (del->irpos >= del->sz) del->irpos -= del->sz;
+#line 628 "bigverb.org"
+#line 705 "bigverb.org"
+frac_norm = del->frpos / (SKFLT)FRACSCALE;
+#line 628 "bigverb.org"
+#line 718 "bigverb.org"
+{
+    SKFLT tmp[2];
+    d = ((frac_norm * frac_norm) - 1) / 6.0;
+    tmp[0] = ((frac_norm + 1.0) * 0.5);
+    tmp[1] = 3.0 * d;
+    a = tmp[0] - 1.0 - d;
+    c = tmp[0] - tmp[1];
+    b = tmp[1] - frac_norm;
+}
+#line 628 "bigverb.org"
+#line 737 "bigverb.org"
+{
+    int n;
+    SKFLT *x;
+    n = del->irpos;
+    x = del->buf;
+
+    if (n > 0 && n < (del->sz - 2)) {
+        s[0] = x[n - 1];
+        s[1] = x[n];
+        s[2] = x[n + 1];
+        s[3] = x[n + 2];
+    } else {
+        int k;
+        n--;
+        if (n < 0) n += del->sz;
+        s[0] = x[n];
+        for (k = 0; k < 3; k++) {
+            n++;
+            if (n >= del->sz) n -= del->sz;
+            s[k + 1] = x[n];
+        }
+    }
+}
+#line 628 "bigverb.org"
+#line 772 "bigverb.org"
+out = (a*s[0] + b*s[1] + c*s[2] + d*s[3]) * frac_norm + s[1];
+#line 628 "bigverb.org"
+#line 780 "bigverb.org"
+del->frpos += del->inc;
+#line 628 "bigverb.org"
+#line 790 "bigverb.org"
+out *= fdbk;
+out += (del->y - out) * filt;
+del->y = out;
+#line 628 "bigverb.org"
+#line 817 "bigverb.org"
+del->counter--;
+if (del->counter <= 0) {
+    generate_next_line(del, sr);
+}
+#line 650 "bigverb.org"
+    return out;
+}
+#line 1008 "bigverb.org"
+static void generate_next_line(sk_bigverb_delay *d, int sr)
+{
+    SKFLT curdel;
+    SKFLT nxtdel;
+    SKFLT inc;
+#line 915 "bigverb.org"
+if (d->rng < 0) d->rng += 0x10000;
+/* 5^6 = 15625 */
+d->rng = (1 + d->rng * 0x3d09);
+d->rng &= 0xFFFF;
+if (d->rng >= 0x8000) d->rng -= 0x10000;
+#line 1008 "bigverb.org"
+#line 940 "bigverb.org"
+d->counter = d->maxcount;
+#line 1008 "bigverb.org"
+#line 950 "bigverb.org"
+curdel = d->wpos -
+    (d->irpos + (d->frpos/(SKFLT)FRACSCALE));
+while (curdel < 0) curdel += d->sz;
+curdel /= sr;
+#line 961 "bigverb.org"
+nxtdel = (d->rng * (d->drift * 0.0001) / 32768.0) + d->dels;
+#line 1008 "bigverb.org"
+#line 994 "bigverb.org"
+inc = ((curdel - nxtdel) / (SKFLT)d->counter)*sr;
+inc += 1;
+#line 1008 "bigverb.org"
+#line 1003 "bigverb.org"
+d->inc = floor(inc * FRACSCALE);
+#line 1018 "bigverb.org"
+}
+#line 93 "bigverb.org"
--- /dev/null
+++ b/tangled/bigverb.h
@@ -1,0 +1,72 @@
+#line 106 "bigverb.org"
+#ifndef SK_BIGVERB_H
+#define SK_BIGVERB_H
+
+#ifndef SKFLT
+#define SKFLT float
+#endif
+#line 125 "bigverb.org"
+typedef struct sk_bigverb sk_bigverb;
+#line 499 "bigverb.org"
+typedef struct sk_bigverb_delay sk_bigverb_delay;
+#line 106 "bigverb.org"
+#line 143 "bigverb.org"
+sk_bigverb * sk_bigverb_new(int sr);
+#line 167 "bigverb.org"
+void sk_bigverb_del(sk_bigverb *bv);
+#line 190 "bigverb.org"
+void sk_bigverb_size(sk_bigverb *bv, SKFLT size);
+#line 222 "bigverb.org"
+void sk_bigverb_cutoff(sk_bigverb *bv, SKFLT cutoff);
+#line 289 "bigverb.org"
+void sk_bigverb_tick(sk_bigverb *bv,
+                     SKFLT inL, SKFLT inR,
+                     SKFLT *outL, SKFLT *outR);
+#line 114 "bigverb.org"
+
+#ifdef SK_BIGVERB_PRIV
+#line 125 "bigverb.org"
+#line 504 "bigverb.org"
+struct sk_bigverb_delay {
+#line 535 "bigverb.org"
+SKFLT *buf;
+size_t sz;
+#line 549 "bigverb.org"
+int wpos;
+#line 564 "bigverb.org"
+int irpos;
+int frpos;
+#line 573 "bigverb.org"
+int rng;
+#line 880 "bigverb.org"
+int inc;
+int counter;
+#line 930 "bigverb.org"
+int maxcount;
+#line 968 "bigverb.org"
+SKFLT dels;
+#line 978 "bigverb.org"
+SKFLT drift;
+#line 1029 "bigverb.org"
+SKFLT y;
+#line 506 "bigverb.org"
+};
+#line 131 "bigverb.org"
+struct sk_bigverb {
+    int sr;
+#line 202 "bigverb.org"
+SKFLT size;
+#line 246 "bigverb.org"
+SKFLT cutoff;
+SKFLT pcutoff;
+#line 267 "bigverb.org"
+SKFLT filt;
+#line 397 "bigverb.org"
+SKFLT *buf;
+#line 471 "bigverb.org"
+sk_bigverb_delay delay[8];
+#line 134 "bigverb.org"
+};
+#line 117 "bigverb.org"
+#endif
+#endif
--- /dev/null
+++ b/tangled/dcblocker.c
@@ -1,0 +1,18 @@
+#line 43 "dcblocker.org"
+#define SK_DCBLOCKER_PRIV
+#include "dcblocker.h"
+#line 92 "dcblocker.org"
+void sk_dcblocker_init(sk_dcblocker *dcblk)
+{
+    dcblk->x = 0;
+    dcblk->y = 0;
+    dcblk->R = 0.99; /* quite reasonable, indeed! */
+}
+#line 112 "dcblocker.org"
+SKFLT sk_dcblocker_tick(sk_dcblocker *dcblk, SKFLT in)
+{
+    dcblk->y = in - dcblk->x + dcblk->R*dcblk->y;
+    dcblk->x = in;
+    return dcblk->y;
+}
+#line 43 "dcblocker.org"
--- /dev/null
+++ b/tangled/dcblocker.h
@@ -1,0 +1,22 @@
+#line 50 "dcblocker.org"
+#ifndef SK_DCBLOCKER_H
+#define SK_DCBLOCKER_H
+#ifndef SKFLT
+#define SKFLT float
+#endif
+#line 71 "dcblocker.org"
+typedef struct sk_dcblocker sk_dcblocker;
+#line 56 "dcblocker.org"
+#ifdef SK_DCBLOCKER_PRIV
+#line 75 "dcblocker.org"
+struct sk_dcblocker {
+    SKFLT x, y, R;
+};
+#line 58 "dcblocker.org"
+#endif
+#line 87 "dcblocker.org"
+void sk_dcblocker_init(sk_dcblocker *dcblk);
+#line 107 "dcblocker.org"
+SKFLT sk_dcblocker_tick(sk_dcblocker *dcblk, SKFLT in);
+#line 60 "dcblocker.org"
+#endif
--- /dev/null
+++ b/tangled/fmpair.c
@@ -1,0 +1,215 @@
+#line 130 "fmpair.org"
+#include <math.h>
+#define SK_FMPAIR_PRIV
+#include "fmpair.h"
+#line 178 "fmpair.org"
+#define SK_FMPAIR_MAXLEN 0x1000000L
+#define SK_FMPAIR_PHASEMASK 0x0FFFFFFL
+#line 130 "fmpair.org"
+#line 303 "fmpair.org"
+void sk_fmpair_init(sk_fmpair *fmp, int sr,
+                    SKFLT *ctab, int csz, SKFLT ciphs,
+                    SKFLT *mtab, int msz, SKFLT miphs)
+{
+#line 198 "fmpair.org"
+fmp->ctab = ctab;
+fmp->csz = msz;
+#line 214 "fmpair.org"
+fmp->mtab = mtab;
+fmp->msz = msz;
+#line 226 "fmpair.org"
+fmp->clphs = floor(ciphs * SK_FMPAIR_MAXLEN);
+fmp->mlphs = floor(miphs * SK_FMPAIR_MAXLEN);
+#line 253 "fmpair.org"
+{
+    int tmp;
+
+    /* carrier */
+    tmp = SK_FMPAIR_MAXLEN / csz;
+    fmp->cnlb = 0;
+    while (tmp >>= 1) fmp->cnlb++;
+
+    /* modulator */
+    tmp = SK_FMPAIR_MAXLEN / msz;
+    fmp->mnlb = 0;
+    while (tmp >>= 1) fmp->mnlb++;
+}
+
+/* phase mask for dividing lower/upper bits */
+
+fmp->cmask = (1<<fmp->cnlb) - 1;
+fmp->mmask = (1<<fmp->mnlb) - 1;
+
+/* constant used to convert to floating point */
+
+fmp->cinlb = 1.0 / (1<<fmp->cnlb);
+fmp->minlb = 1.0 / (1<<fmp->mnlb);
+
+/* max table length in seconds */
+/* used to convert cycles-per-second units to cycles */
+
+fmp->maxlens = 1.0 * SK_FMPAIR_MAXLEN / sr;
+#line 336 "fmpair.org"
+sk_fmpair_freq(fmp, 440);
+#line 370 "fmpair.org"
+sk_fmpair_carrier(fmp, 1);
+sk_fmpair_modulator(fmp, 1);
+#line 399 "fmpair.org"
+sk_fmpair_modindex(fmp, 1);
+#line 308 "fmpair.org"
+}
+#line 321 "fmpair.org"
+void sk_fmpair_freq(sk_fmpair *fmp, SKFLT freq)
+{
+    fmp->freq = freq;
+}
+#line 349 "fmpair.org"
+void sk_fmpair_modulator(sk_fmpair *fmp, SKFLT mod)
+{
+    fmp->mod = mod;
+}
+
+void sk_fmpair_carrier(sk_fmpair *fmp, SKFLT car)
+{
+    fmp->car = car;
+}
+#line 383 "fmpair.org"
+void sk_fmpair_modindex(sk_fmpair *fmp, SKFLT index)
+{
+    fmp->index = index;
+}
+#line 411 "fmpair.org"
+SKFLT sk_fmpair_tick(sk_fmpair *fmp)
+{
+    SKFLT out;
+    SKFLT cfreq, mfreq;
+    SKFLT modout;
+    int ipos;
+    SKFLT frac;
+    SKFLT x[2];
+    out = 0;
+#line 436 "fmpair.org"
+cfreq = fmp->freq * fmp->car;
+mfreq = fmp->freq * fmp->mod;
+#line 411 "fmpair.org"
+#line 446 "fmpair.org"
+fmp->mlphs &= SK_FMPAIR_PHASEMASK;
+ipos = fmp->mlphs >> fmp->mnlb;
+x[0] = fmp->mtab[ipos];
+
+if (ipos == fmp->msz - 1) {
+    x[1] = fmp->mtab[0];
+} else {
+    x[1] = fmp->mtab[ipos + 1];
+}
+
+frac = (fmp->mlphs & fmp->mmask) * fmp->minlb;
+modout = (x[0] + (x[1] - x[0]) * frac);
+#line 411 "fmpair.org"
+#line 467 "fmpair.org"
+modout *= mfreq * fmp->index;
+#line 411 "fmpair.org"
+#line 476 "fmpair.org"
+cfreq += modout;
+#line 411 "fmpair.org"
+#line 485 "fmpair.org"
+fmp->clphs &= SK_FMPAIR_PHASEMASK;
+ipos = (fmp->clphs) >> fmp->cnlb;
+x[0] = fmp->ctab[ipos];
+
+if (ipos == fmp->csz - 1) {
+    x[1] = fmp->ctab[0];
+} else {
+    x[1] = fmp->ctab[ipos + 1];
+}
+
+frac = (fmp->clphs & fmp->cmask) * fmp->cinlb;
+out = (x[0] + (x[1] - x[0]) * frac);
+#line 411 "fmpair.org"
+#line 512 "fmpair.org"
+fmp->clphs += floor(cfreq * fmp->maxlens);
+fmp->mlphs += floor(mfreq * fmp->maxlens);
+#line 426 "fmpair.org"
+    return out;
+}
+#line 555 "fmpair.org"
+void sk_fmpair_fdbk_init(sk_fmpair_fdbk *fmp, int sr,
+                         SKFLT *ctab, int csz, SKFLT ciphs,
+                         SKFLT *mtab, int msz, SKFLT miphs)
+{
+    sk_fmpair_init(&fmp->fmpair, sr,
+                   ctab, csz, ciphs,
+                   mtab, msz, miphs);
+    fmp->prev = 0;
+    fmp->feedback = 0;
+}
+#line 576 "fmpair.org"
+void sk_fmpair_fdbk_amt(sk_fmpair_fdbk *f, SKFLT amt)
+{
+    f->feedback = amt;
+}
+#line 599 "fmpair.org"
+SKFLT sk_fmpair_fdbk_tick(sk_fmpair_fdbk *f)
+{
+    SKFLT out;
+    SKFLT cfreq, mfreq;
+    SKFLT modout;
+    int ipos;
+    SKFLT frac;
+    SKFLT x[2];
+    sk_fmpair *fmp;
+    out = 0;
+    fmp = &f->fmpair;
+
+#line 436 "fmpair.org"
+cfreq = fmp->freq * fmp->car;
+mfreq = fmp->freq * fmp->mod;
+#line 599 "fmpair.org"
+#line 446 "fmpair.org"
+fmp->mlphs &= SK_FMPAIR_PHASEMASK;
+ipos = fmp->mlphs >> fmp->mnlb;
+x[0] = fmp->mtab[ipos];
+
+if (ipos == fmp->msz - 1) {
+    x[1] = fmp->mtab[0];
+} else {
+    x[1] = fmp->mtab[ipos + 1];
+}
+
+frac = (fmp->mlphs & fmp->mmask) * fmp->minlb;
+modout = (x[0] + (x[1] - x[0]) * frac);
+#line 599 "fmpair.org"
+#line 467 "fmpair.org"
+modout *= mfreq * fmp->index;
+#line 614 "fmpair.org"
+
+    /* feedback-oscillator specific */
+#line 632 "fmpair.org"
+modout += f->prev * f->feedback;
+f->prev = modout;
+#line 617 "fmpair.org"
+
+#line 476 "fmpair.org"
+cfreq += modout;
+#line 617 "fmpair.org"
+#line 485 "fmpair.org"
+fmp->clphs &= SK_FMPAIR_PHASEMASK;
+ipos = (fmp->clphs) >> fmp->cnlb;
+x[0] = fmp->ctab[ipos];
+
+if (ipos == fmp->csz - 1) {
+    x[1] = fmp->ctab[0];
+} else {
+    x[1] = fmp->ctab[ipos + 1];
+}
+
+frac = (fmp->clphs & fmp->cmask) * fmp->cinlb;
+out = (x[0] + (x[1] - x[0]) * frac);
+#line 617 "fmpair.org"
+#line 512 "fmpair.org"
+fmp->clphs += floor(cfreq * fmp->maxlens);
+fmp->mlphs += floor(mfreq * fmp->maxlens);
+#line 621 "fmpair.org"
+    return out;
+}
+#line 130 "fmpair.org"
--- /dev/null
+++ b/tangled/fmpair.h
@@ -1,0 +1,74 @@
+#line 143 "fmpair.org"
+#ifndef SK_FMPAIR_H
+#define SK_FMPAIR_H
+#ifndef SKFLT
+#define SKFLT float
+#endif
+#line 160 "fmpair.org"
+typedef struct sk_fmpair sk_fmpair;
+#line 526 "fmpair.org"
+typedef struct sk_fmpair_fdbk sk_fmpair_fdbk;
+#line 143 "fmpair.org"
+#line 296 "fmpair.org"
+void sk_fmpair_init(sk_fmpair *fmp, int sr,
+                    SKFLT *ctab, int csz, SKFLT ciphs,
+                    SKFLT *mtab, int msz, SKFLT miphs);
+#line 316 "fmpair.org"
+void sk_fmpair_freq(sk_fmpair *fmp, SKFLT freq);
+#line 343 "fmpair.org"
+void sk_fmpair_modulator(sk_fmpair *fmp, SKFLT mod);
+void sk_fmpair_carrier(sk_fmpair *fmp, SKFLT car);
+#line 378 "fmpair.org"
+void sk_fmpair_modindex(sk_fmpair *fmp, SKFLT index);
+#line 406 "fmpair.org"
+SKFLT sk_fmpair_tick(sk_fmpair *fmp);
+#line 548 "fmpair.org"
+void sk_fmpair_fdbk_init(sk_fmpair_fdbk *fmp, int sr,
+                         SKFLT *ctab, int csz, SKFLT ciphs,
+                         SKFLT *mtab, int msz, SKFLT miphs);
+#line 571 "fmpair.org"
+void sk_fmpair_fdbk_amt(sk_fmpair_fdbk *f, SKFLT amt);
+#line 587 "fmpair.org"
+SKFLT sk_fmpair_fdbk_tick(sk_fmpair_fdbk *fmp);
+#line 150 "fmpair.org"
+#ifdef SK_FMPAIR_PRIV
+#line 165 "fmpair.org"
+struct sk_fmpair {
+#line 191 "fmpair.org"
+SKFLT *ctab;
+int csz;
+int clphs;
+#line 207 "fmpair.org"
+SKFLT *mtab;
+int msz;
+int mlphs;
+#line 238 "fmpair.org"
+/* carrier constants */
+int cnlb;
+SKFLT cinlb;
+unsigned long cmask;
+
+/* modulator constants */
+int mnlb;
+SKFLT minlb;
+unsigned long mmask;
+
+SKFLT maxlens;
+#line 329 "fmpair.org"
+SKFLT freq;
+#line 362 "fmpair.org"
+SKFLT car;
+SKFLT mod;
+#line 391 "fmpair.org"
+SKFLT index;
+#line 167 "fmpair.org"
+};
+#line 536 "fmpair.org"
+struct sk_fmpair_fdbk {
+    sk_fmpair fmpair;
+    SKFLT prev;
+    SKFLT feedback;
+};
+#line 152 "fmpair.org"
+#endif
+#endif
--- /dev/null
+++ b/tangled/modalres.c
@@ -1,0 +1,82 @@
+#line 19 "modalres.org"
+#include <math.h>
+#define SK_MODALRES_PRIV
+#include "modalres.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#line 58 "modalres.org"
+void sk_modalres_init(sk_modalres *mr, int sr)
+{
+#line 92 "modalres.org"
+mr->x = 0;
+mr->y[0] = 0;
+mr->y[1] = 0;
+#line 110 "modalres.org"
+mr->b1 = 0;
+mr->a1 = 0;
+mr->a2 = 0;
+#line 125 "modalres.org"
+mr->sr = sr;
+#line 140 "modalres.org"
+mr->s = 0;
+#line 172 "modalres.org"
+sk_modalres_freq(mr, 1000);
+mr->pfreq = -1;
+#line 204 "modalres.org"
+sk_modalres_q(mr, 1);
+mr->pq = -1;
+#line 61 "modalres.org"
+}
+#line 153 "modalres.org"
+void sk_modalres_freq(sk_modalres *mr, SKFLT freq)
+{
+    mr->freq = freq;
+}
+#line 185 "modalres.org"
+void sk_modalres_q(sk_modalres *mr, SKFLT q)
+{
+    mr->q = q;
+}
+#line 217 "modalres.org"
+SKFLT sk_modalres_tick(sk_modalres *mr, SKFLT in)
+{
+    SKFLT out;
+
+    out = 0;
+#line 246 "modalres.org"
+if (mr->freq != mr->pfreq || mr->q != mr->pq) {
+    SKFLT w;
+    SKFLT a, b, d;
+
+    w = mr->freq * 2.0 * M_PI;
+
+    a = mr->sr / w;
+    b = a*a;
+    d = 0.5*a;
+
+    mr->pfreq = mr->freq;
+    mr->pq = mr->q;
+
+    mr->b1 = 1.0 / (b + d/mr->q);
+    mr->a1 = (1.0 - 2.0*b) * mr->b1;
+    mr->a2 = (b - d/mr->q) * mr->b1;
+    mr->s = d;
+}
+#line 217 "modalres.org"
+#line 285 "modalres.org"
+out = mr->b1*mr->x - mr->a1*mr->y[0] - mr->a2*mr->y[1];
+#line 217 "modalres.org"
+#line 295 "modalres.org"
+mr->y[1] = mr->y[0];
+mr->y[0] = out;
+mr->x = in;
+#line 217 "modalres.org"
+#line 305 "modalres.org"
+out *= mr->s;
+#line 226 "modalres.org"
+    return out;
+}
+#line 19 "modalres.org"
--- /dev/null
+++ b/tangled/modalres.h
@@ -1,0 +1,46 @@
+#line 32 "modalres.org"
+#ifndef SK_MODALRES_H
+#define SK_MODALRES_H
+
+#ifndef SKFLT
+#define SKFLT float
+#endif
+
+#line 68 "modalres.org"
+typedef struct sk_modalres sk_modalres;
+#line 32 "modalres.org"
+#line 53 "modalres.org"
+void sk_modalres_init(sk_modalres *mr, int sr);
+#line 148 "modalres.org"
+void sk_modalres_freq(sk_modalres *mr, SKFLT freq);
+#line 180 "modalres.org"
+void sk_modalres_q(sk_modalres *mr, SKFLT q);
+#line 212 "modalres.org"
+SKFLT sk_modalres_tick(sk_modalres *mr, SKFLT in);
+#line 41 "modalres.org"
+
+#ifdef SK_MODALRES_PRIV
+#line 73 "modalres.org"
+struct sk_modalres {
+#line 86 "modalres.org"
+SKFLT x;
+SKFLT y[2];
+#line 103 "modalres.org"
+SKFLT b1;
+SKFLT a1;
+SKFLT a2;
+#line 120 "modalres.org"
+int sr;
+#line 135 "modalres.org"
+SKFLT s;
+#line 161 "modalres.org"
+SKFLT freq;
+SKFLT pfreq;
+#line 198 "modalres.org"
+SKFLT q;
+SKFLT pq;
+#line 75 "modalres.org"
+};
+#line 44 "modalres.org"
+#endif
+#endif
--- /dev/null
+++ b/tangled/osc.c
@@ -1,0 +1,84 @@
+#line 44 "osc.org"
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#define SK_OSC_PRIV
+#include "osc.h"
+#line 105 "osc.org"
+#define SK_OSC_MAXLEN 0x1000000L
+#define SK_OSC_PHASEMASK 0x0FFFFFFL
+#line 44 "osc.org"
+#line 92 "osc.org"
+void sk_osc_freq(sk_osc *osc, SKFLT freq)
+{
+    osc->freq = freq;
+}
+
+void sk_osc_amp(sk_osc *osc, SKFLT amp)
+{
+    osc->amp = amp;
+}
+#line 254 "osc.org"
+void sk_osc_init(sk_osc *osc, int sr, SKFLT *wt, int sz, SKFLT iphs)
+{
+#line 140 "osc.org"
+osc->freq = 440;
+osc->amp = 0.2;
+#line 149 "osc.org"
+osc->tab = wt;
+osc->sz = sz;
+#line 160 "osc.org"
+osc->inc = 0;
+#line 170 "osc.org"
+osc->lphs = ((int32_t)(iphs * SK_OSC_MAXLEN)) & SK_OSC_PHASEMASK;
+#line 205 "osc.org"
+{
+    uint32_t tmp;
+    tmp = SK_OSC_MAXLEN / sz;
+    osc->nlb = 0;
+    while (tmp >>= 1) osc->nlb++;
+}
+#line 228 "osc.org"
+osc->mask = (1<<osc->nlb) - 1;
+#line 205 "osc.org"
+#line 238 "osc.org"
+osc->inlb = 1.0 / (1<<osc->nlb);
+#line 205 "osc.org"
+#line 247 "osc.org"
+osc->maxlens = 1.0 * SK_OSC_MAXLEN / sr;
+#line 205 "osc.org"
+#line 257 "osc.org"
+}
+#line 266 "osc.org"
+SKFLT sk_osc_tick(sk_osc *osc)
+{
+    SKFLT out;
+    SKFLT fract;
+    SKFLT x1, x2;
+    int32_t phs;
+    int pos;
+
+    out = 0;
+#line 331 "osc.org"
+osc->inc = floor(lrintf(osc->freq * osc->maxlens));
+#line 266 "osc.org"
+#line 342 "osc.org"
+phs = osc->lphs;
+pos = phs >> osc->nlb;
+x1 = osc->tab[pos];
+x2 = osc->tab[(pos + 1) % osc->sz];
+#line 266 "osc.org"
+#line 372 "osc.org"
+fract = (phs & osc->mask) * osc->inlb;
+#line 266 "osc.org"
+#line 397 "osc.org"
+out = (x1 + (x2 - x1) * fract) * osc->amp;
+#line 266 "osc.org"
+#line 406 "osc.org"
+phs += osc->inc;
+phs &= SK_OSC_PHASEMASK;
+osc->lphs = phs;
+#line 280 "osc.org"
+    return out;
+}
+#line 44 "osc.org"
--- /dev/null
+++ b/tangled/osc.h
@@ -1,0 +1,35 @@
+#line 27 "osc.org"
+#ifndef SK_OSC_H
+#define SK_OSC_H
+#ifndef SKFLT
+#define SKFLT float
+#endif
+#line 112 "osc.org"
+typedef struct sk_osc sk_osc;
+#line 33 "osc.org"
+#ifdef SK_OSC_PRIV
+#line 116 "osc.org"
+struct sk_osc {
+#line 123 "osc.org"
+SKFLT freq, amp;
+SKFLT *tab;
+int inc;
+size_t sz;
+uint32_t nlb;
+SKFLT inlb;
+uint32_t mask;
+SKFLT maxlens;
+int32_t lphs;
+#line 118 "osc.org"
+};
+#line 35 "osc.org"
+#endif
+#line 70 "osc.org"
+void sk_osc_init(sk_osc *osc, int sr, SKFLT *wt, int sz, SKFLT iphs);
+#line 77 "osc.org"
+SKFLT sk_osc_tick(sk_osc *osc);
+#line 86 "osc.org"
+void sk_osc_freq(sk_osc *osc, SKFLT freq);
+void sk_osc_amp(sk_osc *osc, SKFLT amp);
+#line 37 "osc.org"
+#endif
--- /dev/null
+++ b/tangled/peakeq.c
@@ -1,0 +1,79 @@
+#line 64 "peakeq.org"
+#include <math.h>
+#define SK_PEAKEQ_PRIV
+#include "peakeq.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#line 120 "peakeq.org"
+void sk_peakeq_init(sk_peakeq *eq, int sr)
+{
+#line 139 "peakeq.org"
+eq->v[0] = 0;
+eq->v[1] = 0;
+#line 154 "peakeq.org"
+eq->a = 0;
+eq->b = 0;
+#line 168 "peakeq.org"
+eq->sr = sr;
+#line 202 "peakeq.org"
+sk_peakeq_freq(eq, 1000);
+eq->pfreq = -1;
+#line 236 "peakeq.org"
+sk_peakeq_bandwidth(eq, 1000);
+eq->pbw = -1;
+#line 263 "peakeq.org"
+sk_peakeq_gain(eq, 1.0);
+#line 123 "peakeq.org"
+}
+#line 182 "peakeq.org"
+void sk_peakeq_freq(sk_peakeq *eq, SKFLT freq)
+{
+    eq->freq = freq;
+}
+#line 216 "peakeq.org"
+void sk_peakeq_bandwidth(sk_peakeq *eq, SKFLT bw)
+{
+    eq->bw = bw;
+}
+#line 250 "peakeq.org"
+void sk_peakeq_gain(sk_peakeq *eq, SKFLT gain)
+{
+    eq->gain = gain;
+}
+#line 275 "peakeq.org"
+SKFLT sk_peakeq_tick(sk_peakeq *eq, SKFLT in)
+{
+    SKFLT out;
+    SKFLT v;
+    SKFLT y;
+    out = 0;
+
+#line 304 "peakeq.org"
+if (eq->bw != eq->pbw || eq->freq != eq->pfreq) {
+    SKFLT c;
+    eq->b = -cos(2 * M_PI * eq->freq / eq->sr);
+    c = tan(M_PI * eq->bw / eq->sr);
+    eq->a = (1.0 - c) / (1.0 + c);
+
+    eq->pbw = eq->bw;
+    eq->pfreq = eq->freq;
+}
+#line 275 "peakeq.org"
+#line 322 "peakeq.org"
+v = in - eq->b*(1.0 + eq->a)*eq->v[0] - eq->a*eq->v[1];
+y = eq->a*v + eq->b*(1.0 + eq->a)*eq->v[0] + eq->v[1];
+#line 275 "peakeq.org"
+#line 334 "peakeq.org"
+out = ((in + y) + eq->gain*(in - y)) * 0.5;
+#line 275 "peakeq.org"
+#line 346 "peakeq.org"
+eq->v[1] = eq->v[0];
+eq->v[0] = v;
+#line 286 "peakeq.org"
+
+    return out;
+}
+#line 64 "peakeq.org"
--- /dev/null
+++ b/tangled/peakeq.h
@@ -1,0 +1,46 @@
+#line 80 "peakeq.org"
+#ifndef SK_PEAKEQ_H
+#define SK_PEAKEQ_H
+
+#ifndef SKFLT
+#define SKFLT float
+#endif
+
+#line 100 "peakeq.org"
+typedef struct sk_peakeq sk_peakeq;
+#line 80 "peakeq.org"
+#line 115 "peakeq.org"
+void sk_peakeq_init(sk_peakeq *eq, int sr);
+#line 177 "peakeq.org"
+void sk_peakeq_freq(sk_peakeq *eq, SKFLT freq);
+#line 211 "peakeq.org"
+void sk_peakeq_bandwidth(sk_peakeq *eq, SKFLT bw);
+#line 245 "peakeq.org"
+void sk_peakeq_gain(sk_peakeq *eq, SKFLT gain);
+#line 270 "peakeq.org"
+SKFLT sk_peakeq_tick(sk_peakeq *eq, SKFLT in);
+#line 89 "peakeq.org"
+
+#ifdef SK_PEAKEQ_PRIV
+#line 105 "peakeq.org"
+struct sk_peakeq {
+#line 134 "peakeq.org"
+SKFLT v[2];
+#line 148 "peakeq.org"
+SKFLT a;
+SKFLT b;
+#line 163 "peakeq.org"
+int sr;
+#line 193 "peakeq.org"
+SKFLT freq;
+SKFLT pfreq;
+#line 227 "peakeq.org"
+SKFLT bw;
+SKFLT pbw;
+#line 258 "peakeq.org"
+SKFLT gain;
+#line 107 "peakeq.org"
+};
+#line 92 "peakeq.org"
+#endif
+#endif
--- /dev/null
+++ b/tangled/phasewarp.c
@@ -1,0 +1,29 @@
+#line 26 "phasewarp.org"
+#include "phasewarp.h"
+#line 54 "phasewarp.org"
+SKFLT sk_phasewarp_tick(SKFLT in, SKFLT warp)
+{
+    SKFLT out;
+    SKFLT wmp;
+
+    out = 0;
+
+#line 71 "phasewarp.org"
+wmp = (warp + 1.0) * 0.5;
+#line 54 "phasewarp.org"
+#line 80 "phasewarp.org"
+if (in < wmp) {
+#line 92 "phasewarp.org"
+if (wmp != 0) out = ((SKFLT)0.5 / wmp) * in;
+#line 82 "phasewarp.org"
+} else {
+#line 101 "phasewarp.org"
+if (wmp != 1.0) {
+    out = ((SKFLT)0.5 / (SKFLT)(1.0 - wmp)) * (in - wmp) + 0.5;
+}
+#line 84 "phasewarp.org"
+}
+#line 63 "phasewarp.org"
+    return out;
+}
+#line 26 "phasewarp.org"
--- /dev/null
+++ b/tangled/phasewarp.h
@@ -1,0 +1,12 @@
+#line 32 "phasewarp.org"
+#ifndef SK_PHASEWARP_H
+#define SK_PHASEWARP_H
+
+#ifndef SKFLT
+#define SKFLT float
+#endif
+
+#line 49 "phasewarp.org"
+SKFLT sk_phasewarp_tick(SKFLT in, SKFLT warp);
+#line 40 "phasewarp.org"
+#endif
--- /dev/null
+++ b/tangled/rline.c
@@ -1,0 +1,83 @@
+#line 35 "rline.org"
+#include <math.h>
+#define SK_RLINE_PRIV
+#include "rline.h"
+#line 114 "rline.org"
+#define SK_RLINE_PHSLEN 0x1000000L
+#define SK_RLINE_PHSMSK 0xFFFFFFL
+#line 202 "rline.org"
+#define LCG(y) (y * 0x343fd + 0x269ec3)
+#line 215 "rline.org"
+#define RNG(y) ((y >> 1) & 0x7fffffff)
+#line 35 "rline.org"
+#line 231 "rline.org"
+void sk_rline_init(sk_rline *rl, int sr, int seed)
+{
+#line 103 "rline.org"
+rl->rng = seed;
+#line 90 "rline.org"
+rl->rngscale = 1.0 / ((1L<<31) - 1);
+#line 103 "rline.org"
+#line 172 "rline.org"
+rl->rng = LCG(rl->rng);
+rl->start = RNG(rl->rng) * rl->rngscale;
+rl->rng = LCG(rl->rng);
+rl->end = RNG(rl->rng) * rl->rngscale;
+#line 156 "rline.org"
+rl->scale = (rl->end - rl->start) / SK_RLINE_PHSLEN;
+#line 172 "rline.org"
+#line 103 "rline.org"
+#line 131 "rline.org"
+rl->maxlens = (SKFLT)SK_RLINE_PHSLEN / sr;
+#line 146 "rline.org"
+rl->phasepos = 0;
+#line 262 "rline.org"
+sk_rline_min(rl, 0);
+#line 289 "rline.org"
+sk_rline_max(rl, 1);
+#line 316 "rline.org"
+sk_rline_rate(rl, 1);
+#line 234 "rline.org"
+}
+#line 247 "rline.org"
+void sk_rline_min(sk_rline *rl, SKFLT min)
+{
+    rl->min = min;
+}
+#line 274 "rline.org"
+void sk_rline_max(sk_rline *rl, SKFLT max)
+{
+    rl->max= max;
+}
+#line 301 "rline.org"
+void sk_rline_rate(sk_rline *rl, SKFLT rate)
+{
+    rl->rate= rate;
+}
+#line 328 "rline.org"
+SKFLT sk_rline_tick(sk_rline *rl)
+{
+    SKFLT out;
+
+    out = 0;
+
+#line 361 "rline.org"
+out = rl->start + rl->phasepos*rl->scale;
+out = out * (rl->max - rl->min) + rl->min;
+#line 328 "rline.org"
+#line 374 "rline.org"
+rl->phasepos += floor(rl->rate * rl->maxlens);
+#line 328 "rline.org"
+#line 396 "rline.org"
+if (rl->phasepos >= SK_RLINE_PHSLEN) {
+    rl->phasepos &= SK_RLINE_PHSMSK;
+    rl->start = rl->end;
+    rl->rng = LCG(rl->rng);
+    rl->end = RNG(rl->rng) * rl->rngscale;
+    rl->scale = (rl->end - rl->start) / SK_RLINE_PHSLEN;
+}
+#line 337 "rline.org"
+
+    return out;
+}
+#line 35 "rline.org"
--- /dev/null
+++ b/tangled/rline.h
@@ -1,0 +1,49 @@
+#line 48 "rline.org"
+#ifndef SK_RLINE_H
+#define SK_RLINE_H
+
+#ifndef SKFLT
+#define SKFLT float
+#endif
+
+#line 68 "rline.org"
+typedef struct sk_rline sk_rline;
+#line 48 "rline.org"
+#line 226 "rline.org"
+void sk_rline_init(sk_rline *rl, int sr, int seed);
+#line 242 "rline.org"
+void sk_rline_min(sk_rline *rl, SKFLT min);
+#line 269 "rline.org"
+void sk_rline_max(sk_rline *rl, SKFLT max);
+#line 296 "rline.org"
+void sk_rline_rate(sk_rline *rl, SKFLT rate);
+#line 323 "rline.org"
+SKFLT sk_rline_tick(sk_rline *rl);
+#line 57 "rline.org"
+
+#ifdef SK_RLINE_PRIV
+#line 73 "rline.org"
+struct sk_rline {
+#line 85 "rline.org"
+SKFLT rngscale;
+#line 98 "rline.org"
+int rng;
+#line 126 "rline.org"
+SKFLT maxlens;
+#line 140 "rline.org"
+unsigned long phasepos;
+SKFLT scale;
+#line 166 "rline.org"
+SKFLT start;
+SKFLT end;
+#line 255 "rline.org"
+SKFLT min;
+#line 282 "rline.org"
+SKFLT max;
+#line 309 "rline.org"
+SKFLT rate;
+#line 75 "rline.org"
+};
+#line 60 "rline.org"
+#endif
+#endif
--- /dev/null
+++ b/tangled/vardelay.c
@@ -1,0 +1,118 @@
+#line 18 "vardelay.org"
+#include <math.h>
+#include <stdlib.h>
+#define SK_VARDELAY_PRIV
+#include "vardelay.h"
+#line 57 "vardelay.org"
+void sk_vardelay_init(sk_vardelay *vd, int sr,
+                      SKFLT *buf, unsigned long sz)
+{
+#line 92 "vardelay.org"
+vd->sr = sr;
+#line 112 "vardelay.org"
+if (sz < 4) {
+    vd->buf = NULL;
+    vd->buf = 0;
+} else {
+    vd->buf = buf;
+    vd->sz = sz;
+}
+#line 135 "vardelay.org"
+vd->prev = 0;
+#line 156 "vardelay.org"
+vd->writepos = 0;
+#line 185 "vardelay.org"
+sk_vardelay_delay(vd, ((SKFLT)sz / sr) * 0.5);
+#line 213 "vardelay.org"
+sk_vardelay_feedback(vd, 0);
+#line 61 "vardelay.org"
+}
+#line 169 "vardelay.org"
+void sk_vardelay_delay(sk_vardelay *vd, SKFLT delay)
+{
+    vd->delay = delay;
+}
+#line 198 "vardelay.org"
+void sk_vardelay_feedback(sk_vardelay *vd, SKFLT feedback)
+{
+    vd->feedback = feedback;
+}
+#line 225 "vardelay.org"
+SKFLT sk_vardelay_tick(sk_vardelay *vd, SKFLT in)
+{
+    SKFLT out;
+    SKFLT dels;
+    SKFLT f;
+    long i;
+    SKFLT s[4];
+    unsigned long n[4];
+    SKFLT a, b, c, d;
+
+    out = 0;
+#line 254 "vardelay.org"
+if (vd->buf == NULL || vd->sz == 0) return 0;
+#line 225 "vardelay.org"
+#line 261 "vardelay.org"
+vd->buf[vd->writepos] = in + vd->prev * vd->feedback;
+#line 225 "vardelay.org"
+#line 274 "vardelay.org"
+dels = vd->delay * vd->sr;
+i = floor(dels);
+f = i - dels;
+i = vd->writepos - i;
+#line 225 "vardelay.org"
+#line 299 "vardelay.org"
+if ((f < 0.0) || (i < 0)) {
+    /* flip fractional component */
+    f = f + 1.0;
+    /* go backwards one sample */
+    i = i - 1;
+    while (i < 0) i += vd->sz;
+} else while(i >= vd->sz) i -= vd->sz;
+#line 225 "vardelay.org"
+#line 313 "vardelay.org"
+/* x(n) */
+n[1] = i;
+
+/* x(n + 1) */
+if (i == (vd->sz - 1)) n[2] = 0;
+else n[2] = n[1] + 1;
+
+/* x(n - 1) */
+if (i == 0) n[0] = vd->sz - 1;
+else n[0] = i - 1;
+
+if (n[2] == vd->sz - 1) n[3] = 0;
+else n[3] = n[2] + 1;
+
+{
+    int j;
+    for (j = 0; j < 4; j++) s[j] = vd->buf[n[j]];
+}
+#line 225 "vardelay.org"
+#line 338 "vardelay.org"
+{
+    SKFLT tmp[2];
+
+    d = ((f * f) - 1) * 0.1666666667;
+    tmp[0] = (f + 1.0) * 0.5;
+    tmp[1] = 3.0 * d;
+    a = tmp[0] - 1.0 - d;
+    c = tmp[0] - tmp[1];
+    b = tmp[1] - f;
+}
+#line 225 "vardelay.org"
+#line 358 "vardelay.org"
+out = (a*s[0] + b*s[1] + c*s[2] + d*s[3]) * f + s[1];
+#line 225 "vardelay.org"
+#line 366 "vardelay.org"
+vd->writepos++;
+if (vd->writepos == vd->sz) vd->writepos = 0;
+#line 225 "vardelay.org"
+#line 375 "vardelay.org"
+vd->prev = out;
+#line 245 "vardelay.org"
+
+    return out;
+}
+#line 18 "vardelay.org"
--- /dev/null
+++ b/tangled/vardelay.h
@@ -1,0 +1,42 @@
+#line 30 "vardelay.org"
+#ifndef SK_VARDELAY_H
+#define SK_VARDELAY_H
+
+#ifndef SKFLT
+#define SKFLT float
+#endif
+
+#line 71 "vardelay.org"
+typedef struct sk_vardelay sk_vardelay;
+#line 30 "vardelay.org"
+#line 51 "vardelay.org"
+void sk_vardelay_init(sk_vardelay *vd, int sr,
+                      SKFLT *buf, unsigned long sz);
+#line 164 "vardelay.org"
+void sk_vardelay_delay(sk_vardelay *vd, SKFLT delay);
+#line 193 "vardelay.org"
+void sk_vardelay_feedback(sk_vardelay *vd, SKFLT feedback);
+#line 220 "vardelay.org"
+SKFLT sk_vardelay_tick(sk_vardelay *vd, SKFLT in);
+#line 39 "vardelay.org"
+#ifdef SK_VARDELAY_PRIV
+#line 76 "vardelay.org"
+struct sk_vardelay {
+#line 87 "vardelay.org"
+int sr;
+#line 106 "vardelay.org"
+SKFLT *buf;
+unsigned long sz;
+#line 130 "vardelay.org"
+SKFLT prev;
+#line 151 "vardelay.org"
+long writepos;
+#line 177 "vardelay.org"
+SKFLT delay;
+#line 206 "vardelay.org"
+SKFLT feedback;
+#line 78 "vardelay.org"
+};
+#line 41 "vardelay.org"
+#endif
+#endif
--- /dev/null
+++ b/test/Makefile
@@ -1,0 +1,46 @@
+.PHONY: clean perf
+
+all: libsptest.a run.bin #perf
+
+config.mk: config.def.mk
+	cp config.def.mk config.mk
+
+include config.mk
+
+OBJ = $(addprefix t/, $(addsuffix .o, $(TESTS)))
+PERF_OBJ = $(addprefix p/, $(PERF))
+
+LDFLAGS += -L/usr/local/lib -lsndfile -lm
+CFLAGS += -g -I../h -I /usr/local/include -I. -O3 -Wall -pedantic
+CFLAGS += -DSAMPDIR="\"../examples/\""
+
+ifdef WRITE_RAW
+CFLAGS += -DWRITE_RAW
+endif
+
+libsptest.a: md5.o test.o libtap.o
+	ld -o $@ -r md5.o libtap.o test.o
+
+t/%.o: t/%.c all_tests.h
+	$(CC) -c $(CFLAGS) -o $@ $<
+
+perf: $(PERF_OBJ)
+p/p_%: p/p_%.c
+	$(CC) $< $(CFLAGS) ../libsoundpipe.a -lsndfile -lm -o $@
+
+perftest: 
+	./perf_test $(PERF_OBJ)
+
+plot:
+	gnuplot plot.plt
+	convert -rotate 90 demo.png perftest.png
+	rm demo.png
+
+test.o: test.c
+	$(CC) -g -I../h -I /usr/local/include -c -o $@ $<
+
+run.bin: run.c test.c md5.c libsptest.a $(OBJ) all_tests.h
+	$(CC) run.c -Wall $(CFLAGS) $(LDFLAGS) -o$@ $(OBJ) ../libsoundpipe.a libsptest.a -lm -lsndfile
+
+clean:
+	rm -rf run.bin libsptest.a *.o $(OBJ) *.raw $(PERF_OBJ) *.png *.log
--- /dev/null
+++ b/test/README.md
@@ -1,0 +1,13 @@
+# Testing in Soundpipe
+
+(More to be written here.)
+
+To run the performance tests, run:
+
+    make perftest
+
+To plot:
+
+    make plot
+
+This will write a file called perftest.png
--- /dev/null
+++ b/test/all_tests.h
@@ -1,0 +1,114 @@
+TEST(t_foo, "foo", "9b1be87c6b579fde2341515f4d82c008")
+TEST(t_osc, "osc", "c6b5a877a5e4b282262e6b96cb5d37fd")
+/* TEST(t_atone, "atone", "bae03ea296123e33a29211503c30ffc1") */
+/* TEST(t_allpass, "allpass", "aef5f3f109cc70ddf6087ac602f20a9a") */
+/* TEST(t_bal, "bal", "b69e113862b22a053c74ed8334ca2546") */
+/* TEST(t_biquad, "biquad", "0a3d247fe852ceb9ab27955780f510f3") */
+TEST(t_biscale, "biscale", "ca7d61430e28ffd58d0b4370660ab34a")
+TEST(t_blsaw, "blsaw", "a554132bb59acd699fe2c4e6180dbc6d")
+TEST(t_blsquare, "blsquare", "2e2466ed808465df5de309822cab6498")
+TEST(t_bltriangle, "bltriangle", "5c5b2d1bb737eef593932bcaba5d700b")
+/* TEST(t_butbp, "butbp", "8e3d95e3fde358612ef0471162eb08b1") */
+/* TEST(t_butbr, "butbr", "e950a6d5a123a250ae29cdb43a928d23") */
+/* TEST(t_buthp, "buthp", "f437e08168a4b6f9eb57be3c466178f1") */
+/* TEST(t_butlp, "butlp", "db93b2c0c3ec074fd811809496b2bab7") */
+/* TEST(t_clip, "clip", "8560d30573c759e0c7874666b641a059") */
+/* TEST(t_comb, "comb", "dfcb2bbb1fcf157485218d6c6bde770f") */
+TEST(t_bitcrush, "bitcrush", "0c93a78b75123299f6caac428ef3339e")
+TEST(t_delay, "delay", "bb61353652e27f1bc38e2f15d17f6174")
+/* TEST(t_dist, "dist", "5dd6a64b8885193f3f483df64bafc0e5") */
+TEST(t_dmetro, "dmetro", "977818bf3207fe5bb358ec5253b20bb9")
+/* TEST(t_drip, "drip", "1d2b4ada2d286235cb7bf76678e1e964") */
+TEST(t_dtrig, "dtrig", "4e4b520cc8b58363d2453cdf4c420871")
+TEST(t_peakeq, "peakeq", "e0983dd81eba15d20fbe0e8a51a07cf2")
+/* TEST(t_dust, "dust", "83d86a1f874a327ff33e5730fd6c3f56") */
+/* TEST(t_fofilt, "fofilt", "6f38f2fa90f6f1bbd153732b771fe2c0") */
+/* TEST(t_gbuzz, "gbuzz", "e402285a35e9367b975520e8526d3b1f") */
+/* TEST(t_moogladder, "moogladder", "5c2650c0c0374e1faa3c853dae2ac431") */
+/* TEST(t_phasor, "phasor", "e0e96fbadf9736d6e7734028f6557555") */
+/* TEST(t_tone, "tone", "5571f4488385f0f221f4ad0a58665b2b") */
+TEST(t_noise, "noise", "05d1b638e85626876e2b1e3c2cd01a7c")
+/* TEST(t_pareq, "pareq", "5a9df59248a8fc15d543a81a8032019c") */
+/* TEST(t_jitter, "jitter", "7b234521c41ce6ac9fe6586590a9ed1c") */
+/* TEST(t_pluck, "pluck", "cb9f40de0f65a34aac283755cf6cc92b") */
+/* TEST(t_lpf18, "lpf18", "e9f83d8e6332bae5454c1c1a820f81ee") */
+/* TEST(t_tbvcf, "tbvcf", "bbeee0e8e747a006acab06a269e7f896") */
+/* TEST(t_port, "port", "a13637765f6fa947c28d8afdc4dd058b") */
+/* TEST(t_posc3, "posc3", "6977896a8d6157262f39f4e0fbf2b826") */
+TEST(t_prop, "prop", "422c77885af9f96dc04a4e6df68af826")
+TEST(t_rline, "rline", "9b47e0320480b4a1b74b0e1672665051")
+TEST(t_random, "random", "a3e857e8c2cccb8773fe6d4902d6e21f")
+TEST(t_reverse, "reverse", "3296a3444115849585e7cb7a25899c7a")
+TEST(t_bigverb, "bigverb", "e5fcee0007e06587d04d5d6c8bcddbc2")
+TEST(t_rpt, "rpt", "ddcf0fb72209dde0581e5d37e8513c62")
+/* TEST(t_maygate, "maygate", "7147aa5764871be6ec380ebd2d7cd8a1") */
+TEST(t_samphold, "samphold", "cafe3a8f9576b62eb57d9e849d4c8901")
+TEST(t_saturator, "saturator", "141c604b99d3db2cebf47c704197f736")
+TEST(t_scale, "scale", "ca7d61430e28ffd58d0b4370660ab34a")
+/* TEST(t_streson, "streson", "d5d1f75df0262d480722648a77db2087") */
+TEST(t_tenv, "tenv", "3ddfd9bb88d6e12b96dafc291f539da4")
+TEST(t_tenv2, "tenv2", "d4a9ab8ed8f48f4da7714848fb76721a")
+TEST(t_tseq, "tseq", "be3d56a2d11b6f2e86457596285a5374")
+TEST(t_vardelay, "vardelay", "ed020f48993872084ff9502343fa58b9")
+TEST(t_modalres, "modalres", "c7d72851a98e642e6f6881d867fdff14")
+/* TEST(t_jcrev, "jcrev", "1e7125e4563d588fc8d1b417720087ad") */
+/* TEST(t_fold, "fold", "d08344b5dc59f220227818278fe43c26") */
+/* TEST(t_gen_sinesum, "gen_sinesum", "bf0e5de04ab713052433fb31a66aba8d") */
+TEST(t_gen_sine, "gen_sine", "26564cbc0556ae9586c7480d4dec2f83")
+/* TEST(t_gen_gauss, "gen_gauss", "2f60f7c00e6682a14b149f671990d788") */
+/* TEST(t_gen_line, "gen_line", "9eb3fdbed1598e756ed3b2ce7df03889") */
+TEST(t_gen_vals, "gen_vals", "f567965c66dface0b5f5aba18948b3c0")
+/* TEST(t_gen_xline, "gen_xline", "5c6050443a98326723e1809b67b73a9f") */
+/* TEST(t_expon, "expon", "4e7c83be557f938e282c854ba04d4427") */
+TEST(t_randh, "randh", "cfd39121b73a3621e36a9bef09df1a46")
+TEST(t_trand, "trand", "f1a3ff83bffea276428d2f78a61f2e9c")
+TEST(t_adsr, "adsr", "da408e8528aec4e13f3ec648baf18387")
+TEST(t_tdiv, "tdiv", "9b1be87c6b579fde2341515f4d82c008")
+/* TEST(t_paulstretch, "paulstretch", "783135a8f7fbbffb37259a59794ce95d") */
+TEST(t_crossfade, "crossfade", "bbea7ec7d1d54f628351a8e2ba75b909")
+/* TEST(t_fof, "fof", "6fbe6de36f0a9b5591ada0e7026e1797") */
+TEST(t_fosc, "fosc", "38b9082bbd866f1246a5735c40f60f8e")
+/* TEST(t_oscmorph, "oscmorph", "d0d7f65716d846eb1fab90d4fa07f8bf") */
+/* TEST(t_pshift, "pshift", "166ddd604d7b411e6d53be271b5be973") */
+/* TEST(t_sdelay, "sdelay", "3e8e284a51bf96e7dd6fa4b6a1d34f34") */
+TEST(t_line, "line", "dec3380002a2e70c9f854f8069525633")
+/* TEST(t_tblrec, "tblrec", "9cedd52785459aed553fa3faf6f3da0c") */
+/* TEST(t_wpkorg35, "wpkorg35", "2a25ec94d510ac59b430ef858f89fb97") */
+TEST(t_tseg, "tseg", "a7bd2bda3b4db43476684c7dd8e81495")
+/* TEST(t_vocoder, "vocoder", "d988fcf1e28b165bc64e77d53df20f08") */
+/* TEST(t_fog, "fog", "ab8cf3704db8198845d1726563462156") */
+/* TEST(t_compressor, "compressor", "8b717b24d86669564aaf9ef859fbf62c") */
+/* TEST(t_hilbert, "hilbert", "7c85330d2360d6c7e02f5a41efb6ee3f") */
+TEST(t_timer, "timer", "addcd2e6c740921c0829e1db4afdf462")
+/* TEST(t_autowah, "autowah", "4e4a78480cd24e8bae68672a86d1a58d") */
+/* TEST(t_tabread, "tabread", "9b1be87c6b579fde2341515f4d82c008") */
+/* TEST(t_nsmp, "nsmp", "39212b911808a8059e90d07996342b41") */
+/* TEST(t_zitarev, "zitarev", "1ccae5b4673ab4012d946686323ec484") */
+TEST(t_thresh, "thresh", "8d72ab360c9198fb4e469b092349e26d")
+TEST(t_padsynth, "padsynth", "67e7468fc3b13b0e6a29e581efab26b2")
+/* TEST(t_phaser, "phaser", "66b4969e5eacdb27debce0751e34ef6d") */
+/* TEST(t_bar, "bar", "567a8d8b46bcd3c00307b8f714f51c78") */
+/* TEST(t_conv, "conv", "9b1be87c6b579fde2341515f4d82c008") */
+/* TEST(t_diskin, "diskin", "cb72152d73ccaa3bdce298d0587d255c") */
+/* TEST(t_metro, "metro", "f7faa518c3f50acf2b59b562f8f6b0bb") */
+/* TEST(t_mincer, "mincer", "1f3d839081fa7ef5b2850858e4789300") */
+/* TEST(t_pan2, "pan2", "1b9b502d81e337c91bfbd036db5fde4d") */
+/* TEST(t_gen_composite, "gen_composite", "e33caafd160df29d7f6cbfe4178ce1c2") */
+/* TEST(t_gen_file, "gen_file", "e9e8051f4075a559c0d93b47d74f585f") */
+TEST(t_tenvx, "tenvx", "1269a3b4e08abfc4eed548e020b4595c")
+TEST(t_tadsr, "tadsr", "9b1be87c6b579fde2341515f4d82c008")
+/* TEST(t_switch, "switch", "49d42701c018204b9029b236d5f3857a") */
+/* TEST(t_waveset, "waveset", "a6508d38f8e8a5b40b1fcd16f2c6cbe8") */
+/* TEST(t_ptrack, "ptrack", "997c0c9f1cc2760529fd3e86a3106509") */
+TEST(t_phasewarp, "phasewarp", "22aa1a49bb5e3f297e13e8e8baaf4bb1")
+TEST(t_pinknoise, "pinknoise", "2d1e37e1611287d6f3505b0bccd26eeb")
+/* TEST(t_pitchamdf, "pitchamdf", "4d4777f817d5ffb52b299d7dd9197b4a") */
+/* TEST(t_panst, "panst", "e43ae01af73f128255d2bceedbd12eb7") */
+/* TEST(t_peaklim, "peaklim", "63f1990a207cd7f31ebdcb3f6de7f8e3") */
+TEST(t_brown, "brown", "f939d983fe1fe01cb3fc0bed0bca79dc")
+/* TEST(t_spa, "spa", "311150fe437a3d06f24057b090298a90") */
+/* TEST(t_rspline, "rspline", "d3b3c672faeac7f4824c6863946a737e") */
+TEST(t_voc, "voc", "b9e530bfd444fc272498b38da70c12da")
+/* TEST(t_lpc, "lpc", "61eaf9f2f888942ee40b511cdf4fb4bc") */
+TEST(t_smoothdelay, "smoothdelay", "fc1a46df39c40e37aacc019152164717")
+/* TEST(t_talkbox, "talkbox", "67e3e081d8879ac20f51deb4de69f349") */
--- /dev/null
+++ b/test/config.def.mk
@@ -1,0 +1,151 @@
+TESTS = \
+t_adsr \
+t_bitcrush \
+t_gen_sine \
+t_biscale \
+t_blsaw \
+t_blsquare \
+t_bltriangle \
+t_brown \
+t_crossfade \
+t_delay \
+t_dmetro \
+t_dtrig \
+t_expon \
+t_foo \
+t_gen_vals \
+t_line \
+t_lpc \
+t_noise \
+t_osc \
+t_padsynth \
+t_pinknoise \
+t_prop \
+t_randh \
+t_random \
+t_reverse \
+t_rpt \
+t_saturator \
+t_samphold \
+t_scale \
+t_smoothdelay \
+t_spa \
+t_tadsr \
+t_tdiv \
+t_tenv \
+t_tenvx \
+t_tenv2 \
+t_thresh \
+t_timer \
+t_trand \
+t_tseq \
+t_tseg \
+t_voc \
+t_bigverb \
+t_fmpair \
+t_rline \
+t_vardelay \
+t_peakeq \
+t_modalres \
+t_phasewarp \
+
+PERF=\
+p_adsr \
+p_allpass \
+p_atone \
+p_autowah \
+p_bal \
+p_bar \
+p_biquad \
+p_biscale \
+p_bitcrush \
+p_blsaw \
+p_blsquare \
+p_bltriangle \
+p_butbp \
+p_butbr \
+p_buthp \
+p_butlp \
+p_clip \
+p_comb \
+p_compressor \
+p_conv \
+p_count \
+p_crossfade \
+p_dcblock \
+p_delay \
+p_diskin \
+p_dist \
+p_dmetro \
+p_drip \
+p_dust \
+p_eqfil \
+p_expon \
+p_fofilt \
+p_fof \
+p_fog \
+p_fold \
+p_fosc \
+p_hilbert \
+p_incr \
+p_jcrev \
+p_jitter \
+p_line \
+p_lpf18 \
+p_maygate \
+p_metro \
+p_mincer \
+p_mode \
+p_moogladder \
+p_osc \
+p_oscmorph \
+p_paulstretch \
+p_noise \
+p_pan2 \
+p_panst \
+p_pareq \
+p_pdhalf \
+p_peaklim \
+p_phaser \
+p_phasor \
+p_pinknoise \
+p_pitchamdf \
+p_pluck \
+p_port \
+p_posc3 \
+p_prop \
+p_pshift \
+p_ptrack \
+p_randh \
+p_randi \
+p_random \
+p_reson \
+p_reverse \
+p_revsc \
+p_rms \
+p_rpt \
+p_saturator \
+p_samphold \
+p_scale \
+p_sdelay \
+p_smoothdelay \
+p_streson \
+p_switch \
+p_tadsr \
+p_tbvcf \
+p_tdiv \
+p_tenv \
+p_tenv2 \
+p_tenvx \
+p_tgate \
+p_thresh \
+p_timer \
+p_tin \
+p_tone \
+p_trand \
+p_tseg \
+p_vdelay \
+p_voc \
+p_waveset \
+p_wpkorg35 \
+p_zitarev \
--- /dev/null
+++ b/test/config.h
@@ -1,0 +1,3 @@
+#define LEN 10
+#define SR 44100
+#define NUM 4
--- /dev/null
+++ b/test/find_unused_tests.sh
@@ -1,0 +1,9 @@
+#!/bin/sh
+
+# this program figures out which tests haven't been implemented yet.
+
+ls t/*.c > files
+cat all_tests.h | sed "s/TEST(\(.*\),.*,.*)/t\/\1.c/" >> files
+cat files | sort | uniq -u
+
+rm files
--- /dev/null
+++ b/test/libtap.c
@@ -1,0 +1,23 @@
+/*
+Copyright (c) 2013, 2014, Louis P. Santillan <lpsantil@gmail.com>
+All rights reserved.
+
+*/
+#include <stdio.h>
+#include "tap.h"
+
+void plan( unsigned int num )
+{
+   printf( "1..%d\n",
+           num );
+}
+
+unsigned int ok( unsigned int ok, const char* msg )
+{
+   static int testnum = 0;
+   printf( "%s %d - %s\n",
+           ( ok ? "ok" : "not ok" ),
+           ++testnum,
+           msg );
+   return ok;
+}
--- /dev/null
+++ b/test/md5.c
@@ -1,0 +1,392 @@
+/*
+  Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321.
+  It is derived directly from the text of the RFC and not from the
+  reference implementation.
+
+  The original and principal author of md5.c is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+  1999-05-03 lpd Original version.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#ifdef TEST
+/*
+ * Compile with -DTEST to create a self-contained executable test program.
+ * The test program should print out the same values as given in section
+ * A.5 of RFC 1321, reproduced below.
+ */
+#include <string.h>
+main()
+{
+    static const char *const test[7] = {
+	"", /*d41d8cd98f00b204e9800998ecf8427e*/
+	"945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/
+	"abc", /*900150983cd24fb0d6963f7d28e17f72*/
+	"message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/
+	"abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+				/*d174ab98d277d9f5a5611c2c9f419d9f*/
+	"12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/
+    };
+    int i;
+
+    for (i = 0; i < 7; ++i) {
+	md5_state_t state;
+	md5_byte_t digest[16];
+	int di;
+
+	md5_init(&state);
+	md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i]));
+	md5_finish(&state, digest);
+	printf("MD5 (\"%s\") = ", test[i]);
+	for (di = 0; di < 16; ++di)
+	    printf("%02x", digest[di]);
+	printf("\n");
+    }
+    return 0;
+}
+#endif /* TEST */
+
+
+/*
+ * For reference, here is the program that computed the T values.
+ */
+#if 0
+#include <math.h>
+main()
+{
+    int i;
+    for (i = 1; i <= 64; ++i) {
+	unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i)));
+	printf("#define T%d 0x%08lx\n", i, v);
+    }
+    return 0;
+}
+#endif
+/*
+ * End of T computation program.
+ */
+#define T1 0xd76aa478
+#define T2 0xe8c7b756
+#define T3 0x242070db
+#define T4 0xc1bdceee
+#define T5 0xf57c0faf
+#define T6 0x4787c62a
+#define T7 0xa8304613
+#define T8 0xfd469501
+#define T9 0x698098d8
+#define T10 0x8b44f7af
+#define T11 0xffff5bb1
+#define T12 0x895cd7be
+#define T13 0x6b901122
+#define T14 0xfd987193
+#define T15 0xa679438e
+#define T16 0x49b40821
+#define T17 0xf61e2562
+#define T18 0xc040b340
+#define T19 0x265e5a51
+#define T20 0xe9b6c7aa
+#define T21 0xd62f105d
+#define T22 0x02441453
+#define T23 0xd8a1e681
+#define T24 0xe7d3fbc8
+#define T25 0x21e1cde6
+#define T26 0xc33707d6
+#define T27 0xf4d50d87
+#define T28 0x455a14ed
+#define T29 0xa9e3e905
+#define T30 0xfcefa3f8
+#define T31 0x676f02d9
+#define T32 0x8d2a4c8a
+#define T33 0xfffa3942
+#define T34 0x8771f681
+#define T35 0x6d9d6122
+#define T36 0xfde5380c
+#define T37 0xa4beea44
+#define T38 0x4bdecfa9
+#define T39 0xf6bb4b60
+#define T40 0xbebfbc70
+#define T41 0x289b7ec6
+#define T42 0xeaa127fa
+#define T43 0xd4ef3085
+#define T44 0x04881d05
+#define T45 0xd9d4d039
+#define T46 0xe6db99e5
+#define T47 0x1fa27cf8
+#define T48 0xc4ac5665
+#define T49 0xf4292244
+#define T50 0x432aff97
+#define T51 0xab9423a7
+#define T52 0xfc93a039
+#define T53 0x655b59c3
+#define T54 0x8f0ccc92
+#define T55 0xffeff47d
+#define T56 0x85845dd1
+#define T57 0x6fa87e4f
+#define T58 0xfe2ce6e0
+#define T59 0xa3014314
+#define T60 0x4e0811a1
+#define T61 0xf7537e82
+#define T62 0xbd3af235
+#define T63 0x2ad7d2bb
+#define T64 0xeb86d391
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+    md5_word_t
+	a = pms->abcd[0], b = pms->abcd[1],
+	c = pms->abcd[2], d = pms->abcd[3];
+    md5_word_t t;
+
+#ifndef ARCH_IS_BIG_ENDIAN
+# define ARCH_IS_BIG_ENDIAN 1	/* slower, default implementation */
+#endif
+#if ARCH_IS_BIG_ENDIAN
+
+    /*
+     * On big-endian machines, we must arrange the bytes in the right
+     * order.  (This also works on machines of unknown byte order.)
+     */
+    md5_word_t X[16];
+    const md5_byte_t *xp = data;
+    int i;
+
+    for (i = 0; i < 16; ++i, xp += 4)
+	X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+
+#else  /* !ARCH_IS_BIG_ENDIAN */
+
+    /*
+     * On little-endian machines, we can process properly aligned data
+     * without copying it.
+     */
+    md5_word_t xbuf[16];
+    const md5_word_t *X;
+
+    if (!((data - (const md5_byte_t *)0) & 3)) {
+	/* data are properly aligned */
+	X = (const md5_word_t *)data;
+    } else {
+	/* not aligned */
+	memcpy(xbuf, data, 64);
+	X = xbuf;
+    }
+#endif
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+    /* Round 1. */
+    /* Let [abcd k s i] denote the operation
+       a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + F(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+    /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  7,  T1);
+    SET(d, a, b, c,  1, 12,  T2);
+    SET(c, d, a, b,  2, 17,  T3);
+    SET(b, c, d, a,  3, 22,  T4);
+    SET(a, b, c, d,  4,  7,  T5);
+    SET(d, a, b, c,  5, 12,  T6);
+    SET(c, d, a, b,  6, 17,  T7);
+    SET(b, c, d, a,  7, 22,  T8);
+    SET(a, b, c, d,  8,  7,  T9);
+    SET(d, a, b, c,  9, 12, T10);
+    SET(c, d, a, b, 10, 17, T11);
+    SET(b, c, d, a, 11, 22, T12);
+    SET(a, b, c, d, 12,  7, T13);
+    SET(d, a, b, c, 13, 12, T14);
+    SET(c, d, a, b, 14, 17, T15);
+    SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+     /* Round 2. */
+     /* Let [abcd k s i] denote the operation
+          a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + G(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  1,  5, T17);
+    SET(d, a, b, c,  6,  9, T18);
+    SET(c, d, a, b, 11, 14, T19);
+    SET(b, c, d, a,  0, 20, T20);
+    SET(a, b, c, d,  5,  5, T21);
+    SET(d, a, b, c, 10,  9, T22);
+    SET(c, d, a, b, 15, 14, T23);
+    SET(b, c, d, a,  4, 20, T24);
+    SET(a, b, c, d,  9,  5, T25);
+    SET(d, a, b, c, 14,  9, T26);
+    SET(c, d, a, b,  3, 14, T27);
+    SET(b, c, d, a,  8, 20, T28);
+    SET(a, b, c, d, 13,  5, T29);
+    SET(d, a, b, c,  2,  9, T30);
+    SET(c, d, a, b,  7, 14, T31);
+    SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+     /* Round 3. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + H(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  5,  4, T33);
+    SET(d, a, b, c,  8, 11, T34);
+    SET(c, d, a, b, 11, 16, T35);
+    SET(b, c, d, a, 14, 23, T36);
+    SET(a, b, c, d,  1,  4, T37);
+    SET(d, a, b, c,  4, 11, T38);
+    SET(c, d, a, b,  7, 16, T39);
+    SET(b, c, d, a, 10, 23, T40);
+    SET(a, b, c, d, 13,  4, T41);
+    SET(d, a, b, c,  0, 11, T42);
+    SET(c, d, a, b,  3, 16, T43);
+    SET(b, c, d, a,  6, 23, T44);
+    SET(a, b, c, d,  9,  4, T45);
+    SET(d, a, b, c, 12, 11, T46);
+    SET(c, d, a, b, 15, 16, T47);
+    SET(b, c, d, a,  2, 23, T48);
+#undef SET
+
+     /* Round 4. */
+     /* Let [abcd k s t] denote the operation
+          a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+  t = a + I(b,c,d) + X[k] + Ti;\
+  a = ROTATE_LEFT(t, s) + b
+     /* Do the following 16 operations. */
+    SET(a, b, c, d,  0,  6, T49);
+    SET(d, a, b, c,  7, 10, T50);
+    SET(c, d, a, b, 14, 15, T51);
+    SET(b, c, d, a,  5, 21, T52);
+    SET(a, b, c, d, 12,  6, T53);
+    SET(d, a, b, c,  3, 10, T54);
+    SET(c, d, a, b, 10, 15, T55);
+    SET(b, c, d, a,  1, 21, T56);
+    SET(a, b, c, d,  8,  6, T57);
+    SET(d, a, b, c, 15, 10, T58);
+    SET(c, d, a, b,  6, 15, T59);
+    SET(b, c, d, a, 13, 21, T60);
+    SET(a, b, c, d,  4,  6, T61);
+    SET(d, a, b, c, 11, 10, T62);
+    SET(c, d, a, b,  2, 15, T63);
+    SET(b, c, d, a,  9, 21, T64);
+#undef SET
+
+     /* Then perform the following additions. (That is increment each
+        of the four registers by the value it had before this block
+        was started.) */
+    pms->abcd[0] += a;
+    pms->abcd[1] += b;
+    pms->abcd[2] += c;
+    pms->abcd[3] += d;
+}
+
+void
+md5_init(md5_state_t *pms)
+{
+    pms->count[0] = pms->count[1] = 0;
+    pms->abcd[0] = 0x67452301;
+    pms->abcd[1] = 0xefcdab89;
+    pms->abcd[2] = 0x98badcfe;
+    pms->abcd[3] = 0x10325476;
+}
+
+void
+md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)
+{
+    const md5_byte_t *p = data;
+    int left = nbytes;
+    int offset = (pms->count[0] >> 3) & 63;
+    md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+    if (nbytes <= 0)
+	return;
+
+    /* Update the message length. */
+    pms->count[1] += nbytes >> 29;
+    pms->count[0] += nbits;
+    if (pms->count[0] < nbits)
+	pms->count[1]++;
+
+    /* Process an initial partial block. */
+    if (offset) {
+	int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+	memcpy(pms->buf + offset, p, copy);
+	if (offset + copy < 64)
+	    return;
+	p += copy;
+	left -= copy;
+	md5_process(pms, pms->buf);
+    }
+
+    /* Process full blocks. */
+    for (; left >= 64; p += 64, left -= 64)
+	md5_process(pms, p);
+
+    /* Process a final partial block. */
+    if (left)
+	memcpy(pms->buf, p, left);
+}
+
+void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+    static const md5_byte_t pad[64] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    md5_byte_t data[8];
+    int i;
+
+    /* Save the length before padding. */
+    for (i = 0; i < 8; ++i)
+	data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+    /* Pad to 56 bytes mod 64. */
+    md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+    /* Append the length. */
+    md5_append(pms, data, 8);
+    for (i = 0; i < 16; ++i)
+	digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
--- /dev/null
+++ b/test/md5.h
@@ -1,0 +1,93 @@
+/*
+  Copyright (C) 1999 Aladdin Enterprises.  All rights reserved.
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  L. Peter Deutsch
+  ghost@aladdin.com
+
+ */
+/*
+  Independent implementation of MD5 (RFC 1321).
+
+  This code implements the MD5 Algorithm defined in RFC 1321.
+  It is derived directly from the text of the RFC and not from the
+  reference implementation.
+
+  The original and principal author of md5.h is L. Peter Deutsch
+  <ghost@aladdin.com>.  Other authors are noted in the change history
+  that follows (in reverse chronological order):
+
+  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+	added conditionalization for C++ compilation from Martin
+	Purschke <purschke@bnl.gov>.
+  1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#  define md5_INCLUDED
+
+/*
+ * This code has some adaptations for the Ghostscript environment, but it
+ * will compile and run correctly in any environment with 8-bit chars and
+ * 32-bit ints.  Specifically, it assumes that if the following are
+ * defined, they have the same meaning as in Ghostscript: P1, P2, P3,
+ * ARCH_IS_BIG_ENDIAN.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+    md5_word_t count[2];	/* message length in bits, lsw first */
+    md5_word_t abcd[4];		/* digest buffer */
+    md5_byte_t buf[64];		/* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Initialize the algorithm. */
+#ifdef P1
+void md5_init(P1(md5_state_t *pms));
+#else
+void md5_init(md5_state_t *pms);
+#endif
+
+/* Append a string to the message. */
+#ifdef P3
+void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes));
+#else
+void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
+#endif
+
+/* Finish the message and return the digest. */
+#ifdef P2
+void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16]));
+#else
+void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+#endif
+
+#ifdef __cplusplus
+}  /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
--- /dev/null
+++ b/test/p/gen.lua
@@ -1,0 +1,48 @@
+name = arg[1]
+sptbl = {}
+
+dofile ("../../sp_dict.lua")
+
+header=[[
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+]]
+
+compute=[[
+    sp_FOO *unit[NUM];
+
+    for(u = 0; u < NUM; u++) { 
+        sp_FOO_create(&unit[u]);
+        sp_FOO_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_FOO_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_FOO_destroy(&unit[u]);
+]]
+
+
+footer=[[
+    sp_destroy(&sp);
+    return 0;
+}
+]]
+
+compute = string.gsub(compute, "FOO", name)
+
+print(header)
+print(compute)
+print(footer)
--- /dev/null
+++ b/test/p/p_adsr.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_adsr *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_adsr_create(&unit[u]);
+        sp_adsr_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_adsr_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_adsr_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_allpass.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_allpass *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_allpass_create(&unit[u]);
+        sp_allpass_init(sp, unit[u], 1.5);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_allpass_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_allpass_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_atone.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_atone *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_atone_create(&unit[u]);
+        sp_atone_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_atone_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_atone_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_autowah.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_autowah *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_autowah_create(&unit[u]);
+        sp_autowah_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_autowah_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_autowah_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_bal.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0, comp = 0;
+
+    sp_bal *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_bal_create(&unit[u]);
+        sp_bal_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_bal_compute(sp, unit[u], &in, &comp, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_bal_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_bar.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_bar *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_bar_create(&unit[u]);
+        sp_bar_init(sp, unit[u], 3, 0.0001);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_bar_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_bar_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_biquad.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_biquad *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_biquad_create(&unit[u]);
+        sp_biquad_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_biquad_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_biquad_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_biscale.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_biscale *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_biscale_create(&unit[u]);
+        sp_biscale_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_biscale_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_biscale_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_bitcrush.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_bitcrush *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_bitcrush_create(&unit[u]);
+        sp_bitcrush_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_bitcrush_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_bitcrush_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_blsaw.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_blsaw *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_blsaw_create(&unit[u]);
+        sp_blsaw_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_blsaw_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_blsaw_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_blsquare.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_blsquare *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_blsquare_create(&unit[u]);
+        sp_blsquare_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_blsquare_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_blsquare_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_bltriangle.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_bltriangle *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_bltriangle_create(&unit[u]);
+        sp_bltriangle_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_bltriangle_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_bltriangle_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_butbp.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_butbp *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_butbp_create(&unit[u]);
+        sp_butbp_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_butbp_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_butbp_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_butbr.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_butbr *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_butbr_create(&unit[u]);
+        sp_butbr_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_butbr_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_butbr_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_buthp.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_buthp *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_buthp_create(&unit[u]);
+        sp_buthp_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_buthp_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_buthp_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_butlp.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_butlp *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_butlp_create(&unit[u]);
+        sp_butlp_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_butlp_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_butlp_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_clip.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_clip *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_clip_create(&unit[u]);
+        sp_clip_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_clip_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_clip_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_comb.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_comb *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_comb_create(&unit[u]);
+        sp_comb_init(sp, unit[u], 1.1);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_comb_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_comb_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_compressor.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_compressor *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_compressor_create(&unit[u]);
+        sp_compressor_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_compressor_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_compressor_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_conv.c
@@ -1,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+    sp_ftbl *ft;
+
+    sp_conv *unit[NUM];
+
+    sp_ftbl_loadfile(sp, &ft, SAMPDIR "oneart.wav");
+
+    for(u = 0; u < NUM; u++) {
+        sp_conv_create(&unit[u]);
+        sp_conv_init(sp, unit[u], ft, 2048);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_conv_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_conv_destroy(&unit[u]);
+
+    sp_ftbl_destroy(&ft);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_count.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_count *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_count_create(&unit[u]);
+        sp_count_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_count_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_count_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_crossfade.c
@@ -1,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in1 = 0, out = 0, in2 = 0;
+
+    sp_crossfade *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_crossfade_create(&unit[u]);
+        sp_crossfade_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_crossfade_compute(sp, unit[u],
+                &in1, &in2, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_crossfade_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_dcblock.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_dcblock *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_dcblock_create(&unit[u]);
+        sp_dcblock_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_dcblock_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_dcblock_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_delay.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_delay *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_delay_create(&unit[u]);
+        sp_delay_init(sp, unit[u], 1.0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_delay_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_delay_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_diskin.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_diskin *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_diskin_create(&unit[u]);
+        sp_diskin_init(sp, unit[u], SAMPDIR "oneart.wav");
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_diskin_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_diskin_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_dist.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_dist *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_dist_create(&unit[u]);
+        sp_dist_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_dist_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_dist_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_dmetro.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_dmetro *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_dmetro_create(&unit[u]);
+        sp_dmetro_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_dmetro_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_dmetro_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_drip.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_drip *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_drip_create(&unit[u]);
+        sp_drip_init(sp, unit[u], 0.09);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_drip_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_drip_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_dtrig.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_dtrig *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_dtrig_create(&unit[u]);
+        sp_dtrig_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_dtrig_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_dtrig_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_dust.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_dust *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_dust_create(&unit[u]);
+        sp_dust_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_dust_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_dust_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_eqfil.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_eqfil *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_eqfil_create(&unit[u]);
+        sp_eqfil_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_eqfil_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_eqfil_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_expon.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_expon *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_expon_create(&unit[u]);
+        sp_expon_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_expon_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_expon_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_fof.c
@@ -1,0 +1,39 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_fof *unit[NUM];
+
+    sp_ftbl *sine;
+    sp_ftbl *win;
+
+    sp_ftbl_create(sp, &sine, 2048);
+    sp_ftbl_create(sp, &win, 1024);
+
+    for(u = 0; u < NUM; u++) {
+        sp_fof_create(&unit[u]);
+        sp_fof_init(sp, unit[u], sine, win, 100, 0);
+    }
+
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_fof_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_fof_destroy(&unit[u]);
+    sp_ftbl_destroy(&sine);
+    sp_ftbl_destroy(&win);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_fofilt.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_fofilt *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_fofilt_create(&unit[u]);
+        sp_fofilt_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_fofilt_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_fofilt_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_fog.c
@@ -1,0 +1,38 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+    sp_ftbl *wav;
+    sp_ftbl *win;
+
+    sp_fog *unit[NUM];
+
+    sp_ftbl_loadfile(sp, &wav, SAMPDIR "oneart.wav");
+    sp_ftbl_create(sp, &win, 1024);
+    sp_gen_composite(sp, win, "0.5 0.5 270 0.5");
+
+    for(u = 0; u < NUM; u++) {
+        sp_fog_create(&unit[u]);
+        sp_fog_init(sp, unit[u], win, wav, 100, 0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_fog_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_fog_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    sp_ftbl_destroy(&wav);
+    sp_ftbl_destroy(&win);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_fold.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_fold *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_fold_create(&unit[u]);
+        sp_fold_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_fold_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_fold_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_fosc.c
@@ -1,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_ftbl *ft;
+    sp_fosc *unit[NUM];
+    sp_ftbl_create(sp, &ft, 8192);
+    sp_gen_sine(sp, ft);
+
+    for(u = 0; u < NUM; u++) {
+        sp_fosc_create(&unit[u]);
+        sp_fosc_init(sp, unit[u], ft);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_fosc_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_fosc_destroy(&unit[u]);
+
+    sp_ftbl_destroy(&ft);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_gbuzz.c
@@ -1,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_gbuzz *unit[NUM];
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 8192);
+    sp_gen_sine(sp, ft);
+
+    for(u = 0; u < NUM; u++) {
+        sp_gbuzz_create(&unit[u]);
+        sp_gbuzz_init(sp, unit[u], ft, 0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_gbuzz_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_gbuzz_destroy(&unit[u]);
+
+    sp_ftbl_destroy(&ft);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_hilbert.c
@@ -1,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out1 = 0, out2 = 0;
+
+    sp_hilbert *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_hilbert_create(&unit[u]);
+        sp_hilbert_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_hilbert_compute(sp, unit[u], &in,
+                &out1, &out2);
+    }
+
+    for(u = 0; u < NUM; u++) sp_hilbert_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_in.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_in *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_in_create(&unit[u]);
+        sp_in_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_in_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_in_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_incr.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_incr *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_incr_create(&unit[u]);
+        sp_incr_init(sp, unit[u], 0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_incr_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_incr_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_jcrev.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_jcrev *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_jcrev_create(&unit[u]);
+        sp_jcrev_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_jcrev_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_jcrev_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_jitter.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_jitter *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_jitter_create(&unit[u]);
+        sp_jitter_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_jitter_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_jitter_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_line.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_line *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_line_create(&unit[u]);
+        sp_line_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_line_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_line_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_lpf18.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_lpf18 *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_lpf18_create(&unit[u]);
+        sp_lpf18_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_lpf18_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_lpf18_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_maygate.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_maygate *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_maygate_create(&unit[u]);
+        sp_maygate_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_maygate_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_maygate_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_metro.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_metro *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_metro_create(&unit[u]);
+        sp_metro_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_metro_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_metro_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_mincer.c
@@ -1,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_mincer *unit[NUM];
+    sp_ftbl *wav;
+
+    sp_ftbl_loadfile(sp, &wav, SAMPDIR "oneart.wav");
+
+    for(u = 0; u < NUM; u++) {
+        sp_mincer_create(&unit[u]);
+        sp_mincer_init(sp, unit[u], wav, 2048);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_mincer_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_mincer_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    sp_ftbl_destroy(&wav);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_mode.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_mode *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_mode_create(&unit[u]);
+        sp_mode_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_mode_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_mode_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_moogladder.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_moogladder *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_moogladder_create(&unit[u]);
+        sp_moogladder_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_moogladder_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_moogladder_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_noise.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_noise *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_noise_create(&unit[u]);
+        sp_noise_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_noise_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_noise_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_nsmp.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_nsmp *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_nsmp_create(&unit[u]);
+        sp_nsmp_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_nsmp_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_nsmp_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_osc.c
@@ -1,0 +1,35 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_osc *unit[NUM];
+    sp_ftbl *ft;
+
+    sp_ftbl_create(sp, &ft, 8192);
+    sp_gen_sine(sp, ft);
+
+    for(u = 0; u < NUM; u++) {
+        sp_osc_create(&unit[u]);
+        sp_osc_init(sp, unit[u], ft, 0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_osc_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_osc_destroy(&unit[u]);
+
+    sp_ftbl_destroy(&ft);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_oscmorph.c
@@ -1,0 +1,44 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_ftbl *ft[2];
+    sp_ftbl *ft1;
+    sp_ftbl *ft2;
+
+    sp_oscmorph *unit[NUM];
+
+    sp_ftbl_create(sp, &ft1, 4096);
+    sp_gen_sine(sp, ft1);
+    sp_ftbl_create(sp, &ft2, 4096);
+    sp_gen_sinesum(sp, ft2, "1 1 1");
+
+    ft[0] = ft1;
+    ft[1] = ft2;
+
+    for(u = 0; u < NUM; u++) {
+        sp_oscmorph_create(&unit[u]);
+        sp_oscmorph_init(sp, unit[u], ft, 2, 0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_oscmorph_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_oscmorph_destroy(&unit[u]);
+
+    sp_ftbl_destroy(&ft1);
+    sp_ftbl_destroy(&ft2);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_padsynth.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_padsynth *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_padsynth_create(&unit[u]);
+        sp_padsynth_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_padsynth_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_padsynth_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_pan2.c
@@ -1,0 +1,32 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out1 = 0, out2 = 0;
+
+    sp_pan2 *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_pan2_create(&unit[u]);
+        sp_pan2_init(sp, unit[u]);
+        unit[u]->type  = 1;
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_pan2_compute(sp, unit[u], &in,
+                &out1, &out2);
+    }
+
+    for(u = 0; u < NUM; u++) sp_pan2_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_panst.c
@@ -1,0 +1,32 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in1 = 0, out1 = 0;
+    SPFLOAT in2 = 0, out2 = 0;
+
+    sp_panst *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_panst_create(&unit[u]);
+        sp_panst_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_panst_compute(sp, unit[u],
+                &in1, &in2, &out1, &out2);
+    }
+
+    for(u = 0; u < NUM; u++) sp_panst_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_pareq.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_pareq *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_pareq_create(&unit[u]);
+        sp_pareq_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_pareq_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_pareq_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_paulstretch.c
@@ -1,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+    sp_ftbl *wav;
+
+    sp_paulstretch *unit[NUM];
+
+    sp_ftbl_loadfile(sp, &wav, SAMPDIR "oneart.wav");
+
+    for(u = 0; u < NUM; u++) {
+        sp_paulstretch_create(&unit[u]);
+        sp_paulstretch_init(sp, unit[u], wav, 1.0, 10);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_paulstretch_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_paulstretch_destroy(&unit[u]);
+
+    sp_ftbl_destroy(&wav);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_pdhalf.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_pdhalf *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_pdhalf_create(&unit[u]);
+        sp_pdhalf_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_pdhalf_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_pdhalf_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_peaklim.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_peaklim *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_peaklim_create(&unit[u]);
+        sp_peaklim_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_peaklim_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_peaklim_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_phaser.c
@@ -1,0 +1,32 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in1 = 0, out1 = 0;
+    SPFLOAT in2 = 0, out2 = 0;
+
+    sp_phaser *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_phaser_create(&unit[u]);
+        sp_phaser_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_phaser_compute(sp, unit[u],
+                &in1, &in2, &out1, &out2);
+    }
+
+    for(u = 0; u < NUM; u++) sp_phaser_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_phasor.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_phasor *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_phasor_create(&unit[u]);
+        sp_phasor_init(sp, unit[u], 0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_phasor_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_phasor_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_pinknoise.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_pinknoise *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_pinknoise_create(&unit[u]);
+        sp_pinknoise_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_pinknoise_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_pinknoise_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_pitchamdf.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, rms = 0, cps = 0;
+
+    sp_pitchamdf *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_pitchamdf_create(&unit[u]);
+        sp_pitchamdf_init(sp, unit[u], 100, 400);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_pitchamdf_compute(sp, unit[u], &in, &cps, &rms);
+    }
+
+    for(u = 0; u < NUM; u++) sp_pitchamdf_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_pluck.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_pluck *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_pluck_create(&unit[u]);
+        sp_pluck_init(sp, unit[u], 400);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_pluck_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_pluck_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_port.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_port *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_port_create(&unit[u]);
+        sp_port_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_port_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_port_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_posc3.c
@@ -1,0 +1,35 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_posc3 *unit[NUM];
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 8192);
+    sp_gen_sine(sp, ft);
+
+    for(u = 0; u < NUM; u++) {
+        sp_posc3_create(&unit[u]);
+        sp_posc3_init(sp, unit[u], ft);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_posc3_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_posc3_destroy(&unit[u]);
+
+    sp_ftbl_destroy(&ft);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_prop.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_prop *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_prop_create(&unit[u]);
+        sp_prop_init(sp, unit[u], "+");
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_prop_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_prop_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_pshift.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_pshift *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_pshift_create(&unit[u]);
+        sp_pshift_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_pshift_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_pshift_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_ptrack.c
@@ -1,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, freq = 0, amp = 0;
+
+    sp_ptrack *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_ptrack_create(&unit[u]);
+        sp_ptrack_init(sp, unit[u], 512, 20);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_ptrack_compute(sp, unit[u], &in,
+                &freq, &amp);
+    }
+
+    for(u = 0; u < NUM; u++) sp_ptrack_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_randh.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_randh *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_randh_create(&unit[u]);
+        sp_randh_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_randh_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_randh_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_randi.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_randi *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_randi_create(&unit[u]);
+        sp_randi_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_randi_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_randi_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_random.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_random *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_random_create(&unit[u]);
+        sp_random_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_random_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_random_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_reson.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_reson *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_reson_create(&unit[u]);
+        sp_reson_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_reson_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_reson_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_reverse.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_reverse *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_reverse_create(&unit[u]);
+        sp_reverse_init(sp, unit[u], 1.0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_reverse_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_reverse_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_revsc.c
@@ -1,0 +1,32 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in1 = 0, out1 = 0;
+    SPFLOAT in2 = 0, out2 = 0;
+
+    sp_revsc *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_revsc_create(&unit[u]);
+        sp_revsc_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_revsc_compute(sp, unit[u],
+                &in1, &in2, &out1, &out2);
+    }
+
+    for(u = 0; u < NUM; u++) sp_revsc_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_rms.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_rms *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_rms_create(&unit[u]);
+        sp_rms_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_rms_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_rms_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_rpt.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0, trig = 0;
+
+    sp_rpt *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_rpt_create(&unit[u]);
+        sp_rpt_init(sp, unit[u], 2.0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_rpt_compute(sp, unit[u], &trig, &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_rpt_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_samphold.c
@@ -1,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0, trig = 0;
+
+    sp_samphold *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_samphold_create(&unit[u]);
+        sp_samphold_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_samphold_compute(sp, unit[u],
+                &trig, &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_samphold_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_saturator.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_saturator *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_saturator_create(&unit[u]);
+        sp_saturator_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_saturator_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_saturator_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_scale.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_scale *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_scale_create(&unit[u]);
+        sp_scale_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_scale_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_scale_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_sdelay.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_sdelay *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_sdelay_create(&unit[u]);
+        sp_sdelay_init(sp, unit[u], 1024);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_sdelay_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_sdelay_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_slice.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_slice *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_slice_create(&unit[u]);
+        sp_slice_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_slice_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_slice_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_smoothdelay.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_smoothdelay *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_smoothdelay_create(&unit[u]);
+        sp_smoothdelay_init(sp, unit[u], 1.0, 1024);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_smoothdelay_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_smoothdelay_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_streson.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_streson *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_streson_create(&unit[u]);
+        sp_streson_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_streson_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_streson_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_switch.c
@@ -1,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT trig = 0, in1 = 0, in2 = 0, out = 0;
+
+    sp_switch *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_switch_create(&unit[u]);
+        sp_switch_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_switch_compute(sp, unit[u],
+                &trig, &in1, &in2, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_switch_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tabread.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tabread *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tabread_create(&unit[u]);
+        sp_tabread_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tabread_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tabread_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tadsr.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tadsr *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tadsr_create(&unit[u]);
+        sp_tadsr_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tadsr_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tadsr_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tblrec.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tblrec *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tblrec_create(&unit[u]);
+        sp_tblrec_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tblrec_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tblrec_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tbvcf.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tbvcf *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tbvcf_create(&unit[u]);
+        sp_tbvcf_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tbvcf_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tbvcf_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tdiv.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tdiv *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tdiv_create(&unit[u]);
+        sp_tdiv_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tdiv_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tdiv_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tenv.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tenv *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tenv_create(&unit[u]);
+        sp_tenv_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tenv_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tenv_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tenv2.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tenv2 *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tenv2_create(&unit[u]);
+        sp_tenv2_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tenv2_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tenv2_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tenvx.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tenvx *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tenvx_create(&unit[u]);
+        sp_tenvx_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tenvx_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tenvx_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tgate.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tgate *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tgate_create(&unit[u]);
+        sp_tgate_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tgate_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tgate_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_thresh.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_thresh *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_thresh_create(&unit[u]);
+        sp_thresh_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_thresh_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_thresh_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_timer.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_timer *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_timer_create(&unit[u]);
+        sp_timer_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_timer_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_timer_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tin.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tin *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tin_create(&unit[u]);
+        sp_tin_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tin_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tin_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tone.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tone *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tone_create(&unit[u]);
+        sp_tone_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tone_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tone_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_trand.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_trand *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_trand_create(&unit[u]);
+        sp_trand_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_trand_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_trand_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tseg.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tseg *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tseg_create(&unit[u]);
+        sp_tseg_init(sp, unit[u], 0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tseg_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tseg_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_tseq.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_tseq *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_tseq_create(&unit[u]);
+        sp_tseq_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_tseq_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_tseq_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_vdelay.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_vdelay *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_vdelay_create(&unit[u]);
+        sp_vdelay_init(sp, unit[u], 1.0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_vdelay_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_vdelay_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_voc.c
@@ -1,0 +1,31 @@
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT out = 0;
+
+    sp_voc *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_voc_create(&unit[u]);
+        sp_voc_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_voc_compute(sp, unit[u], &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_voc_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_vocoder.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_vocoder *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_vocoder_create(&unit[u]);
+        sp_vocoder_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_vocoder_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_vocoder_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_waveset.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_waveset *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_waveset_create(&unit[u]);
+        sp_waveset_init(sp, unit[u], 5.0);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_waveset_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_waveset_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_wpkorg35.c
@@ -1,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in = 0, out = 0;
+
+    sp_wpkorg35 *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_wpkorg35_create(&unit[u]);
+        sp_wpkorg35_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_wpkorg35_compute(sp, unit[u], &in, &out);
+    }
+
+    for(u = 0; u < NUM; u++) sp_wpkorg35_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/p/p_zitarev.c
@@ -1,0 +1,32 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "config.h"
+
+int main() {
+    sp_data *sp;
+    sp_create(&sp);
+    sp_srand(sp, 12345);
+    sp->sr = SR;
+    sp->len = sp->sr * LEN;
+    uint32_t t, u;
+    SPFLOAT in1 = 0, out1 = 0;
+    SPFLOAT in2 = 0, out2 = 0;
+
+    sp_zitarev *unit[NUM];
+
+    for(u = 0; u < NUM; u++) {
+        sp_zitarev_create(&unit[u]);
+        sp_zitarev_init(sp, unit[u]);
+    }
+
+    for(t = 0; t < sp->len; t++) {
+        for(u = 0; u < NUM; u++) sp_zitarev_compute(sp, unit[u],
+                &in1, &in2, &out1, &out2);
+    }
+
+    for(u = 0; u < NUM; u++) sp_zitarev_destroy(&unit[u]);
+
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/test/perf_test
@@ -1,0 +1,8 @@
+#/bin/sh
+> time.log
+for p in $*
+do
+    echo "testing $p"
+    printf "$p " | sed "s/^p\/p_//" >> time.log
+    /usr/bin/time -p ./$p 2>&1 | grep real | sed -E 's/[[:space:]]+/ /' | cut -d ' ' -f 2 >> time.log
+done
--- /dev/null
+++ b/test/plot.plt
@@ -1,0 +1,11 @@
+set terminal png size 900,400 font ',10'
+set bmargin 10 
+set output "demo.png"
+set nokey
+set style data histogram
+unset border
+set xtics rotate 
+set xtics axis
+
+plot 'time.log' using 2:xtic(1) with boxes
+
--- /dev/null
+++ b/test/run.c
@@ -1,0 +1,118 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+#define TEST(str, desc, md5hash) int str(sp_test *tst, sp_data *sp, const char *hash);
+#include "all_tests.h"
+#undef TEST
+
+#define SIZE(x) sizeof(x) / sizeof(*x)
+
+typedef struct {
+    sp_data *sp;
+    uint32_t size;
+} test_data;
+
+static void print_help()
+{
+    printf("Commands:\n");
+    printf("\tgen_header: print header.\n");
+    printf("\tregen_header: regenerate header\n");
+    printf("\trender NUM: render output at position NUM\n");
+    printf("\ttest NUM: test position NUM\n");
+}
+
+/* TODO: refactor */
+int main(int argc, char *argv[])
+{
+    uint32_t n;
+    sp_test_entry tests [] = {
+#define TEST(str, desc, md5hash) {str, desc, md5hash},
+#include "all_tests.h"
+#undef TEST
+    };
+
+    int err = 0;
+    unsigned int rc;
+    unsigned int errcnt;
+    sp_test *tst;
+    sp_data *sp;
+    sp_create(&sp);
+
+    uint32_t size = 44100 * 5;
+
+    errcnt = 0;
+    if(argc == 1) {
+        plan(SIZE(tests));
+        for(n = 0; n < SIZE(tests); n++) {
+            sp_test_create(&tst, size);
+            rc = ok(tests[n].func(tst, sp, tests[n].hash)  == SP_OK, tests[n].desc);
+#ifdef WRITE_RAW
+            if(n != 0) sp_test_write_raw(tst, n);
+#endif
+            if(n != 0 && !rc) {
+                errcnt++;
+            }
+            sp_test_destroy(&tst);
+        }
+        if(errcnt > 0) {
+            fprintf(stderr, "Testing resulted in %d error(s).\n", errcnt);
+        }
+    } else {
+        if (!strcmp(argv[1], "gen_header")) {
+            for(n = 0; n < SIZE(tests); n++) {
+                printf("TEST(t_%s, \"%s\", \"%s\")\n",
+                        tests[n].desc, tests[n].desc, tests[n].hash);
+            }
+        } else if (!strcmp(argv[1], "test")) {
+            if(argc < 3) {
+                fprintf(stderr, "Not enough options for test!\n");
+                err = 1;
+            } else {
+                unsigned int pos = atoi(argv[2]) - 1;
+                if(pos > SIZE(tests)) {
+                    fprintf(stderr, "Test number %d exceeds size\n", pos);
+                } else {
+                    plan(SIZE(tests));
+                    sp_test_create(&tst, size);
+                    ok(tests[pos].func(tst, sp, tests[pos].hash)  == SP_OK, tests[pos].desc);
+                    sp_test_destroy(&tst);
+                }
+            }
+        } else if (!strcmp(argv[1], "regen_header")) {
+            for(n = 0; n < SIZE(tests); n++) {
+                sp_test_create(&tst, size);
+                tst->mode = HEADER;
+                tst->cur_entry = &tests[n];
+                tests[n].func(tst, sp, tests[n].hash);
+                sp_test_destroy(&tst);
+            }
+        } else if (!strcmp(argv[1], "render")) {
+            if(argc < 3) {
+                fprintf(stderr, "Not enough options for render!\n");
+                err = 1;
+            } else {
+                unsigned int pos = atoi(argv[2]) - 1;
+                if(pos > SIZE(tests)) {
+                    fprintf(stderr, "Test number %d exceeds size\n", pos);
+                } else {
+                    sp_test_create(&tst, size);
+                    tests[pos].func(tst, sp, tests[pos].hash);
+                    sp_test_write_raw(tst, pos + 1);
+                    sp_test_destroy(&tst);
+                }
+            }
+        } else if (!strcmp(argv[1], "help")) {
+            print_help();
+        } else {
+            fprintf(stderr, "Invalid command %s\n", argv[1]);
+            err = 1;
+        }
+    }
+    sp_destroy(&sp);
+    return err;
+}
--- /dev/null
+++ b/test/t/t_adsr.c
@@ -1,0 +1,55 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_adsr *adsr;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_adsr(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 12345);
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    sp_adsr_create(&ud.adsr);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 8192);
+    SPFLOAT osc = 0, adsr = 0, gate = 0;
+
+
+    sp_adsr_init(sp, ud.adsr);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.5;
+
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < tst->size * 0.5) {
+            gate = 1;
+        } else {
+            gate = 0;
+        }
+        sp_adsr_compute(sp, ud.adsr, &gate, &adsr);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, adsr * osc);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    sp_adsr_destroy(&ud.adsr);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_OK;
+
+}
--- /dev/null
+++ b/test/t/t_allpass.c
@@ -1,0 +1,49 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_allpass(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    sp_allpass *ap_d;
+    sp_tenv *env_d;
+    sp_noise *nz_d;
+
+    SPFLOAT tick = 0, env = 0, noise = 0, allpass = 0;
+
+    sp_allpass_create(&ap_d);
+    sp_tenv_create(&env_d);
+    sp_noise_create(&nz_d);
+
+    sp_allpass_init(sp, ap_d, 0.1);
+    sp_tenv_init(sp, env_d);
+    env_d->atk = 0.001;
+    env_d->hold = 0.00;
+    env_d->rel =  0.1;
+
+    sp_noise_init(sp, nz_d);
+
+    for(n = 0; n < tst->size; n++) {
+
+        tick = 0, env = 0, noise = 0, allpass = 0;
+        tick = (n == 0) ? 1 : 0;
+        sp_tenv_compute(sp, env_d, &tick, &env);
+        sp_noise_compute(sp, nz_d, NULL, &noise);
+        noise *= env * 0.5;
+        sp_allpass_compute(sp, ap_d, &noise, &allpass);
+
+        sp_test_add_sample(tst, allpass);
+    }
+
+    fail = sp_test_verify(tst,hash);
+
+    sp_noise_destroy(&nz_d);
+    sp_tenv_destroy(&env_d);
+    sp_allpass_destroy(&ap_d);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_atone.c
@@ -1,0 +1,36 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_atone(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT noise = 0, atone = 0;
+
+    sp_atone *atone_d;
+    sp_noise *noise_d;
+
+    sp_atone_create(&atone_d);
+    sp_noise_create(&noise_d);
+
+    sp_atone_init(sp, atone_d);
+    sp_noise_init(sp, noise_d);
+
+    for(n = 0; n < tst->size; n++) {
+        noise = 0, atone = 0;
+        sp_noise_compute(sp, noise_d, NULL, &noise);
+        sp_atone_compute(sp, atone_d, &noise, &atone);
+        sp_test_add_sample(tst, atone);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_atone_destroy(&atone_d);
+    sp_noise_destroy(&noise_d);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_autowah.c
@@ -1,0 +1,41 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_autowah *autowah;
+    sp_spa *disk;
+} UserData;
+
+int t_autowah(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT disk = 0, autowah = 0;
+
+    UserData ud;
+
+    sp_autowah_create(&ud.autowah);
+    sp_spa_create(&ud.disk);
+
+    sp_spa_init(sp, ud.disk, SAMPDIR "oneart.spa");
+    sp_autowah_init(sp, ud.autowah);
+    *ud.autowah->wah = 1.0;
+
+    for(n = 0; n < tst->size; n++) {
+        disk = 0;
+        autowah = 0;
+        sp_spa_compute(sp, ud.disk, NULL, &disk);
+        sp_autowah_compute(sp, ud.autowah, &disk, &autowah);
+        sp_test_add_sample(tst, autowah);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_autowah_destroy(&ud.autowah);
+    sp_spa_destroy(&ud.disk);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_bal.c
@@ -1,0 +1,68 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_bal(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n, i;
+    int fail = 0;
+    SPFLOAT out = 0, osc = 0, filt = 0, bal = 0, env = 0, tick;
+
+    sp_osc *osc_d[3];
+    sp_ftbl *ft_d;
+    sp_moogladder *filt_d;
+    sp_bal *bal_d;
+    sp_tenv *env_d;
+
+    sp_ftbl_create(sp, &ft_d, 4096);
+    for(i = 0; i < 3; i++) {
+        sp_osc_create(&osc_d[i]);
+        osc_d[i]->amp = 0.5;
+    }
+    sp_bal_create(&bal_d);
+    sp_moogladder_create(&filt_d);
+    filt_d->res = 0.8;
+    sp_tenv_create(&env_d);
+
+    sp_gen_line(sp, ft_d, "0 1 4096 -1");
+    sp_osc_init(sp, osc_d[0], ft_d, 0);
+    osc_d[0]->freq = sp_midi2cps(41 - 0.05);
+    sp_osc_init(sp, osc_d[1], ft_d, 0);
+    osc_d[1]->freq = sp_midi2cps(41 - 12);
+    sp_osc_init(sp, osc_d[2], ft_d, 0);
+    osc_d[2]->freq = sp_midi2cps(41 + 0.05);
+    sp->len = 44100 * 5;
+    sp_bal_init(sp, bal_d);
+    sp_moogladder_init(sp, filt_d);
+    sp_tenv_init(sp, env_d);
+    env_d->atk = 2.25;
+    env_d->hold = 0.5;
+    env_d->rel =  2.25;
+
+
+    for(n = 0; n < tst->size; n++) {
+        out = 0, osc = 0, filt = 0, bal = 0, env = 0;
+        for(i = 0; i < 3; i++) {
+           sp_osc_compute(sp, osc_d[i], NULL, &osc);
+           out += osc * 0.5;
+        }
+        tick = (sp->pos == 0) ? 1.0 : 0.0;
+        sp_tenv_compute(sp, env_d, &tick, &env);
+        filt_d->freq = 300 + 3000 * env;
+        sp_moogladder_compute(sp, filt_d, &out, &filt);
+        sp_bal_compute(sp, bal_d, &filt, &osc, &bal);
+        sp_test_add_sample(tst, bal * env);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft_d);
+    for(i = 0; i < 3; i++) sp_osc_destroy(&osc_d[i]);
+    sp_bal_destroy(&bal_d);
+    sp_moogladder_destroy(&filt_d);
+    sp_tenv_destroy(&env_d);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_bar.c
@@ -1,0 +1,43 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_bar *bar;
+    sp_metro *met;
+} UserData;
+
+int t_bar(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT bar = 0, met = 0;
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_bar_create(&ud.bar);
+    sp_metro_create(&ud.met);
+
+    sp_bar_init(sp, ud.bar, 3, 0.0001);
+    ud.bar->T30 = 1;
+
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 1;
+
+    for(n = 0; n < tst->size; n++) {
+        bar = 0;
+        met = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_bar_compute(sp, ud.bar, &met, &bar);
+        sp_test_add_sample(tst, bar);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_bar_destroy(&ud.bar);
+    sp_metro_destroy(&ud.met);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_bigverb.c
@@ -1,0 +1,49 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_bigverb *rev;
+    int counter;
+} UserData;
+
+int t_bigverb(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT in = 0;
+    SPFLOAT foo = 0;
+    sp_srand(sp, 123456);
+    UserData ud;
+    ud.counter = 0;
+    sp_noise_create(&ud.ns);
+    sp_bigverb_create(&ud.rev);
+    sp_noise_init(sp, ud.ns);
+    sp_bigverb_init(sp, ud.rev);
+
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        foo = 0;
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+
+        if(ud.counter < 2000) {
+            ud.counter = (ud.counter + 1) % 5000;
+        }else{
+            in = 0;
+        }
+        sp_bigverb_compute(sp, ud.rev, &in, &in, &sp->out[0], &foo);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_bigverb_destroy(&ud.rev);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_biquad.c
@@ -1,0 +1,42 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct udata {
+    sp_noise *ns;
+    sp_biquad *tn;
+} UserData;
+
+int t_biquad(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT in = 0;
+    SPFLOAT out = 0;
+
+    UserData ud;
+
+    sp_noise_create(&ud.ns);
+    sp_biquad_create(&ud.tn);
+
+    sp_noise_init(sp, ud.ns);
+    sp_biquad_init(sp, ud.tn);
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        out = 0;
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_biquad_compute(sp, ud.tn, &in, &out);
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_biquad_destroy(&ud.tn);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_biscale.c
@@ -1,0 +1,52 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_biscale *biscale;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_biscale(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT val = 1;
+    SPFLOAT osc = 0, biscale = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_biscale_create(&ud.biscale);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_biscale_init(sp, ud.biscale);
+    ud.biscale->min = 0;
+    ud.biscale->max = 880;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.1;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, biscale = 0;
+        /* constant set to 1, when biscaled, it becomes 440 */
+        val = 1;
+        sp_biscale_compute(sp, ud.biscale, &val, &biscale);
+        ud.osc->freq = biscale;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_biscale_destroy(&ud.biscale);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_bitcrush.c
@@ -1,0 +1,41 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_bitcrush *bitcrush;
+    sp_noise *nz;
+} UserData;
+
+int t_bitcrush(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT noise = 0, bitcrush = 0;
+    UserData ud;
+
+    sp_srand(sp, 0);
+    sp_bitcrush_create(&ud.bitcrush);
+    sp_noise_create(&ud.nz);
+
+    sp_noise_init(sp, ud.nz);
+    sp_bitcrush_init(sp, ud.bitcrush);
+    ud.bitcrush->bitdepth = 8;
+    ud.bitcrush->srate = 10000;
+
+    for(n = 0; n < tst->size; n++) {
+        noise = 0, bitcrush = 0;
+        sp_noise_compute(sp, ud.nz, NULL, &noise);
+        sp_bitcrush_compute(sp, ud.bitcrush, &noise, &bitcrush);
+        sp_test_add_sample(tst, bitcrush);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_bitcrush_destroy(&ud.bitcrush);
+    sp_noise_destroy(&ud.nz);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_blsaw.c
@@ -1,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_blsaw(sp_test *tst, sp_data *sp, const char *hash) {
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT blsaw;
+    sp_blsaw *blsaw_d;
+
+    sp_blsaw_create(&blsaw_d);
+
+    sp_blsaw_init(sp, blsaw_d);
+    *blsaw_d->freq = 500;
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        blsaw = 0;
+        sp_blsaw_compute(sp, blsaw_d, NULL, &blsaw);
+        sp_out(sp, 0, blsaw);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_blsaw_destroy(&blsaw_d);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_blsquare.c
@@ -1,0 +1,35 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_blsquare(sp_test *tst, sp_data *sp, const char *hash) {
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT blsquare;
+    sp_blsquare *blsquare_d;
+
+    sp_blsquare_create(&blsquare_d);
+
+    sp_blsquare_init(sp, blsquare_d);
+    *blsquare_d->freq = 500;
+    *blsquare_d->width = 0.4;
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        blsquare = 0;
+        sp_blsquare_compute(sp, blsquare_d, NULL, &blsquare);
+        sp_out(sp, 0, blsquare);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_blsquare_destroy(&blsquare_d);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_bltriangle.c
@@ -1,0 +1,34 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_bltriangle(sp_test *tst, sp_data *sp, const char *hash) {
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT bltriangle;
+    sp_bltriangle *bltriangle_d;
+
+    sp_bltriangle_create(&bltriangle_d);
+
+    sp_bltriangle_init(sp, bltriangle_d);
+    *bltriangle_d->freq = 500;
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        bltriangle = 0;
+        sp_bltriangle_compute(sp, bltriangle_d, NULL, &bltriangle);
+        sp_out(sp, 0, bltriangle);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_bltriangle_destroy(&bltriangle_d);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_brown.c
@@ -1,0 +1,33 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_brown *brown;
+} UserData;
+
+int t_brown(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT brown = 0;
+
+    UserData ud;
+    sp_brown_create(&ud.brown);
+
+    sp_srand(sp, 0);
+    sp_brown_init(sp, ud.brown);
+
+    for(n = 0; n < tst->size; n++) {
+        sp_brown_compute(sp, ud.brown, NULL, &brown);
+        sp_test_add_sample(tst, brown);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_brown_destroy(&ud.brown);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_butbp.c
@@ -1,0 +1,45 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_butbp *butbp;
+    int counter;
+} UserData;
+
+int t_butbp(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT in = 0;
+    SPFLOAT out = 0;
+    UserData ud;
+    ud.counter = 0;
+    sp_noise_create(&ud.ns);
+    sp_butbp_create(&ud.butbp);
+    sp_noise_init(sp, ud.ns);
+    sp_butbp_init(sp, ud.butbp);
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        out = 0;
+        if(ud.counter == 0) {
+            ud.butbp->freq= 500 + sp_rand(sp) % 4000;
+        }
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_butbp_compute(sp, ud.butbp, &in, &out);
+        ud.counter = (ud.counter + 1) % 5000;
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_butbp_destroy(&ud.butbp);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_butbr.c
@@ -1,0 +1,39 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_butbr *butbr;
+    sp_noise *ns;
+} UserData;
+
+int t_butbr(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT noise = 0, butbr = 0;
+    UserData ud;
+
+    sp_butbr_create(&ud.butbr);
+    sp_noise_create(&ud.ns);
+
+    sp_butbr_init(sp, ud.butbr);
+    sp_noise_init(sp, ud.ns);
+
+    for(n = 0; n < tst->size; n++) {
+        noise = 0, butbr = 0;
+        sp_noise_compute(sp, ud.ns, NULL, &noise);
+        sp_butbr_compute(sp, ud.butbr, &noise, &butbr);
+        sp_test_add_sample(tst, butbr);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_butbr_destroy(&ud.butbr);
+    sp_noise_destroy(&ud.ns);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_buthp.c
@@ -1,0 +1,41 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_buthp *buthp;
+} UserData;
+
+int t_buthp(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT in = 0;
+    SPFLOAT out = 0;
+
+    UserData ud;
+    sp_noise_create(&ud.ns);
+    sp_buthp_create(&ud.buthp);
+    sp_noise_init(sp, ud.ns);
+    sp_buthp_init(sp, ud.buthp);
+    ud.buthp->freq = 5000;
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        out = 0;
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_buthp_compute(sp, ud.buthp, &in, &out);
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_buthp_destroy(&ud.buthp);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_butlp.c
@@ -1,0 +1,47 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_butlp *butlp;
+    int counter;
+} UserData;
+
+int t_butlp(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+
+    SPFLOAT in = 0;
+    SPFLOAT out = 0;
+
+    UserData ud;
+    ud.counter = 0;
+    sp_noise_create(&ud.ns);
+    sp_butlp_create(&ud.butlp);
+    sp_noise_init(sp, ud.ns);
+    sp_butlp_init(sp, ud.butlp);
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        out = 0;
+        if(ud.counter == 0) {
+            ud.butlp->freq= 500 + sp_rand(sp) % 4000;
+        }
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_butlp_compute(sp, ud.butlp, &in, &out);
+        ud.counter = (ud.counter + 1) % 5000;
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_butlp_destroy(&ud.butlp);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_clamp.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_clamp(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_clip.c
@@ -1,0 +1,50 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+   sp_ftbl *ft;
+   sp_osc *osc;
+   sp_clip *clp;
+   sp_moogladder *filt;
+} UserData;
+
+int t_clip(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out, osc, filt;
+
+    UserData ud;
+    sp_clip_create(&ud.clp);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 4096);
+    sp_moogladder_create(&ud.filt);
+
+    sp_gen_line(sp, ud.ft, "0 1 4096 -1");
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->freq = sp_midi2cps(48);
+    sp_clip_init(sp, ud.clp);
+    sp_moogladder_init(sp, ud.filt);
+    ud.filt->freq = 1000;
+    ud.filt->res = 0.8;
+
+    for(n = 0; n < tst->size; n++) {
+        out = 0 , osc = 0 , filt = 0;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_moogladder_compute(sp, ud.filt, &osc, &filt);
+        sp_clip_compute(sp, ud.clp, &filt, &out);
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_osc_destroy(&ud.osc);
+    sp_clip_destroy(&ud.clp);
+    sp_ftbl_destroy(&ud.ft);
+    sp_moogladder_destroy(&ud.filt);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_clock.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_clock(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_comb.c
@@ -1,0 +1,52 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_comb *comb;
+    sp_tenv *env;
+    sp_noise *nz;
+} UserData;
+
+int t_comb(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT tick = 0, env = 0, noise = 0, comb = 0;
+
+    UserData ud;
+
+    sp_comb_create(&ud.comb);
+    sp_tenv_create(&ud.env);
+    sp_noise_create(&ud.nz);
+
+    sp_comb_init(sp, ud.comb, 0.01);
+    sp_tenv_init(sp, ud.env);
+    ud.env->atk = 0.001;
+    ud.env->hold = 0.00;
+    ud.env->rel =  0.1;
+
+    sp_noise_init(sp, ud.nz);
+
+    for(n = 0; n < tst->size; n++) {
+        tick = 0, env = 0, noise = 0, comb = 0;
+
+        tick = (sp->pos == 0) ? 1 : 0;
+        sp_tenv_compute(sp, ud.env, &tick, &env);
+        sp_noise_compute(sp, ud.nz, NULL, &noise);
+        noise *= env * 0.5;
+        sp_comb_compute(sp, ud.comb, &noise, &comb);
+        sp_test_add_sample(tst, comb);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.nz);
+    sp_tenv_destroy(&ud.env);
+    sp_comb_destroy(&ud.comb);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_compressor.c
@@ -1,0 +1,45 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_compressor *compressor;
+    sp_diskin *diskin;
+} UserData;
+
+int t_compressor(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT diskin = 0, compressor = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_compressor_create(&ud.compressor);
+    sp_diskin_create(&ud.diskin);
+
+    sp_compressor_init(sp, ud.compressor);
+    *ud.compressor->ratio = 4;
+    *ud.compressor->thresh = -30;
+    *ud.compressor->atk = 0.2;
+    *ud.compressor->rel = 0.2;
+
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+
+    for(n = 0; n < tst->size; n++) {
+        diskin = 0; compressor = 0;
+        sp_diskin_compute(sp, ud.diskin, NULL, &diskin);
+        sp_compressor_compute(sp, ud.compressor, &diskin, &compressor);
+        sp_test_add_sample(tst, compressor);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_compressor_destroy(&ud.compressor);
+    sp_diskin_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_conv.c
@@ -1,0 +1,43 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_diskin *diskin;
+    sp_conv *conv;
+    sp_ftbl *ft;
+} UserData;
+
+int t_conv(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT conv = 0, diskin = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_diskin_create(&ud.diskin);
+    sp_conv_create(&ud.conv);
+    sp_ftbl_loadfile(sp, &ud.ft, SAMPDIR "imp.wav");
+
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+    sp_conv_init(sp, ud.conv, ud.ft, 8192);
+
+    for(n = 0; n < tst->size; n++) {
+        conv = 0; diskin = 0;
+        sp_diskin_compute(sp, ud.diskin, NULL, &diskin);
+        sp_conv_compute(sp, ud.conv, &diskin, &conv);
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_conv_destroy(&ud.conv);
+    sp_ftbl_destroy(&ud.ft);
+    sp_diskin_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_count.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_count(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_crossfade.c
@@ -1,0 +1,59 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_crossfade *crossfade;
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_osc *lfo;
+    sp_noise *ns;
+} UserData;
+
+int t_crossfade(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, crossfade = 0, ns = 0, lfo = 0;
+
+    UserData ud;
+    sp_srand(sp, 12345);
+    sp_crossfade_create(&ud.crossfade);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_osc_create(&ud.lfo);
+    sp_noise_create(&ud.ns);
+
+    sp_crossfade_init(sp, ud.crossfade);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_osc_init(sp, ud.lfo, ud.ft, 0);
+    ud.lfo->amp = 1;
+    ud.lfo->freq = 1;
+    sp_noise_init(sp, ud.ns);
+    ud.ns->amp = 0.1;
+
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, crossfade = 0, ns = 0, lfo = 0;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        sp_noise_compute(sp, ud.ns, NULL, &ns);
+        ud.crossfade->pos = (lfo + 1) * 0.5;
+        sp_crossfade_compute(sp, ud.crossfade, &osc, &ns, &crossfade);
+        sp_test_add_sample(tst, crossfade);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_crossfade_destroy(&ud.crossfade);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_osc_destroy(&ud.lfo);
+    sp_noise_destroy(&ud.ns);
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_dcblock.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_dcblock(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_delay.c
@@ -1,0 +1,64 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_delay *delay;
+    sp_osc *osc;
+    sp_metro *met;
+    sp_tenv *tenv;
+    sp_ftbl *ft;
+} UserData;
+
+int t_delay(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, delay = 0, met = 0, tenv = 0;
+    UserData ud;
+
+    sp_delay_create(&ud.delay);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_metro_create(&ud.met);
+    sp_tenv_create(&ud.tenv);
+
+    sp_delay_init(sp, ud.delay, 0.75 * 0.5);
+    ud.delay->feedback = 0.5;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.5;
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 1;
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.005;
+    ud.tenv->hold = 0.1;
+    ud.tenv->rel =  0.1;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, delay = 0, met = 0, tenv = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_tenv_compute(sp, ud.tenv, &met, &tenv);
+        if(met) {
+            ud.osc->freq = 100 + sp_rand(sp) % 500;
+        }
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        osc *= tenv;
+        sp_delay_compute(sp, ud.delay, &osc, &delay);
+
+        sp_test_add_sample(tst, osc + delay);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_metro_destroy(&ud.met);
+    sp_delay_destroy(&ud.delay);
+    sp_osc_destroy(&ud.osc);
+    sp_ftbl_destroy(&ud.ft);
+    sp_tenv_destroy(&ud.tenv);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_diode.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_diode(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_diskin.c
@@ -1,0 +1,36 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_diskin *diskin;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_diskin(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT diskin = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_diskin_create(&ud.diskin);
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+
+    for(n = 0; n < tst->size; n++) {
+        diskin = 0;
+        sp_diskin_compute(sp, ud.diskin, NULL, &diskin);
+        sp_test_add_sample(tst, diskin);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_diskin_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_dist.c
@@ -1,0 +1,54 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_fosc *osc;
+    sp_ftbl *ft;
+    sp_dist *ds;
+    sp_osc *lfo;
+} UserData;
+
+int t_dist(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, lfo = 0, out = 0;
+    UserData ud;
+
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_fosc_create(&ud.osc);
+    sp_dist_create(&ud.ds);
+    sp_osc_create(&ud.lfo);
+
+    sp_gen_sine(sp, ud.ft);
+    sp_fosc_init(sp, ud.osc, ud.ft);
+    ud.osc->freq = 60;
+    sp_dist_init(sp, ud.ds);
+    ud.ds->pregain = 10;
+    sp_osc_init(sp, ud.lfo, ud.ft, 0);
+    ud.lfo->freq = 0.5;
+
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, lfo = 0, out = 0;
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        lfo = 7 * (0.5 * (lfo + 1));
+        ud.osc->indx = lfo;
+        sp_fosc_compute(sp, ud.osc, NULL, &osc);
+        sp_dist_compute(sp, ud.ds, &osc, &out);
+
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_fosc_destroy(&ud.osc);
+    sp_dist_destroy(&ud.ds);
+    sp_osc_destroy(&ud.lfo);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_dmetro.c
@@ -1,0 +1,60 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_dmetro *dmetro;
+    sp_osc *osc;
+    sp_osc *lfo;
+    sp_ftbl *ft;
+    sp_tenv *tenv;
+} UserData;
+
+int t_dmetro(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    SPFLOAT osc = 0, dmetro = 0, tenv = 0, lfo = 0;
+
+    sp_dmetro_create(&ud.dmetro);
+    sp_osc_create(&ud.osc);
+    sp_osc_create(&ud.lfo);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_tenv_create(&ud.tenv);
+
+    sp_dmetro_init(sp, ud.dmetro);
+    ud.dmetro->time = 0.05;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_osc_init(sp, ud.lfo, ud.ft, 0);
+    ud.lfo->freq = 0.3;
+    ud.lfo->amp = 0.5;
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.001;
+    ud.tenv->hold = 0.03;
+    ud.tenv->rel =  0.001;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, dmetro = 0, tenv = 0, lfo = 0;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        lfo += 0.5;
+        ud.dmetro->time = 0.05 + 0.3 * lfo;
+        sp_dmetro_compute(sp, ud.dmetro, NULL, &dmetro);
+        sp_tenv_compute(sp, ud.tenv, &dmetro, &tenv);
+        sp_test_add_sample(tst, tenv * osc);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_dmetro_destroy(&ud.dmetro);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_osc_destroy(&ud.lfo);
+    sp_tenv_destroy(&ud.tenv);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_drip.c
@@ -1,0 +1,44 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_drip *drip;
+    sp_dust *trig;
+    sp_revsc *rev;
+} UserData;
+
+int t_drip(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT trig, rev1, rev2, drip;
+    UserData ud;
+
+    sp_revsc_create(&ud.rev);
+    sp_drip_create(&ud.drip);
+    sp_dust_create(&ud.trig);
+
+    sp_dust_init(sp, ud.trig);
+    sp_drip_init(sp, ud.drip, 0.09);
+    ud.drip->amp = 0.3;
+    sp_revsc_init(sp, ud.rev);
+    ud.rev->feedback = 0.9;
+
+    for(n = 0; n < tst->size; n++) {
+        sp_dust_compute(sp, ud.trig, NULL, &trig);
+        sp_drip_compute(sp, ud.drip, &trig, &drip);
+        sp_revsc_compute(sp, ud.rev, &drip, &drip, &rev1, &rev2);
+        sp_test_add_sample(tst, drip + rev1 * 0.05);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_drip_destroy(&ud.drip);
+    sp_dust_destroy(&ud.trig);
+    sp_revsc_destroy(&ud.rev);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_dtrig.c
@@ -1,0 +1,70 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft, *delta;
+    sp_tenv *tenv;
+    sp_dtrig *dt;
+} UserData;
+
+int t_dtrig(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+
+    SPFLOAT env = 0;
+    SPFLOAT osc = 0;
+    SPFLOAT trig;
+    SPFLOAT dtrig = 0;
+
+    sp_dtrig_create(&ud.dt);
+    sp_tenv_create(&ud.tenv);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_ftbl_create(sp, &ud.delta, 4);
+    sp_osc_create(&ud.osc);
+
+    ud.delta->tbl[0] = 1.0;
+    ud.delta->tbl[1] = 1.0;
+    ud.delta->tbl[2] = 0.5;
+    ud.delta->tbl[3] = 0.5;
+    sp_dtrig_init(sp, ud.dt, ud.delta);
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.03;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel =  0.3;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->freq = 1000;
+    ud.osc->amp = 0.5;
+
+    for(n = 0; n < tst->size; n++) {
+        env = 0;
+        osc = 0;
+        trig = 0;
+        dtrig = 0;
+        if(sp->pos == 0){
+            trig = 1.0;
+        }else{
+            trig = 0.0;
+        }
+        sp_dtrig_compute(sp, ud.dt, &trig, &dtrig);
+        sp_tenv_compute(sp, ud.tenv, &dtrig, &env);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, osc * env);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_dtrig_destroy(&ud.dt);
+    sp_tenv_destroy(&ud.tenv);
+    sp_ftbl_destroy(&ud.ft);
+    sp_ftbl_destroy(&ud.delta);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_dust.c
@@ -1,0 +1,34 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_dust *dst;
+} UserData;
+
+int t_dust(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+    UserData ud;
+
+    sp_dust_create(&ud.dst);
+    sp_dust_init(sp, ud.dst);
+    sp->len = 44100 * 5;
+    ud.dst->bipolar = 1.0;
+
+    for(n = 0; n < tst->size; n++) {
+        out = 0;
+        sp_dust_compute(sp, ud.dst, NULL, &out);
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_dust_destroy(&ud.dst);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_expon.c
@@ -1,0 +1,53 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_expon *line;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_expon(sp_test *tst, sp_data *sp, const char *hash)
+{
+
+    sp_srand(sp, 1234567);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, line = 0;
+    SPFLOAT tick = 0;
+    UserData ud;
+
+    sp_expon_create(&ud.line);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_expon_init(sp, ud.line);
+    ud.line->a = 100;
+    ud.line->dur = 3;
+    ud.line->b = 400;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        if(n == 0) tick = 1; else tick = 0;
+        sp_expon_compute(sp, ud.line, &tick, &line);
+        ud.osc->freq = line;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc;
+
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_expon_destroy(&ud.line);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_fmpair.c
@@ -1,0 +1,45 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_fmpair *osc;
+    sp_ftbl *ft;
+    int counter;
+} UserData;
+
+int t_fosc(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    ud.counter = 0;
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_fmpair_create(&ud.osc);
+
+    sp_gen_sine(sp, ud.ft);
+    sp_fmpair_init(sp, ud.osc, ud.ft);
+    ud.osc->freq = 500;
+
+    for(n = 0; n < tst->size; n++) {
+        if(ud.counter == 0){
+            ud.osc->freq = 500 + sp_rand(sp) % 2000;
+        }
+
+        sp_fmpair_compute(sp, ud.osc, NULL, &sp->out[0]);
+        ud.counter = (ud.counter + 1) % 4410;
+
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_fmpair_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_fof.c
@@ -1,0 +1,45 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_fof *fof;
+    sp_ftbl *sine;
+    sp_ftbl *win;
+} UserData;
+
+int t_fof(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, fof = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_ftbl_create(sp, &ud.sine, 2048);
+    sp_ftbl_create(sp, &ud.win, 1024);
+    sp_fof_create(&ud.fof);
+
+    sp_gen_sine(sp, ud.sine);
+    sp_gen_composite(sp, ud.win, "0.5 0.5 270 0.5");
+
+    sp_fof_init(sp, ud.fof, ud.sine, ud.win, 100, 0);
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0;
+        fof = 0;
+        sp_fof_compute(sp, ud.fof, &osc, &fof);
+        sp_test_add_sample(tst, fof);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_fof_destroy(&ud.fof);
+    sp_ftbl_destroy(&ud.sine);
+    sp_ftbl_destroy(&ud.win);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_fofilt.c
@@ -1,0 +1,39 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_fofilt *ff;
+} UserData;
+
+int t_fofilt(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT in = 0;
+
+    UserData ud;
+    sp_noise_create(&ud.ns);
+    sp_fofilt_create(&ud.ff);
+    sp_noise_init(sp, ud.ns);
+    sp_fofilt_init(sp, ud.ff);
+    ud.ff->freq = 500;
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_fofilt_compute(sp, ud.ff, &in, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_fofilt_destroy(&ud.ff);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_fog.c
@@ -1,0 +1,54 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_fog *fog;
+    sp_ftbl *wav;
+    sp_ftbl *win;
+    sp_phasor *phs;
+} UserData;
+
+int t_fog(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT phs = 0, fog = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_ftbl_loadfile(sp, &ud.wav, SAMPDIR "oneart.wav");
+    sp_ftbl_create(sp, &ud.win, 1024);
+    sp_fog_create(&ud.fog);
+    sp_phasor_create(&ud.phs);
+
+    sp_gen_composite(sp, ud.win, "0.5 0.5 270 0.5");
+
+    sp_fog_init(sp, ud.fog, ud.wav, ud.win, 100, 0);
+    ud.fog->trans = 0.9;
+
+    sp_phasor_init(sp, ud.phs, 0);
+    ud.phs->freq = 0.3 / ((SPFLOAT)ud.wav->size / sp->sr);
+
+    for(n = 0; n < tst->size; n++) {
+        phs = 0;
+        fog = 0;
+        sp_phasor_compute(sp, ud.phs, NULL, &phs);
+        ud.fog->spd = phs;
+        sp_fog_compute(sp, ud.fog, NULL, &fog);
+        sp_test_add_sample(tst, fog);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_fog_destroy(&ud.fog);
+    sp_ftbl_destroy(&ud.wav);
+    sp_ftbl_destroy(&ud.win);
+    sp_phasor_destroy(&ud.phs);
+
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_fold.c
@@ -1,0 +1,44 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_fold *fold;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_fold(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+
+    sp_fold_create(&ud.fold);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_fold_init(sp, ud.fold);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    sp->len = 44100 * 5;
+    for(n = 0; n < tst->size; n++) {
+        SPFLOAT osc = 0, fold = 0;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_fold_compute(sp, ud.fold, &osc, &fold);
+        sp->out[0] = fold;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_fold_destroy(&ud.fold);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_foo.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_foo(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_gbuzz.c
@@ -1,0 +1,36 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_gbuzz *buzz;
+    sp_ftbl *ft;
+    int counter;
+} UserData;
+
+int t_gbuzz(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    ud.counter = 0;
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_gbuzz_create(&ud.buzz);
+    sp_gen_sine(sp, ud.ft);
+    sp_gbuzz_init(sp, ud.buzz, ud.ft, 0);
+
+    for(n = 0; n < tst->size; n++) {
+        sp_gbuzz_compute(sp, ud.buzz, NULL, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_gbuzz_destroy(&ud.buzz);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_composite.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_composite(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 4096);
+    sp_gen_composite(sp, ft, "0.5 0.5 270 0.5");
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_file.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_file(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 4096);
+    sp_gen_file(sp, ft, SAMPDIR "oneart.wav");
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_gauss.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_gauss(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 4096);
+    sp_gen_gauss(sp, ft, 1, 123456);
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_line.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_line(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 4096);
+    sp_gen_line(sp, ft, "0 -1 2048 1 4096 -1");
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_sine.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_sine(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 4096);
+    sp_gen_sine(sp, ft);
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_sinesum.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_sinesum(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 4096);
+    sp_gen_sinesum(sp, ft, "1 0.5 0.25");
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_vals.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_vals(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 1);
+    sp_gen_vals(sp, ft, "1 1.5 -3 5");
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_gen_xline.c
@@ -1,0 +1,31 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_gen_xline(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    sp_ftbl *ft;
+    sp_ftbl_create(sp, &ft, 4096);
+    sp_gen_xline(sp, ft, "0 0.0001 4096 1.0");
+
+    for(n = 0; n < tst->size; n++) {
+        if(n < ft->size) {
+            out = ft->tbl[n];
+        } else {
+            out = 0;
+        }
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_granule.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_granule(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_hilbert.c
@@ -1,0 +1,63 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_hilbert *hilbert;
+    sp_osc *cos, *sin;
+    sp_ftbl *ft;
+    sp_diskin *diskin;
+} UserData;
+
+int t_hilbert(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT real = 0, imag = 0;
+    SPFLOAT diskin = 0;
+    SPFLOAT sin = 0, cos = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_hilbert_create(&ud.hilbert);
+    sp_osc_create(&ud.sin);
+    sp_osc_create(&ud.cos);
+    sp_diskin_create(&ud.diskin);
+    sp_ftbl_create(sp, &ud.ft, 8192);
+
+    sp_hilbert_init(sp, ud.hilbert);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.sin, ud.ft, 0);
+    sp_osc_init(sp, ud.cos, ud.ft, 0.25);
+    ud.sin->freq = 1000;
+    ud.cos->freq = 1000;
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+
+    for(n = 0; n < tst->size; n++) {
+        real = 0;
+        imag = 0;
+        diskin = 0;
+        sin = 0;
+        cos = 0;
+
+        sp_diskin_compute(sp, ud.diskin, NULL, &diskin);
+        sp_osc_compute(sp, ud.sin, NULL, &sin);
+        sp_osc_compute(sp, ud.cos, NULL, &cos);
+        sp_hilbert_compute(sp, ud.hilbert, &diskin, &real, &imag);
+        sp->out[0] = ((cos * real) + (sin * real)) * 0.7;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_hilbert_destroy(&ud.hilbert);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.sin);
+    sp_osc_destroy(&ud.cos);
+    sp_diskin_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_incr.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_incr(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_jcrev.c
@@ -1,0 +1,54 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_fosc *osc;
+    sp_ftbl *ft;
+    sp_jcrev *dsp;
+    int counter;
+} UserData;
+
+int t_jcrev(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    SPFLOAT in = 0, out = 0;
+
+    sp_srand(sp, 123456);
+    sp_jcrev_create(&ud.dsp);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_fosc_create(&ud.osc);
+
+    sp_jcrev_init(sp, ud.dsp);
+    ud.counter = 0;
+    sp_gen_sine(sp, ud.ft);
+    sp_fosc_init(sp, ud.osc, ud.ft);
+    ud.osc->freq = 500;
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0, out = 0;
+
+        if(ud.counter == 0){
+            ud.osc->freq = 500 + sp_rand(sp) % 2000;
+        }
+
+        sp_fosc_compute(sp, ud.osc, NULL, &in);
+        sp_jcrev_compute(sp, ud.dsp, &in, &out);
+
+        sp->out[0] = out;
+        ud.counter = (ud.counter + 1) % 4410;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_jcrev_destroy(&ud.dsp);
+    sp_ftbl_destroy(&ud.ft);
+    sp_fosc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_jitter.c
@@ -1,0 +1,47 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_fosc *osc;
+    sp_ftbl *ft;
+    sp_jitter *jit;
+} UserData;
+
+int t_jitter(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 1234567);
+
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_fosc_create(&ud.osc);
+    sp_jitter_create(&ud.jit);
+
+    sp_gen_sine(sp, ud.ft);
+    sp_fosc_init(sp, ud.osc, ud.ft);
+    sp_jitter_init(sp, ud.jit);
+    ud.jit->cpsMin = 0.5;
+    ud.jit->cpsMax = 4;
+    ud.jit->amp = 3;
+
+    for(n = 0; n < tst->size; n++) {
+        SPFLOAT jit = 0;
+        sp_jitter_compute(sp, ud.jit, NULL, &jit);
+        ud.osc->freq = sp_midi2cps(60 + jit);
+        sp_fosc_compute(sp, ud.osc, NULL, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_fosc_destroy(&ud.osc);
+    sp_jitter_destroy(&ud.jit);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_line.c
@@ -1,0 +1,53 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_line *line;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_line(sp_test *tst, sp_data *sp, const char *hash)
+{
+
+    sp_srand(sp, 1234567);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, line = 0;
+    SPFLOAT tick = 0;
+    UserData ud;
+
+    sp_line_create(&ud.line);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_line_init(sp, ud.line);
+    ud.line->a = 100;
+    ud.line->dur = 3;
+    ud.line->b = 400;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        if(n == 0) tick = 1; else tick = 0;
+        sp_line_compute(sp, ud.line, &tick, &line);
+        ud.osc->freq = line;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc;
+
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_line_destroy(&ud.line);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_lpc.c
@@ -1,0 +1,42 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_spa *wav;
+    sp_lpc *lpc;
+} user_data;
+
+int t_lpc(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    user_data dt;
+    SPFLOAT diskin;
+    SPFLOAT out;
+
+    diskin = 0;
+    out = 0;
+    sp_srand(sp, 0);
+    sp_lpc_create(&dt.lpc);
+    sp_lpc_init(sp, dt.lpc, 512);
+    sp_spa_create(&dt.wav);
+    sp_spa_init(sp, dt.wav, SAMPDIR "oneart.spa");
+
+
+    for(n = 0; n < tst->size; n++) {
+        sp_spa_compute(sp, dt.wav, NULL, &diskin);
+        sp_lpc_compute(sp, dt.lpc, &diskin, &out);
+
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_spa_destroy(&dt.wav);
+    sp_lpc_destroy(&dt.lpc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_lpf18.c
@@ -1,0 +1,64 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc[3];
+    sp_ftbl *ft;
+    sp_lpf18 *lpf;
+    sp_osc *lfo;
+    sp_ftbl *sine_ft;
+} UserData;
+
+int t_lpf18(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    sp_srand(sp, 0);
+    int i;
+    UserData ud;
+    sp_ftbl_create(sp, &ud.ft, 4096);
+    for(i = 0; i < 3; i++) sp_osc_create(&ud.osc[i]);
+    sp_lpf18_create(&ud.lpf);
+    sp_osc_create(&ud.lfo);
+    sp_ftbl_create(sp, &ud.sine_ft, 4096);
+    sp_gen_sine(sp, ud.sine_ft);
+
+    sp_gen_line(sp, ud.ft, "0 1 4096 -1");
+    sp_osc_init(sp, ud.osc[0], ud.ft, 0);
+    ud.osc[0]->freq = sp_midi2cps(40 - 0.05);
+    sp_osc_init(sp, ud.osc[1], ud.ft, 0);
+    ud.osc[1]->freq = sp_midi2cps(40 - 12);
+    sp_osc_init(sp, ud.osc[2], ud.ft, 0);
+    ud.osc[2]->freq = sp_midi2cps(40 + 0.05);
+    sp_lpf18_init(sp, ud.lpf);
+    sp_osc_init(sp, ud.lfo, ud.sine_ft, 0);
+    ud.lfo->freq = 0.4;
+    SPFLOAT out = 0, osc = 0, filt = 0, lfo = 0;
+
+    for(n = 0; n < tst->size; n++) {
+        int i;
+        for(i = 0; i < 3; i++) {
+            sp_osc_compute(sp, ud.osc[i], NULL, &osc);
+            out += osc * 0.3;
+        }
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        ud.lpf->cutoff = 100 + 3000 * (0.5 * (lfo + 1));
+        sp_lpf18_compute(sp, ud.lpf, &out, &filt);
+        out = filt;
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    for(i = 0; i < 3; i++) sp_osc_destroy(&ud.osc[i]);
+    sp_lpf18_destroy(&ud.lpf);
+    sp_osc_destroy(&ud.lfo);
+    sp_ftbl_destroy(&ud.sine_ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_maygate.c
@@ -1,0 +1,86 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_tevent *te;
+    sp_metro *met;
+    sp_tenv *tenv;
+    sp_maygate *mg;
+    SPFLOAT freq;
+    sp_data *sp;
+} UserData;
+
+static void freq_reinit(void *ud){
+    UserData *udata = ud;
+    udata->osc->freq = 500 + sp_rand(udata->sp) % 2000;
+}
+
+static void freq_compute(void *ud, SPFLOAT *out){
+    UserData *udata = ud;
+    *out = udata->osc->freq;
+}
+
+int t_maygate(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT trig = 0;
+    SPFLOAT env = 0;
+    SPFLOAT osc = 0;
+    SPFLOAT mgate = 0;
+
+    sp_srand(sp, 123456);
+    UserData ud;
+    ud.freq = 400;
+    ud.sp = sp;
+    sp_maygate_create(&ud.mg);
+    sp_tenv_create(&ud.tenv);
+    sp_metro_create(&ud.met);
+    sp_tevent_create(&ud.te);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_osc_create(&ud.osc);
+
+    sp_maygate_init(sp, ud.mg);
+    ud.mg->prob = 0.2;
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.01;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel =  0.2;
+
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 12;
+    sp_tevent_init(sp, ud.te, freq_reinit, freq_compute, &ud);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+
+    for(n = 0; n < tst->size; n++) {
+        trig = 0;
+        env = 0;
+        osc = 0;
+        mgate = 0;
+        sp_metro_compute(sp, ud.met, NULL, &trig);
+        sp_maygate_compute(sp, ud.mg, &trig, &mgate);
+        sp_tevent_compute(sp, ud.te, &trig, &ud.osc->freq);
+        sp_tenv_compute(sp, ud.tenv, &trig, &env);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc * env * mgate;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_maygate_destroy(&ud.mg);
+    sp_tenv_destroy(&ud.tenv);
+    sp_metro_destroy(&ud.met);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_tevent_destroy(&ud.te);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_metro.c
@@ -1,0 +1,64 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_tenv *tenv;
+    sp_metro *met;
+    sp_randi *rand;
+    SPFLOAT freq;
+} UserData;
+
+int t_metro(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, trig = 0, tenv = 0;
+
+    UserData ud;
+    SPFLOAT *freqp = &ud.freq;
+    ud.freq = 400;
+
+    sp_srand(sp, 12345);
+
+    sp_randi_create(&ud.rand);
+    sp_metro_create(&ud.met);
+    sp_tenv_create(&ud.tenv);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_osc_create(&ud.osc);
+
+    sp_randi_init(sp, ud.rand);
+    ud.rand->min = 2.0;
+    ud.rand->max= 15.0;
+    sp_metro_init(sp, ud.met);
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.005;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel = 0.003;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->freq = *freqp;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0; trig = 0; tenv = 0;
+        sp_randi_compute(sp, ud.rand, NULL, &ud.met->freq);
+        sp_metro_compute(sp, ud.met, NULL, &trig);
+        sp_tenv_compute(sp, ud.tenv, &trig, &tenv);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, osc * tenv);
+    }
+
+    sp_randi_destroy(&ud.rand);
+    sp_metro_destroy(&ud.met);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_tenv_destroy(&ud.tenv);
+
+    fail = sp_test_verify(tst, hash);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_mincer.c
@@ -1,0 +1,52 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_mincer *mincer;
+    sp_ftbl *ft;
+    sp_randi *randi;
+} UserData;
+
+int t_mincer(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT mincer = 0, randi = 0;
+
+    UserData ud;
+    sp_srand(sp, 1234567);
+
+    sp_mincer_create(&ud.mincer);
+    /* allocates loads an audio file into a ftable */
+    sp_ftbl_loadfile(sp, &ud.ft, SAMPDIR "oneart.wav");
+
+    sp_randi_create(&ud.randi);
+
+    sp_mincer_init(sp, ud.mincer, ud.ft, 2048);
+    sp_randi_init(sp, ud.randi);
+    ud.randi->min = 0;
+    ud.randi->max = 5;
+    ud.randi->cps = 1;
+
+    for(n = 0; n < tst->size; n++) {
+        mincer = 0; randi = 0;
+
+        sp_randi_compute(sp, ud.randi, NULL, &randi);
+        ud.mincer->time = randi;
+        ud.mincer->amp = 1;
+        ud.mincer->pitch = 1;
+        sp_mincer_compute(sp, ud.mincer, NULL, &mincer);
+        sp_test_add_sample(tst, mincer);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_mincer_destroy(&ud.mincer);
+    sp_ftbl_destroy(&ud.ft);
+    sp_randi_destroy(&ud.randi);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_modalres.c
@@ -1,0 +1,140 @@
+#include <stdlib.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_modalres *mode[4];
+    SPFLOAT *mfreq[4];
+    SPFLOAT *Q[4];
+    SPFLOAT amp;
+    SPFLOAT *freq;
+    SPFLOAT lfreq;
+} modal;
+
+typedef struct {
+    modal *mod;
+    sp_metro *met;
+    sp_ftbl *notes;
+    sp_tseq *seq;
+} UserData;
+
+static int modal_create(modal **md)
+{
+    *md = malloc(sizeof(modal));
+    return SP_OK;
+}
+
+static int modal_init(sp_data *sp, modal *md)
+{
+    int i;
+    md->amp = 0.5;
+
+
+    for(i = 0; i < 4; i++) {
+        sp_modalres_create(&md->mode[i]);
+        sp_modalres_init(sp, md->mode[i]);
+        md->mfreq[i] = &md->mode[i]->freq;
+        md->Q[i] = &md->mode[i]->q;
+    }
+
+    *md->mfreq[0] = 1000;
+    *md->mfreq[1] = 3000;
+    *md->Q[0] = 12;
+    *md->Q[1] = 8;
+
+    *md->mfreq[2] = 440;
+    *md->mfreq[3] = *md->mfreq[2] * 2.01081;
+    *md->Q[2] = 500;
+    *md->Q[3] = 420;
+
+    md->freq = md->mfreq[2];
+    md->lfreq = *md->freq;
+    return SP_OK;
+}
+
+static int modal_compute(sp_data *sp, modal *md, SPFLOAT *in, SPFLOAT *out)
+{
+    SPFLOAT exc1, exc2, exc;
+    SPFLOAT res1, res2, res;
+
+    if(*md->freq != md->lfreq) {
+        *md->mfreq[3] = *md->freq * 2.01081;
+        md->lfreq = *md->freq;
+    }
+
+    sp_modalres_compute(sp, md->mode[0], in, &exc1);
+    sp_modalres_compute(sp, md->mode[1], in, &exc2);
+    exc = (exc1 + exc2) * 0.5;
+
+    if(exc > md->amp) {
+        exc = md->amp;
+    } else if (exc < 0 ) {
+        exc = 0;
+    }
+
+    sp_modalres_compute(sp, md->mode[2], &exc, &res1);
+    sp_modalres_compute(sp, md->mode[3], &exc, &res2);
+    res = (res1 + res2) * 0.5;
+
+
+    *out = (exc + res) * md->amp;
+
+    return SP_OK;
+}
+
+static int modal_destroy(modal **md)
+{
+    int i;
+    modal *mdp = *md;
+    for(i = 0; i < 4; i++) {
+        sp_modalres_destroy(&mdp->mode[i]);
+    }
+
+    free(*md);
+    return SP_OK;
+}
+
+int t_modalres(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    SPFLOAT met = 0, mod = 0, nn;
+
+    modal_create(&ud.mod);
+    modal_init(sp, ud.mod);
+
+    sp_metro_create(&ud.met);
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 3.0;
+
+    sp_ftbl_create(sp, &ud.notes, 1);
+    sp_gen_vals(sp, ud.notes, "60 67 62 69 76");
+
+    sp_tseq_create(&ud.seq);
+    sp_tseq_init(sp, ud.seq, ud.notes);
+
+    for(n = 0; n < tst->size; n++) {
+        met = 0;
+        mod = 0;
+        nn = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_tseq_compute(sp, ud.seq, &met, &nn);
+        *ud.mod->freq = sp_midi2cps(nn);
+        modal_compute(sp, ud.mod, &met, &mod);
+        sp->out[0] = mod;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    modal_destroy(&ud.mod);
+    sp_metro_destroy(&ud.met);
+    sp_ftbl_destroy(&ud.notes);
+    sp_tseq_destroy(&ud.seq);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_moogladder.c
@@ -1,0 +1,49 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_moogladder *moog;
+    int counter;
+} UserData;
+
+int t_moogladder(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    ud.counter = 0;
+    sp_noise_create(&ud.ns);
+    sp_moogladder_create(&ud.moog);
+    sp_noise_init(sp, ud.ns);
+    sp_moogladder_init(sp, ud.moog);
+
+    SPFLOAT in;
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+
+        if(ud.counter == 0) {
+            ud.moog->res = 0.8;
+            ud.moog->freq = 500 + sp_rand(sp) % 4000;
+        }
+
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_moogladder_compute(sp, ud.moog, &in, &sp->out[0]);
+        ud.counter = (ud.counter + 1) % 5000;
+
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_moogladder_destroy(&ud.moog);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_noise.c
@@ -1,0 +1,33 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+} UserData;
+
+int t_noise(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    sp_noise_create(&ud.ns);
+    sp_noise_init(sp, ud.ns);
+
+    SPFLOAT in;
+
+    for(n = 0; n < tst->size; n++) {
+        sp_noise_compute(sp, ud.ns, &in, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_nsmp.c
@@ -1,0 +1,47 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_metro *met;
+    sp_nsmp *nsmp;
+    sp_ftbl *ft;
+} UserData;
+
+int t_nsmp(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT met = 0, nsmp = 0;
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_ftbl_loadfile(sp, &ud.ft, SAMPDIR "oneart.wav");
+    sp_nsmp_create(&ud.nsmp);
+    sp_metro_create(&ud.met);
+
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 2;
+    sp_nsmp_init(sp, ud.nsmp, ud.ft, 44100, SAMPDIR "oneart.ini");
+
+    for(n = 0; n < tst->size; n++) {
+        met = 0; nsmp = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        if(met) {
+            ud.nsmp->index = sp_rand(sp) % 3;
+        }
+        sp_nsmp_compute(sp, ud.nsmp, &met, &nsmp);
+        sp_test_add_sample(tst, nsmp);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_nsmp_destroy(&ud.nsmp);
+    sp_metro_destroy(&ud.met);
+
+    sp_ftbl_destroy(&ud.ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_osc.c
@@ -1,0 +1,38 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_osc(sp_test *tst, sp_data *sp, const char *hash) {
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc;
+    sp_osc *osc_d;
+    sp_ftbl *ft_d;
+
+    sp_ftbl_create(sp, &ft_d, 2048);
+    sp_osc_create(&osc_d);
+
+    sp_gen_sine(sp, ft_d);
+    sp_osc_init(sp, osc_d, ft_d, 0);
+    osc_d->freq = 500;
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0;
+        sp_osc_compute(sp, osc_d, NULL, &osc);
+        sp_out(sp, 0, osc);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ft_d);
+    sp_osc_destroy(&osc_d);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_oscmorph.c
@@ -1,0 +1,55 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_oscmorph *oscmorph;
+    sp_ftbl *wt1;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_oscmorph(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, oscmorph = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_oscmorph_create(&ud.oscmorph);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_ftbl_create(sp, &ud.wt1, 2048);
+
+    sp_gen_line(sp, ud.wt1, "0 1 2048 -1");
+    sp_gen_sine(sp, ud.ft);
+
+    sp_ftbl *ft_array[] = {ud.wt1, ud.ft};
+    sp_oscmorph_init(sp, ud.oscmorph, ft_array, 2, 0);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->freq = 1;
+    ud.osc->amp = 1;
+
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, oscmorph = 0;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        osc = (1 + osc) * 0.5;
+        ud.oscmorph->wtpos = osc;
+        sp_oscmorph_compute(sp, ud.oscmorph, NULL, &oscmorph);
+        sp_test_add_sample(tst, oscmorph);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_oscmorph_destroy(&ud.oscmorph);
+    sp_ftbl_destroy(&ud.ft);
+    sp_ftbl_destroy(&ud.wt1);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_padsynth.c
@@ -1,0 +1,54 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct user_data {
+    sp_ftbl *ft, *amps;
+    sp_osc *osc;
+    SPFLOAT fc;
+} UserData;
+
+int t_padsynth(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    UserData ud;
+    int i;
+    sp_srand(sp, 12345);
+    sp_ftbl_create(sp, &ud.amps, 64);
+    sp_ftbl_create(sp, &ud.ft, 262144);
+    sp_osc_create(&ud.osc);
+
+    ud.amps->tbl[0] = 0.0;
+
+    for(i = 1; i < ud.amps->size; i++){
+        ud.amps->tbl[i] = 1.0 / i;
+        if((i % 2) == 0) ud.amps->tbl[i] *= 2.0;
+    }
+
+
+    /* Discovered empirically. multiply frequency by this constant. */
+    ud.fc = 1 / (6.0 * 440);
+    sp_gen_padsynth(sp, ud.ft, ud.amps, sp_midi2cps(60), 40.0);
+
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->freq = sp_midi2cps(70) * ud.fc;
+    ud.osc->amp = 1.0;
+
+    for(n = 0; n < tst->size; n++) {
+        sp_osc_compute(sp, ud.osc, NULL, &out);
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_osc_destroy(&ud.osc);
+    sp_ftbl_destroy(&ud.amps);
+    sp_ftbl_destroy(&ud.ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_pan2.c
@@ -1,0 +1,52 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_pan2 *pan2;
+    sp_osc *osc;
+    sp_osc *lfo;
+    sp_ftbl *ft;
+} UserData;
+
+int t_pan2(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, outL = 0, outR = 0, lfo = 0;
+
+    UserData ud;
+
+    sp_pan2_create(&ud.pan2);
+    sp_osc_create(&ud.osc);
+    sp_osc_create(&ud.lfo);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_pan2_init(sp, ud.pan2);
+    ud.pan2->type = 2;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_osc_init(sp, ud.lfo, ud.ft, 0);
+    ud.lfo->amp = 1;
+    ud.lfo->freq = 1;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0; outL = 0; outR = 0; lfo = 0;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        ud.pan2->pan = lfo;
+        sp_pan2_compute(sp, ud.pan2, &osc, &outL, &outR);
+        sp_test_add_sample(tst, outL);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_pan2_destroy(&ud.pan2);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_osc_destroy(&ud.lfo);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_panst.c
@@ -1,0 +1,58 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_panst *panst;
+    sp_osc *osc;
+    sp_osc *lfo;
+    sp_ftbl *ft;
+} UserData;
+
+int t_panst(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    SPFLOAT osc = 0, outL = 0, outR = 0, lfo = 0;
+
+    sp_panst_create(&ud.panst);
+    sp_osc_create(&ud.osc);
+    sp_osc_create(&ud.lfo);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_panst_init(sp, ud.panst);
+    ud.panst->type = 0;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_osc_init(sp, ud.lfo, ud.ft, 0);
+    ud.lfo->amp = 1;
+    ud.lfo->freq = 0.5;
+
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n += 2) {
+        osc = 0; outL = 0; outR = 0; lfo = 0;
+
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        ud.panst->pan = lfo;
+
+        sp_panst_compute(sp, ud.panst, &osc, &osc, &outL, &outR);
+        sp_test_add_sample(tst, outL);
+        sp_test_add_sample(tst, outR);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_panst_destroy(&ud.panst);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_osc_destroy(&ud.lfo);
+
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_pareq.c
@@ -1,0 +1,43 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_pareq *pareq;
+    sp_noise *noise;
+    sp_ftbl *ft;
+} UserData;
+
+int t_pareq(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+
+    sp_pareq_create(&ud.pareq);
+    sp_noise_create(&ud.noise);
+
+    sp_pareq_init(sp, ud.pareq);
+    ud.pareq->fc = 500;
+    sp_noise_init(sp, ud.noise);
+    ud.noise->amp = 0.4;
+
+    for(n = 0; n < tst->size; n++) {
+        SPFLOAT noise = 0, pareq = 0;
+        sp_noise_compute(sp, ud.noise, NULL, &noise);
+        sp_pareq_compute(sp, ud.pareq, &noise, &pareq);
+        sp->out[0] = pareq;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_pareq_destroy(&ud.pareq);
+    sp_noise_destroy(&ud.noise);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_paulstretch.c
@@ -1,0 +1,40 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_paulstretch *paulstretch;
+    sp_ftbl *ft;
+} UserData;
+
+int t_paulstretch(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT paulstretch = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_paulstretch_create(&ud.paulstretch);
+    sp_ftbl_loadfile(sp, &ud.ft, SAMPDIR "oneart.wav");
+
+    sp_paulstretch_init(sp, ud.paulstretch, ud.ft, 1.0, 10);
+
+
+    for(n = 0; n < tst->size; n++) {
+        paulstretch = 0;
+        sp_paulstretch_compute(sp, ud.paulstretch, NULL, &paulstretch);
+        sp->out[0] = paulstretch;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_paulstretch_destroy(&ud.paulstretch);
+    sp_ftbl_destroy(&ud.ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_peakeq.c
@@ -1,0 +1,48 @@
+#include <math.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_peakeq *peakeq;
+    int counter;
+} UserData;
+
+int t_peakeq(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    SPFLOAT in = 0;
+    SPFLOAT out = 0;
+
+    ud.counter = 0;
+    sp_noise_create(&ud.ns);
+    sp_peakeq_create(&ud.peakeq);
+    sp_noise_init(sp, ud.ns);
+    sp_peakeq_init(sp, ud.peakeq);
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        out = 0;
+        if(ud.counter == 0) {
+            ud.peakeq->freq = 500 + sp_rand(sp) % 4000;
+            ud.peakeq->bw = fabs(ud.peakeq->freq * 0.5);
+        }
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_peakeq_compute(sp, ud.peakeq, &in, &out);
+        ud.counter = (ud.counter + 1) % 5000;
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_peakeq_destroy(&ud.peakeq);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_peaklim.c
@@ -1,0 +1,44 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_peaklim *peaklim;
+    sp_diskin *diskin;
+} UserData;
+
+int t_peaklim(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT diskin = 0, peaklim = 0;
+
+    UserData ud;
+    sp_srand(sp, 1234567);
+
+    sp_peaklim_create(&ud.peaklim);
+    sp_diskin_create(&ud.diskin);
+
+    sp_peaklim_init(sp, ud.peaklim);
+    ud.peaklim->atk = 0.1;
+    ud.peaklim->rel = 0.1;
+    ud.peaklim->thresh = -30;
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+
+    for(n = 0; n < tst->size; n++) {
+        diskin = 0; peaklim = 0;
+        sp_diskin_compute(sp, ud.diskin, NULL, &diskin);
+        sp_peaklim_compute(sp, ud.peaklim, &diskin, &peaklim);
+        sp_test_add_sample(tst, peaklim);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_peaklim_destroy(&ud.peaklim);
+    sp_diskin_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_phaser.c
@@ -1,0 +1,40 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_phaser *phaser;
+    sp_diskin *disk;
+} UserData;
+
+int t_phaser(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    SPFLOAT disk1 = 0, disk2 = 0, phaser = 0, foo = 0;
+    UserData ud;
+
+    sp_phaser_create(&ud.phaser);
+    sp_diskin_create(&ud.disk);
+
+    sp_diskin_init(sp, ud.disk, SAMPDIR "oneart.wav");
+    sp_phaser_init(sp, ud.phaser);
+
+    for(n = 0; n < tst->size; n++) {
+        disk1 = 0; disk2 = 0; phaser = 0; foo = 0;
+        sp_diskin_compute(sp, ud.disk, NULL, &disk1);
+        disk2 = disk1;
+        sp_phaser_compute(sp, ud.phaser, &disk1, &disk2, &phaser, &foo);
+        sp_test_add_sample(tst, phaser);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_phaser_destroy(&ud.phaser);
+    sp_diskin_destroy(&ud.disk);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_phasewarp.c
@@ -1,0 +1,97 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_metro *met;
+    sp_ftbl *ft;
+    sp_phasor *phs;
+    sp_tenv *tenv;
+    sp_phasewarp *phasewarp;
+    sp_scale *scl;
+    sp_tseq *ts;
+    sp_ftbl *seq;
+} UserData;
+
+int t_phasewarp(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT met = 0;
+    SPFLOAT tenv = 0;
+    SPFLOAT phs = 0;
+    SPFLOAT pd = 0;
+    SPFLOAT amt = 0;
+    SPFLOAT rev = 0;
+    SPFLOAT frq = 0;
+
+    UserData ud;
+    sp_srand(sp, 1234567);
+
+    sp_phasewarp_create(&ud.phasewarp);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_gen_sine(sp, ud.ft);
+    sp_metro_create(&ud.met);
+
+    sp_tenv_create(&ud.tenv);
+    sp_phasor_create(&ud.phs);
+    sp_scale_create(&ud.scl);
+    sp_ftbl_create(sp, &ud.seq, 1);
+    sp_gen_vals(sp, ud.seq, "62 67 69 72");
+    sp_tseq_create(&ud.ts);
+
+
+    sp_phasewarp_init(sp, ud.phasewarp);
+    sp_phasor_init(sp, ud.phs, 0);
+    ud.phs->freq = 440;
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.001;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel = 0.2;
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 8;
+    sp_scale_init(sp, ud.scl);
+    ud.scl->min = -0.8;
+    ud.scl->max = 0;
+    sp_tseq_init(sp, ud.ts, ud.seq);
+
+
+    for(n = 0; n < tst->size; n++) {
+        met = 0;
+        tenv = 0;
+        phs = 0;
+        pd = 0;
+        amt = 0;
+        rev = 0;
+        frq = 0;
+
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_tenv_compute(sp, ud.tenv, &met, &tenv);
+        sp_tseq_compute(sp, ud.ts, &met, &frq);
+        frq = sp_midi2cps(frq);
+        ud.phs->freq = frq;
+        sp_phasor_compute(sp, ud.phs, NULL, &phs);
+        rev = 1 - tenv;
+        sp_scale_compute(sp, ud.scl, &rev, &amt);
+        ud.phasewarp->amount = amt;
+        sp_phasewarp_compute(sp, ud.phasewarp, &phs, &pd);
+
+        sp_test_add_sample(tst, pd);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_phasewarp_destroy(&ud.phasewarp);
+    sp_ftbl_destroy(&ud.ft);
+    sp_metro_destroy(&ud.met);
+
+    sp_tenv_destroy(&ud.tenv);
+    sp_phasor_destroy(&ud.phs);
+    sp_scale_destroy(&ud.scl);
+    sp_ftbl_destroy(&ud.seq);
+    sp_tseq_destroy(&ud.ts);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_phasor.c
@@ -1,0 +1,30 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_phasor *phs;
+} UserData;
+
+int t_phasor(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    sp_phasor_create(&ud.phs);
+    sp_phasor_init(sp, ud.phs, 0);
+
+    for(n = 0; n < tst->size; n++) {
+        sp_phasor_compute(sp, ud.phs, NULL, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_phasor_destroy(&ud.phs);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_pinknoise.c
@@ -1,0 +1,33 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_pinknoise *ns;
+} UserData;
+
+int t_pinknoise(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT out = 0;
+
+    UserData ud;
+    sp_srand(sp, 12345);
+    sp_pinknoise_create(&ud.ns);
+    sp_pinknoise_init(sp, ud.ns);
+
+    for(n = 0; n < tst->size; n++) {
+        out = 0;
+        sp_pinknoise_compute(sp, ud.ns, NULL, &out);
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_pinknoise_destroy(&ud.ns);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_pitchamdf.c
@@ -1,0 +1,62 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_pitchamdf *pitchamdf;
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_blsaw *blsaw;
+    sp_randh *randh;
+} UserData;
+
+int t_pitchamdf(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT freq = 0, amp = 0, blsaw = 0, randh = 0, osc = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_pitchamdf_create(&ud.pitchamdf);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_blsaw_create(&ud.blsaw);
+    sp_randh_create(&ud.randh);
+
+    sp_pitchamdf_init(sp, ud.pitchamdf, 200, 500);
+    sp_randh_init(sp, ud.randh);
+    ud.randh->max = 500;
+    ud.randh->min = 200;
+    ud.randh->freq = 6;
+
+    sp_blsaw_init(sp, ud.blsaw);
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+
+    for(n = 0; n < tst->size; n++) {
+        freq = 0, amp = 0, blsaw = 0, randh = 0, osc = 0;
+        sp_randh_compute(sp, ud.randh, NULL, &randh);
+        *ud.blsaw->freq = randh;
+        sp_blsaw_compute(sp, ud.blsaw, NULL, &blsaw);
+        sp_pitchamdf_compute(sp, ud.pitchamdf, &blsaw, &freq, &amp);
+        ud.osc->freq = freq;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, osc);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_blsaw_destroy(&ud.blsaw);
+    sp_randh_destroy(&ud.randh);
+    sp_pitchamdf_destroy(&ud.pitchamdf);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_pluck.c
@@ -1,0 +1,45 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_pluck *pluck;
+    sp_metro *met;
+} UserData;
+
+int t_pluck(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    sp_srand(sp, 1337);
+    SPFLOAT pluck = 0, met = 0;
+    SPFLOAT notes[] = {60, 63, 67, 70, 74};
+
+    sp_pluck_create(&ud.pluck);
+    sp_metro_create(&ud.met);
+
+    sp_pluck_init(sp, ud.pluck, 400);
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 4;
+
+    for(n = 0; n < tst->size; n++) {
+        pluck = 0, met = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        if(met) {
+            ud.pluck->freq = sp_midi2cps(notes[sp_rand(sp) % 5]);
+        }
+        sp_pluck_compute(sp, ud.pluck, &met, &pluck);
+        sp_test_add_sample(tst, pluck);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_pluck_destroy(&ud.pluck);
+    sp_metro_destroy(&ud.met);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_port.c
@@ -1,0 +1,62 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_metro *mt;
+    sp_ftbl *sine, *nn;
+    sp_tseq *seq;
+    sp_port *prt;
+} UserData;
+
+int t_port(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp,123456);
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    SPFLOAT osc, mt, nn, freq, pfreq;
+
+    sp_metro_create(&ud.mt);
+    sp_ftbl_create(sp, &ud.sine, 2048);
+    sp_ftbl_create(sp, &ud.nn, 1);
+    sp_osc_create(&ud.osc);
+    sp_port_create(&ud.prt);
+
+    sp_gen_vals(sp, ud.nn, "60 63 65 60 63 67");
+    sp_tseq_create(&ud.seq);
+    sp_tseq_init(sp, ud.seq, ud.nn);
+
+    sp_port_init(sp, ud.prt);
+    ud.prt->smooth = 0.02;
+    sp_metro_init(sp, ud.mt);
+    ud.mt->freq = 4.0;
+    sp_gen_sine(sp, ud.sine);
+    sp_osc_init(sp, ud.osc, ud.sine, 0);
+
+
+    for(n = 0; n < tst->size; n++) {
+        sp_metro_compute(sp, ud.mt, NULL, &mt);
+        sp_tseq_compute(sp, ud.seq, &mt, &nn);
+        freq = sp_midi2cps(nn);
+        sp_port_compute(sp, ud.prt, &freq, &pfreq);
+        ud.osc->freq = pfreq;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_port_destroy(&ud.prt);
+    sp_tseq_destroy(&ud.seq);
+    sp_metro_destroy(&ud.mt);
+    sp_ftbl_destroy(&ud.sine);
+    sp_ftbl_destroy(&ud.nn);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_posc3.c
@@ -1,0 +1,43 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_posc3 *posc3;
+    sp_ftbl *ft;
+    int counter;
+} UserData;
+
+int t_posc3(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    sp_srand(sp, 123456);
+    UserData ud;
+    ud.counter = 0;
+    sp_ftbl_create(sp, &ud.ft, 1024);
+    sp_posc3_create(&ud.posc3);
+
+    sp_gen_sine(sp, ud.ft);
+    sp_posc3_init(sp, ud.posc3, ud.ft);
+    ud.posc3->freq = 500;
+
+    for(n = 0; n < tst->size; n++) {
+        if(ud.counter == 0){
+            ud.posc3->freq = 500 + sp_rand(sp) % 2000;
+        }
+        sp_posc3_compute(sp, ud.posc3, NULL, &sp->out[0]);
+        ud.counter = (ud.counter + 1) % 4410;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_posc3_destroy(&ud.posc3);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_prop.c
@@ -1,0 +1,58 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_prop *prop;
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_tenv *tenv;
+} UserData;
+
+int t_prop(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, prop = 0, tenv = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_prop_create(&ud.prop);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_tenv_create(&ud.tenv);
+
+    sp_prop_init(sp, ud.prop, "2(++)3(+++)-2(-2(++))+5(+++++)");
+    ud.prop->bpm = 80;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.01;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel =  0.2;
+
+    ud.osc->freq = 500;
+
+    for(n = 0; n < tst->size; n++) {
+
+        osc = 0, prop = 0, tenv = 0;
+        ud.prop->bpm = 80;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_prop_compute(sp, ud.prop, NULL, &prop);
+        sp_tenv_compute(sp, ud.tenv, &prop, &tenv);
+        sp->out[0] = osc * tenv;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_prop_destroy(&ud.prop);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_tenv_destroy(&ud.tenv);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_pshift.c
@@ -1,0 +1,45 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_pshift *pshift;
+    sp_diskin *diskin;
+} UserData;
+
+int t_pshift(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    SPFLOAT diskin = 0, pshift = 0;
+
+    sp_pshift_create(&ud.pshift);
+    sp_diskin_create(&ud.diskin);
+
+    sp_pshift_init(sp, ud.pshift);
+    *ud.pshift->shift = 7;
+    *ud.pshift->window = 500;
+    /* half window size is smoothest sounding */
+    *ud.pshift->xfade = 250;
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+
+    for(n = 0; n < tst->size; n++) {
+        diskin = 0;
+        pshift = 0;
+        sp_diskin_compute(sp, ud.diskin, NULL, &diskin);
+        sp_pshift_compute(sp, ud.pshift, &diskin, &pshift);
+        sp_test_add_sample(tst, pshift);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_pshift_destroy(&ud.pshift);
+    sp_diskin_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_ptrack.c
@@ -1,0 +1,63 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_ptrack *ptrack;
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_blsaw *blsaw;
+    sp_randh *randh;
+} UserData;
+
+int t_ptrack(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT freq = 0, amp = 0, blsaw = 0, randh = 0, osc = 0;
+
+    UserData ud;
+    sp_srand(sp, 1234567);
+
+    sp_ptrack_create(&ud.ptrack);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_blsaw_create(&ud.blsaw);
+    sp_randh_create(&ud.randh);
+
+    sp_ptrack_init(sp, ud.ptrack, 512, 20);
+    sp_randh_init(sp, ud.randh);
+    ud.randh->max = 500;
+    ud.randh->min = 200;
+    ud.randh->freq = 6;
+
+    sp_blsaw_init(sp, ud.blsaw);
+    *ud.blsaw->amp = 1.0;
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+
+    for(n = 0; n < tst->size; n++) {
+        freq = 0; amp = 0; blsaw = 0; randh = 0; osc = 0;
+        sp_randh_compute(sp, ud.randh, NULL, &randh);
+        *ud.blsaw->freq = randh;
+        sp_blsaw_compute(sp, ud.blsaw, NULL, &blsaw);
+        sp_ptrack_compute(sp, ud.ptrack, &blsaw, &freq, &amp);
+        ud.osc->freq = freq;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, osc);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_blsaw_destroy(&ud.blsaw);
+    sp_randh_destroy(&ud.randh);
+    sp_ptrack_destroy(&ud.ptrack);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_randh.c
@@ -1,0 +1,46 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_randh *randh;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_randh(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT freq;
+
+    UserData ud;
+    sp_srand(sp, 12345);
+    sp_ftbl_create(sp, &ud.ft, 1024);
+    sp_osc_create(&ud.osc);
+    sp_randh_create(&ud.randh);
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_randh_init(sp, ud.randh);
+
+    ud.randh->min = 300;
+    ud.randh->max = 3000;
+
+    for(n = 0; n < tst->size; n++) {
+        sp_randh_compute(sp, ud.randh, NULL, &freq);
+        ud.osc->freq = freq;
+        sp_osc_compute(sp, ud.osc, NULL, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_randh_destroy(&ud.randh);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_random.c
@@ -1,0 +1,40 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_random *random;
+} UserData;
+
+int t_random(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT random = 0;
+
+    sp_srand(sp,1234567);
+    UserData ud;
+
+    sp_random_create(&ud.random);
+
+    sp_random_init(sp, ud.random);
+    ud.random->min = -0.2;
+    ud.random->max = 0.2;
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        random = 0;
+        sp_random_compute(sp, ud.random, NULL, &random);
+        sp->out[0] = random;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+    sp_random_destroy(&ud.random);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_reverse.c
@@ -1,0 +1,74 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_tenv *tenv;
+    sp_reverse *rv;
+} UserData;
+
+int t_reverse(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    sp_srand(sp, 123456);
+    UserData ud;
+    SPFLOAT env = 0;
+    SPFLOAT osc = 0;
+    SPFLOAT rv = 0;
+    SPFLOAT dry = 0;
+    SPFLOAT trig;
+
+    sp_reverse_create(&ud.rv);
+    sp_tenv_create(&ud.tenv);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_osc_create(&ud.osc);
+
+    sp_reverse_init(sp, ud.rv, 1.0);
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.03;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel =  0.3;
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->freq = 1000;
+    ud.osc->amp = 0.5;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        env = 0;
+        osc = 0;
+        rv = 0;
+        dry = 0;
+        trig = 0;
+
+        if(n == 0){
+            trig = 1.0;
+        }else{
+            trig = 0.0;
+        }
+        sp_tenv_compute(sp, ud.tenv, &trig, &env);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        dry = osc * env;
+        sp_reverse_compute(sp, ud.rv, &dry, &rv);
+        sp->out[0] = dry + rv;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    sp_reverse_destroy(&ud.rv);
+    sp_tenv_destroy(&ud.tenv);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_rline.c
@@ -1,0 +1,46 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_rline *rnd;
+} UserData;
+
+int t_rline(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT freq;
+
+    UserData ud;
+    sp_srand(sp, 12345);
+    sp_ftbl_create(sp, &ud.ft, 1024);
+    sp_osc_create(&ud.osc);
+    sp_rline_create(&ud.rnd);
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_rline_init(sp, ud.rnd);
+
+    ud.rnd->min = 300;
+    ud.rnd->max = 3000;
+
+    for(n = 0; n < tst->size; n++) {
+        sp_rline_compute(sp, ud.rnd, NULL, &freq);
+        ud.osc->freq = freq;
+        sp_osc_compute(sp, ud.osc, NULL, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_rline_destroy(&ud.rnd);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_rpt.c
@@ -1,0 +1,75 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct{
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_metro *mt;
+    sp_tenv *te;
+    sp_rpt *rpt;
+    sp_maygate *mg;
+} UserData;
+
+int t_rpt(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    int tempo = 120;
+    SPFLOAT met, osc, env, rpt, maygate, trig, dry;
+
+    sp_srand(sp, 0);
+    sp_rpt_create(&ud.rpt);
+    sp_maygate_create(&ud.mg);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 4096);
+    sp_metro_create(&ud.mt);
+    sp_tenv_create(&ud.te);
+
+
+    sp_maygate_init(sp, ud.mg);
+    ud.mg->prob = 0.5;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_metro_init(sp, ud.mt);
+    ud.mt->freq = tempo / 60.0;
+    sp_rpt_init(sp, ud.rpt, 1.0);
+    ud.rpt->bpm = tempo;
+    ud.rpt->div = 8;
+    ud.rpt->rep = 4;
+    sp_tenv_init(sp, ud.te);
+    ud.te->atk = 0.001;
+    ud.te->hold = 0.1;
+    ud.te->rel =  0.1;
+
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        sp_metro_compute(sp, ud.mt, NULL, &met);
+        sp_tenv_compute(sp, ud.te, &met, &env);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        dry = osc * env;
+        sp_maygate_compute(sp, ud.mg, &met, &maygate);
+        trig = met * maygate;
+        sp_rpt_compute(sp, ud.rpt, &trig, &dry, &rpt);
+        sp_test_add_sample(tst, rpt);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    sp_maygate_destroy(&ud.mg);
+    sp_tenv_destroy(&ud.te);
+    sp_metro_destroy(&ud.mt);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_rpt_destroy(&ud.rpt);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_rspline.c
@@ -1,0 +1,51 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_rspline *rspline;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_rspline(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc, rspline;
+
+    UserData ud;
+    sp_srand(sp, 1234567);
+
+    sp_rspline_create(&ud.rspline);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_rspline_init(sp, ud.rspline);
+    ud.rspline->min = 300;
+    ud.rspline->max = 900;
+    ud.rspline->cps_min = 0.1;
+    ud.rspline->cps_max = 3;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        osc = 0;
+        rspline = 0;
+        sp_rspline_compute(sp, ud.rspline, NULL, &rspline);
+        ud.osc->freq = rspline;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, osc);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_rspline_destroy(&ud.rspline);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_samphold.c
@@ -1,0 +1,59 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_samphold *samphold;
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_metro *met;
+    sp_noise *noise;
+} UserData;
+
+int t_samphold(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 1234567);
+    UserData ud;
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, samphold = 0, met = 0, noise = 0;
+
+    sp_samphold_create(&ud.samphold);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_metro_create(&ud.met);
+    sp_noise_create(&ud.noise);
+
+    sp_samphold_init(sp, ud.samphold);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 5;
+    sp_noise_init(sp, ud.noise);
+    ud.noise->amp = 1;
+    sp->len = 44100 * 5;
+
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, samphold = 0, met = 0, noise = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_noise_compute(sp, ud.noise, NULL, &noise);
+        sp_samphold_compute(sp, ud.samphold, &met, &noise, &samphold);
+        ud.osc->freq = 200 + (samphold + 1) * 300;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_samphold_destroy(&ud.samphold);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_metro_destroy(&ud.met);
+    sp_noise_destroy(&ud.noise);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_saturator.c
@@ -1,0 +1,46 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_saturator *saturator;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_saturator(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 12345);
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+        SPFLOAT osc = 0, saturator = 0;
+
+    sp_saturator_create(&ud.saturator);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_saturator_init(sp, ud.saturator);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.5;
+    ud.saturator->dcoffset = 4;
+    ud.saturator->drive = 20;
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_saturator_compute(sp, ud.saturator, &osc, &saturator);
+        sp_test_add_sample(tst, saturator);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_saturator_destroy(&ud.saturator);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_scale.c
@@ -1,0 +1,52 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_scale *scale;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_scale(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT val = 1;
+    SPFLOAT osc = 0, scale = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_scale_create(&ud.scale);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_scale_init(sp, ud.scale);
+    ud.scale->min = 0;
+    ud.scale->max = 880;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.1;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, scale = 0;
+        /* constant set to 1, when scaled, it becomes 440 */
+        val = 1;
+        sp_scale_compute(sp, ud.scale, &val, &scale);
+        ud.osc->freq = scale;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_scale_destroy(&ud.scale);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_sdelay.c
@@ -1,0 +1,66 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_sdelay *sdelay;
+    sp_lpf18 *filt1;
+    sp_lpf18 *filt2;
+    sp_metro *met;
+} UserData;
+
+int t_sdelay(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT met = 0, sdelay = 0;
+    SPFLOAT filt1 = 0, filt2 = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_sdelay_create(&ud.sdelay);
+    sp_metro_create(&ud.met);
+    sp_lpf18_create(&ud.filt1);
+    sp_lpf18_create(&ud.filt2);
+
+    sp_sdelay_init(sp, ud.sdelay, 2000);
+    sp_metro_init(sp, ud.met);
+
+    ud.met->freq = 2;
+
+    sp_lpf18_init(sp, ud.filt1);
+    ud.filt1->cutoff = 4000;
+    ud.filt1->res = 0.8;
+
+    sp_lpf18_init(sp, ud.filt2);
+    ud.filt2->cutoff = 500;
+    ud.filt2->res = 0.8;
+
+    for(n = 0; n < tst->size; n++) {
+        met = 0;
+        sdelay = 0;
+        filt1 = 0;
+        filt2 = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_sdelay_compute(sp, ud.sdelay, &met, &sdelay);
+
+        sp_lpf18_compute(sp, ud.filt1, &met, &filt1);
+        sp_lpf18_compute(sp, ud.filt2, &sdelay, &filt2);
+
+        sp->out[0] = filt1 + filt2;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_sdelay_destroy(&ud.sdelay);
+    sp_metro_destroy(&ud.met);
+    sp_lpf18_destroy(&ud.filt1);
+    sp_lpf18_destroy(&ud.filt2);
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_slice.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_slice(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_smoothdelay.c
@@ -1,0 +1,66 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_smoothdelay *smoothdelay;
+    sp_osc *osc;
+    sp_metro *met;
+    sp_tenv *tenv;
+    sp_ftbl *ft;
+} UserData;
+
+
+int t_smoothdelay(sp_test *tst, sp_data *sp, const char *hash)
+{
+    sp_srand(sp, 0);
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, smoothdelay = 0, met = 0, tenv = 0;
+    UserData ud;
+
+    sp_smoothdelay_create(&ud.smoothdelay);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_metro_create(&ud.met);
+    sp_tenv_create(&ud.tenv);
+
+    sp_smoothdelay_init(sp, ud.smoothdelay, 0.75 * 0.5, 256);
+    ud.smoothdelay->del = 0.11;
+    ud.smoothdelay->feedback = 0.66;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.5;
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 1;
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.005;
+    ud.tenv->hold = 0.1;
+    ud.tenv->rel =  0.1;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, smoothdelay = 0, met = 0, tenv = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_tenv_compute(sp, ud.tenv, &met, &tenv);
+        if(met) {
+            ud.osc->freq = 100 + sp_rand(sp) % 500;
+        }
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        osc *= tenv;
+        sp_smoothdelay_compute(sp, ud.smoothdelay, &osc, &smoothdelay);
+
+        sp_test_add_sample(tst, osc + smoothdelay);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_metro_destroy(&ud.met);
+    sp_smoothdelay_destroy(&ud.smoothdelay);
+    sp_osc_destroy(&ud.osc);
+    sp_ftbl_destroy(&ud.ft);
+    sp_tenv_destroy(&ud.tenv);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_sndwarp.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_sndwarp(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_spa.c
@@ -1,0 +1,34 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_spa *spa;
+} UserData;
+
+int t_spa(sp_test *tst, sp_data *sp, const char *hash)
+{
+    UserData ud;
+    uint32_t n;
+    SPFLOAT spa;
+    int fail = 0;
+
+    sp_srand(sp, 1234567);
+    sp_spa_create(&ud.spa);
+    sp_spa_init(sp, ud.spa, SAMPDIR "oneart.spa");
+
+
+    for(n = 0; n < tst->size; n++) {
+        spa = 0;
+        sp_spa_compute(sp, ud.spa, NULL, &spa);
+        sp_test_add_sample(tst, spa);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_spa_destroy(&ud.spa);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_streson.c
@@ -1,0 +1,40 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_streson *stres;
+} UserData;
+
+int t_streson(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT noise = 0;
+
+    sp_srand(sp, 123456);
+    UserData ud;
+
+    sp_streson_create(&ud.stres);
+    sp_noise_create(&ud.ns);
+    sp_noise_init(sp, ud.ns);
+    sp_streson_init(sp, ud.stres);
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        noise = 0;
+        sp_noise_compute(sp, ud.ns, NULL, &noise);
+        sp_streson_compute(sp, ud.stres, &noise, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_streson_destroy(&ud.stres);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_switch.c
@@ -1,0 +1,63 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_switch *sw;
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_metro *met;
+    sp_osc *lfo;
+    sp_fosc *fosc;
+} UserData;
+
+int t_switch(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT osc = 0, sw = 0, met = 0, fosc = 0, lfo = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_switch_create(&ud.sw);
+    sp_osc_create(&ud.osc);
+    sp_osc_create(&ud.lfo);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_metro_create(&ud.met);
+    sp_fosc_create(&ud.fosc);
+
+    sp_switch_init(sp, ud.sw);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_osc_init(sp, ud.lfo, ud.ft, 0);
+    ud.lfo->amp = 100;
+    ud.lfo->freq = 6;
+    sp_fosc_init(sp, ud.fosc, ud.ft);
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 2.5;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0; sw = 0; met = 0; fosc = 0; lfo = 0;
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        ud.osc->freq = 550 + lfo;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_fosc_compute(sp, ud.fosc, NULL, &fosc);
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_switch_compute(sp, ud.sw, &met, &osc, &fosc, &sw);
+        sp_test_add_sample(tst, sw);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_switch_destroy(&ud.sw);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_osc_destroy(&ud.lfo);
+    sp_fosc_destroy(&ud.fosc);
+    sp_metro_destroy(&ud.met);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tabread.c
@@ -1,0 +1,57 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_tabread *tr;
+    sp_ftbl *ft;
+    sp_phasor *phasor;
+} UserData;
+
+int t_tabread(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT tab = 0.0, phasor = 0.0;
+
+    sp_srand(sp, 123456);
+    UserData ud;
+
+    sp_tabread_create(&ud.tr);
+
+    sp_phasor_create(&ud.phasor);
+
+    sp_ftbl_create(sp, &ud.ft, 395393);
+    sp_gen_file(sp, ud.ft, "oneart.wav");
+
+    sp_tabread_init(sp, ud.tr, ud.ft, 1);
+
+    /* since mode = 1, offset 5% into file */
+    ud.tr->offset = 0.05;
+    /* no wraparound */
+    ud.tr->wrap = 0;
+
+    sp_phasor_init(sp, ud.phasor, 0);
+    /* set playback rate to half speed, or 1/(t * 2) */
+    ud.phasor->freq = 1 / (8.97 * 2);
+    sp->len = 44100 * 5;
+
+
+    for(n = 0; n < tst->size; n++) {
+        tab = 0.0; phasor = 0.0;
+        sp_phasor_compute(sp, ud.phasor, NULL, &phasor);
+        ud.tr->index = phasor;
+        sp_tabread_compute(sp, ud.tr, NULL, &tab);
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_phasor_destroy(&ud.phasor);
+    sp_tabread_destroy(&ud.tr);
+    sp_ftbl_destroy(&ud.ft);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tadsr.c
@@ -1,0 +1,48 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_tadsr *tadsr;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_tadsr(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+    SPFLOAT osc = 0, tadsr = 0, trig = 0;
+
+    sp_tadsr_create(&ud.tadsr);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_tadsr_init(sp, ud.tadsr);
+    ud.tadsr->atk = 0.1;
+    ud.tadsr->dec = 0.2;
+    ud.tadsr->sus = 0.3;
+    ud.tadsr->rel = 0.1;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    for(n = 0; n < tst->size; n++) {
+        osc = 0; tadsr = 0; trig = 0;
+        if(n == 0 || n == sp->sr * 2) trig = 1;
+        sp_tadsr_compute(sp, ud.tadsr, &trig, &tadsr);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tadsr_destroy(&ud.tadsr);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_talkbox.c
@@ -1,0 +1,76 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+#define NOSC 5
+
+typedef struct {
+    sp_talkbox *talkbox;
+    sp_blsaw *saw[NOSC];
+    sp_diskin *diskin;
+} UserData;
+
+static int chord[] = {48, 51, 55, 60, 70};
+
+static SPFLOAT process(sp_data *sp, void *udata) {
+    UserData *ud = udata;
+    SPFLOAT tmp;
+    int i;
+    SPFLOAT src = 0;
+    SPFLOAT exc = 0;
+    SPFLOAT talkbox = 0;
+
+    exc = 0;
+    for(i = 0; i < NOSC; i++) {
+		sp_blsaw_compute(sp, ud->saw[i], NULL, &tmp);
+		exc += tmp;
+    }
+    sp_diskin_compute(sp, ud->diskin, NULL, &src);
+    src *= 0.5;
+    sp_talkbox_compute(sp, ud->talkbox, &src, &exc, &talkbox);
+    return talkbox;
+}
+
+int t_talkbox(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    UserData ud;
+    int fail = 0;
+    int i;
+    SPFLOAT tmp;
+
+    /* allocate / initialize modules here */
+    sp_srand(sp, 1234567);
+
+    sp_diskin_create(&ud.diskin);
+	sp_talkbox_create(&ud.talkbox);
+	sp_talkbox_init(sp, ud.talkbox);
+	ud.talkbox->quality = 0.2;
+
+	for(i = 0; i < NOSC; i++) {
+		sp_blsaw_create(&ud.saw[i]);
+		sp_blsaw_init(sp, ud.saw[i]);
+		*ud.saw[i]->freq = sp_midi2cps(chord[i]);
+		*ud.saw[i]->amp = 0.1;
+    }
+
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+
+
+    for(n = 0; n < tst->size; n++) {
+    	tmp = process(sp, &ud);
+        sp_test_add_sample(tst, tmp);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_talkbox_destroy(&ud.talkbox);
+    for(i = 0; i < NOSC; i ++) {
+		sp_blsaw_destroy(&ud.saw[i]);
+    }
+    sp_diskin_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tblrec.c
@@ -1,0 +1,70 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_tblrec *tblrec;
+    sp_ftbl *ft;
+    sp_metro *met;
+    sp_pluck *plk;
+    sp_randi *randi;
+    sp_tabread *tr;
+} UserData;
+
+int t_tblrec(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT trig, pluck, rand, tr, tblrec;
+    SPFLOAT tick = (sp->pos == 0 ? 1 : 0);
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_tblrec_create(&ud.tblrec);
+    sp_ftbl_create(sp, &ud.ft, sp->sr * 0.5);
+
+    sp_metro_create(&ud.met);
+    sp_pluck_create(&ud.plk);
+    sp_randi_create(&ud.randi);
+    sp_tabread_create(&ud.tr);
+
+    sp_tblrec_init(sp, ud.tblrec, ud.ft);
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 2.5;
+    sp_pluck_init(sp, ud.plk, 110);
+    ud.plk->freq = 440;
+    sp_randi_init(sp, ud.randi);
+    sp_tabread_init(sp, ud.tr, ud.ft, 1);
+
+    for(n = 0; n < tst->size; n++) {
+        trig = 0;
+        pluck = 0;
+        rand = 0;
+        tr = 0;
+        tick = (n == 0 ? 1 : 0);
+        tblrec = 0;
+        sp_metro_compute(sp, ud.met, NULL, &trig);
+        sp_pluck_compute(sp, ud.plk, &trig, &pluck);
+        sp_tblrec_compute(sp, ud.tblrec, &pluck, &tick, &tblrec);
+        sp_randi_compute(sp, ud.randi, NULL, &rand);
+        ud.tr->index = rand;
+        sp_tabread_compute(sp, ud.tr, NULL, &tr);
+        sp_test_add_sample(tst, tr);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tblrec_destroy(&ud.tblrec);
+    sp_ftbl_destroy(&ud.ft);
+    sp_metro_destroy(&ud.met);
+    sp_pluck_destroy(&ud.plk);
+    sp_randi_destroy(&ud.randi);
+    sp_tabread_destroy(&ud.tr);
+
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tbvcf.c
@@ -1,0 +1,41 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+
+typedef struct {
+    sp_noise *ns;
+    sp_tbvcf *tn;
+} UserData;
+
+int t_tbvcf(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    sp_srand(sp, 0);
+    UserData ud;
+    sp_noise_create(&ud.ns);
+    sp_tbvcf_create(&ud.tn);
+    sp_noise_init(sp, ud.ns);
+    sp_tbvcf_init(sp, ud.tn);
+    ud.tn->dist = 1.0;
+    SPFLOAT in = 0;
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_tbvcf_compute(sp, ud.tn, &in, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_noise_destroy(&ud.ns);
+    sp_tbvcf_destroy(&ud.tn);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tdiv.c
@@ -1,0 +1,91 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc1;
+    sp_osc *osc2;
+    sp_ftbl *ft;
+    sp_metro *met;
+    sp_tenv *tenv1;
+    sp_tenv *tenv2;
+    sp_tdiv *tdiv;
+} UserData;
+
+int t_tdiv(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    SPFLOAT trig = 0;
+    SPFLOAT div  = 0;
+    SPFLOAT env1 = 0;
+    SPFLOAT env2 = 0;
+    SPFLOAT osc1 = 0;
+    SPFLOAT osc2 = 0;
+
+    UserData ud;
+    sp_srand(sp, 123456);
+
+    sp_tenv_create(&ud.tenv1);
+    sp_tenv_create(&ud.tenv2);
+    sp_metro_create(&ud.met);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_osc_create(&ud.osc1);
+    sp_osc_create(&ud.osc2);
+    sp_tdiv_create(&ud.tdiv);
+
+    sp_tenv_init(sp, ud.tenv1);
+    ud.tenv1->atk = 0.03;
+    ud.tenv1->hold = 0.01;
+    ud.tenv1->rel = 0.1;
+
+    sp_tenv_init(sp, ud.tenv2);
+    ud.tenv2->atk = 0.03;
+    ud.tenv2->hold = 0.01;
+    ud.tenv2->rel = 0.1;
+
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 3;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc1, ud.ft, 0);
+    ud.osc1->freq = 400;
+    sp_osc_init(sp, ud.osc2, ud.ft, 0);
+    ud.osc2->freq = 800;
+
+    sp_tdiv_init(sp, ud.tdiv);
+    ud.tdiv->num = 3;
+
+    for(n = 0; n < tst->size; n++) {
+        trig = 0;
+        div  = 0;
+        env1 = 0;
+        env2 = 0;
+        osc1 = 0;
+        osc2 = 0;
+        sp_metro_compute(sp, ud.met, NULL, &trig);
+        sp_tdiv_compute(sp, ud.tdiv, &trig, &div);
+        sp_osc_compute(sp, ud.osc1, NULL, &osc1);
+        sp_osc_compute(sp, ud.osc2, NULL, &osc2);
+
+        sp_tenv_compute(sp, ud.tenv1, &trig, &env1);
+        sp_tenv_compute(sp, ud.tenv2, &div, &env2);
+
+        sp->out[0] = (osc1 * env1) + (osc2 * env2);
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tenv_destroy(&ud.tenv1);
+    sp_tenv_destroy(&ud.tenv2);
+    sp_metro_destroy(&ud.met);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc1);
+    sp_osc_destroy(&ud.osc2);
+    sp_tdiv_destroy(&ud.tdiv);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tenv.c
@@ -1,0 +1,57 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_metro *met;
+    sp_tenv *tenv;
+    SPFLOAT freq;
+} UserData;
+
+int t_tenv(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    sp_srand(sp, 123456);
+
+    sp_tenv_create(&ud.tenv);
+    sp_metro_create(&ud.met);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_osc_create(&ud.osc);
+
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.03;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel = 0.1;
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 3;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    for(n = 0; n < tst->size; n++) {
+        SPFLOAT trig = 0;
+        SPFLOAT env = 0;
+        SPFLOAT osc = 0;
+        sp_metro_compute(sp, ud.met, NULL, &trig);
+        if(trig) ud.osc->freq = 500 + sp_rand(sp) % 2000;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_tenv_compute(sp, ud.tenv, &trig, &env);
+        sp->out[0] = osc * env;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tenv_destroy(&ud.tenv);
+    sp_metro_destroy(&ud.met);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tenv2.c
@@ -1,0 +1,50 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_tenv2 *tenv2;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_tenv2(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    sp_srand(sp, 1234567);
+    UserData ud;
+    SPFLOAT osc = 0, tenv2 = 0, tick = 0;
+
+    sp_tenv2_create(&ud.tenv2);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_tenv2_init(sp, ud.tenv2);
+    ud.tenv2->atk = 3;
+    ud.tenv2->rel = 1;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.6;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0, tenv2 = 0, tick = 0;
+
+        if(sp->pos == 0 || sp->pos == sp->sr * 1) tick = 1;
+
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_tenv2_compute(sp, ud.tenv2, &tick, &tenv2);
+        sp->out[0] = osc * tenv2;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tenv2_destroy(&ud.tenv2);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tenvx.c
@@ -1,0 +1,60 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_metro *met;
+    sp_tenvx *tenvx;
+    SPFLOAT freq;
+} UserData;
+
+int t_tenvx(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    SPFLOAT *freqp = &ud.freq;
+    ud.freq = 400;
+    sp_srand(sp, 123456);
+
+    sp_tenvx_create(&ud.tenvx);
+    sp_metro_create(&ud.met);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_osc_create(&ud.osc);
+
+    sp_tenvx_init(sp, ud.tenvx);
+    ud.tenvx->atk = 0.03;
+    ud.tenvx->hold = 0.1;
+    ud.tenvx->rel = 0.1;
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 3;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 0.5;
+    ud.osc->freq = *freqp;
+
+    for(n = 0; n < tst->size; n++) {
+        SPFLOAT trig = 0;
+        SPFLOAT env = 0;
+        SPFLOAT osc = 0;
+        sp_metro_compute(sp, ud.met, NULL, &trig);
+        if(trig) ud.osc->freq = 500 + sp_rand(sp) % 2000;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_tenvx_compute(sp, ud.tenvx, &trig, &env);
+        sp_test_add_sample(tst, osc * env);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tenvx_destroy(&ud.tenvx);
+    sp_metro_destroy(&ud.met);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tgate.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_tgate(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_thresh.c
@@ -1,0 +1,61 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_thresh *thresh;
+    sp_osc *osc, *lfo;
+    sp_ftbl *ft;
+    sp_tenv *tenv;
+} UserData;
+
+int t_thresh(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+    SPFLOAT osc = 0, thresh = 0, lfo = 0, tenv = 0;
+
+    sp_thresh_create(&ud.thresh);
+    sp_osc_create(&ud.osc);
+    sp_osc_create(&ud.lfo);
+    sp_tenv_create(&ud.tenv);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_thresh_init(sp, ud.thresh);
+    ud.thresh->mode = 1;
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    sp_osc_init(sp, ud.lfo, ud.ft, 0);
+    ud.lfo->freq = 3;
+    ud.lfo->amp = 1;
+
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.01;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel = 0.01;
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0; thresh = 0; lfo = 0; tenv = 0;
+        sp_osc_compute(sp, ud.lfo, NULL, &lfo);
+        sp_thresh_compute(sp, ud.thresh, &lfo, &thresh);
+        sp_tenv_compute(sp, ud.tenv, &thresh, &tenv);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, osc * tenv);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_thresh_destroy(&ud.thresh);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_osc_destroy(&ud.lfo);
+    sp_tenv_destroy(&ud.tenv);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_timer.c
@@ -1,0 +1,64 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_timer *timer;
+    sp_osc *osc;
+    sp_ftbl *ft;
+    sp_tenv *tenv;
+    sp_dmetro *dmetro;
+} UserData;
+
+int t_timer(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    SPFLOAT osc = 0, timer = 0, clock = 0, tenv = 0;
+    sp_srand(sp, 1234567);
+
+    UserData ud;
+
+    sp_timer_create(&ud.timer);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_tenv_create(&ud.tenv);
+    sp_dmetro_create(&ud.dmetro);
+
+    sp_timer_init(sp, ud.timer);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.1;
+    ud.tenv->hold= 0.1;
+    ud.tenv->rel = 0.1;
+    sp_dmetro_init(sp, ud.dmetro);
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0; timer = 0; clock = 0; tenv = 0;
+
+        if(sp->pos % 20000 == 0) {
+            clock = 1;
+        }
+        sp_timer_compute(sp, ud.timer, &clock, &timer);
+        ud.dmetro->time = timer;
+        sp_dmetro_compute(sp, ud.dmetro, NULL, &timer);
+        sp_tenv_compute(sp, ud.tenv, &timer, &tenv);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc * tenv;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_timer_destroy(&ud.timer);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_tenv_destroy(&ud.tenv);
+    sp_dmetro_destroy(&ud.dmetro);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tone.c
@@ -1,0 +1,37 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_noise *ns;
+    sp_tone *tn;
+} UserData;
+
+int t_tone(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    sp_noise_create(&ud.ns);
+    sp_tone_create(&ud.tn);
+    sp_noise_init(sp, ud.ns);
+    sp_tone_init(sp, ud.tn);
+
+    SPFLOAT in;
+
+    for(n = 0; n < tst->size; n++) {
+        sp_noise_compute(sp, ud.ns, NULL, &in);
+        sp_tone_compute(sp, ud.tn, &in, &sp->out[0]);
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tone_destroy(&ud.tn);
+    sp_noise_destroy(&ud.ns);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_trand.c
@@ -1,0 +1,56 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_trand *trand;
+    sp_metro *met;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_trand(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    UserData ud;
+    sp_srand(sp, 1234567);
+
+    sp_metro_create(&ud.met);
+    sp_trand_create(&ud.trand);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_metro_init(sp, ud.met);
+    ud.met->freq = 20;
+    sp_trand_init(sp, ud.trand);
+    ud.trand->min = 40;
+    ud.trand->max = 1000;
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    sp->len = 44100 * 5;
+
+    for(n = 0; n < tst->size; n++) {
+        SPFLOAT osc = 0, trand = 0, met = 0;
+        sp_metro_compute(sp, ud.met, NULL, &met);
+        sp_trand_compute(sp, ud.trand, &met, &trand);
+        ud.osc->freq = trand;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+    sp_trand_destroy(&ud.trand);
+    sp_metro_destroy(&ud.met);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tseg.c
@@ -1,0 +1,51 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_tseg *tseg;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_tseg(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    sp_srand(sp, 1234567);
+    UserData ud;
+    SPFLOAT osc = 0, tseg = 0;
+    SPFLOAT trig = (sp->pos == 0);
+
+    sp_tseg_create(&ud.tseg);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_tseg_init(sp, ud.tseg, 0.0001);
+    ud.tseg->end = 1.0;
+    ud.tseg->type = 3.0;
+    ud.tseg->dur = 4.0;
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+
+    for(n = 0; n < tst->size; n++) {
+        osc = 0;
+        tseg = 0;
+        trig = (sp->pos == 0);
+        sp_tseg_compute(sp, ud.tseg, &trig, &tseg);
+        ud.osc->freq = 100 + (tseg * 1000);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_test_add_sample(tst, osc);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_tseg_destroy(&ud.tseg);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_tseq.c
@@ -1,0 +1,83 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc;
+    sp_ftbl *ft, *delta, *nn;
+    sp_tenv *tenv;
+    sp_dtrig *dt;
+    sp_tseq *seq;
+} UserData;
+
+int t_tseq(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT env = 0;
+    SPFLOAT osc = 0;
+    SPFLOAT trig;
+    SPFLOAT dtrig = 0;
+    SPFLOAT note = 0;
+
+    sp_srand(sp, 123456);
+    UserData ud;
+    sp_dtrig_create(&ud.dt);
+    sp_tenv_create(&ud.tenv);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+    sp_ftbl_create(sp, &ud.delta, 4);
+    sp_ftbl_create(sp, &ud.nn, 1);
+    sp_osc_create(&ud.osc);
+
+    sp_gen_vals(sp, ud.delta, "0.2 0.2 0.2 0.1");
+    sp_gen_vals(sp, ud.nn, "60 62 64 67");
+    sp_tseq_create(&ud.seq);
+    sp_tseq_init(sp, ud.seq, ud.nn);
+
+    sp_dtrig_init(sp, ud.dt, ud.delta);
+    ud.dt->loop = 1.0;
+    sp_tenv_init(sp, ud.tenv);
+    ud.tenv->atk = 0.01;
+    ud.tenv->hold = 0.01;
+    ud.tenv->rel =  0.05;
+
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->freq = 1000;
+    ud.osc->amp = 0.5;
+
+
+    for(n = 0; n < tst->size; n++) {
+        env = 0;
+        osc = 0;
+        dtrig = 0;
+        note = 0;
+        if(sp->pos == 0){
+            trig = 1.0;
+        }else{
+            trig = 0.0;
+        }
+        sp_dtrig_compute(sp, ud.dt, &trig, &dtrig);
+        sp_tseq_compute(sp, ud.seq, &dtrig, &note);
+        ud.osc->freq = sp_midi2cps(note + 24);
+        env = 1.0;
+        sp_tenv_compute(sp, ud.tenv, &dtrig, &env);
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp->out[0] = osc * env;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_dtrig_destroy(&ud.dt);
+    sp_tseq_destroy(&ud.seq);
+    sp_tenv_destroy(&ud.tenv);
+    sp_ftbl_destroy(&ud.ft);
+    sp_ftbl_destroy(&ud.nn);
+    sp_ftbl_destroy(&ud.delta);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_vardelay.c
@@ -1,0 +1,54 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_osc *osc, *lfo;
+    sp_ftbl *sine;
+    sp_vardelay *del;
+} UserData;
+
+int t_vardelay(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    UserData ud;
+    SPFLOAT freq = 0.0, del = 0.0, osc = 0.0;
+
+    sp_vardelay_create(&ud.del);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.sine, 4096);
+    sp_osc_create(&ud.lfo);
+
+    sp_vardelay_init(sp, ud.del, 0.5);
+    sp_gen_sine(sp, ud.sine);
+
+    sp_osc_init(sp, ud.osc, ud.sine, 0);
+    ud.osc->freq = sp_midi2cps(50);
+
+    sp_osc_init(sp, ud.lfo, ud.sine, 0);
+    ud.lfo->freq = 0.2;
+
+    for(n = 0; n < tst->size; n++) {
+        freq = 0.0, del = 0.0, osc = 0.0;
+        sp_osc_compute(sp, ud.lfo, NULL, &freq);
+        freq = 1.0 + (freq * 0.5);
+        freq = 0.02 + (freq * 0.02);
+        ud.del->del = freq;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        sp_vardelay_compute(sp, ud.del, &osc, &del);
+        sp->out[0] = del * 0.5 + osc * 0.5;
+        sp_test_add_sample(tst, sp->out[0]);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_vardelay_destroy(&ud.del);
+    sp_ftbl_destroy(&ud.sine);
+    sp_osc_destroy(&ud.osc);
+    sp_osc_destroy(&ud.lfo);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_voc.c
@@ -1,0 +1,52 @@
+
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_voc *voc;
+    sp_osc *osc;
+    sp_ftbl *ft;
+} UserData;
+
+int t_voc(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    UserData ud;
+
+    int fail = 0;
+    SPFLOAT osc, voc;
+    sp_srand(sp, 0);
+    sp_voc_create(&ud.voc);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    sp_voc_init(sp, ud.voc);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft, 0);
+    ud.osc->amp = 1;
+    ud.osc->freq = 0.1;
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        osc = 0;
+        voc = 0;
+        sp_osc_compute(sp, ud.osc, NULL, &osc);
+        if(sp_voc_get_counter(ud.voc) == 0) {
+            osc = 12 + 16 * (0.5 * (osc + 1));
+            sp_voc_set_tongue_shape(ud.voc, osc, 2.9);
+        }
+        sp_voc_compute(sp, ud.voc, &voc);
+        sp_test_add_sample(tst, voc);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_voc_destroy(&ud.voc);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_vocoder.c
@@ -1,0 +1,64 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_vocoder *vocoder;
+    sp_blsaw *saw[3];
+    sp_spa *diskin;
+} UserData;
+
+int t_vocoder(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT diskin = 0, vocoder = 0, saw = 0, tmp = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    int i;
+
+    int scale[] = {58, 65, 72};
+
+    sp_vocoder_create(&ud.vocoder);
+    sp_vocoder_init(sp, ud.vocoder);
+
+    sp_spa_create(&ud.diskin);
+    sp_spa_init(sp, ud.diskin, SAMPDIR "oneart.spa");
+
+    for(i = 0; i < 3; i++) {
+        sp_blsaw_create(&ud.saw[i]);
+        sp_blsaw_init(sp, ud.saw[i]);
+        *ud.saw[i]->freq = sp_midi2cps(scale[i]);
+    }
+
+    for(n = 0; n < tst->size; n++) {
+        diskin = 0;
+        vocoder = 0;
+        saw = 0;
+        tmp = 0;
+        sp_spa_compute(sp, ud.diskin, NULL, &diskin);
+        for(i = 0; i < 3; i++) {
+            sp_blsaw_compute(sp, ud.saw[i], NULL, &tmp);
+            saw += tmp;
+        }
+        saw *= 0.2;
+        sp_vocoder_compute(sp, ud.vocoder, &diskin, &saw, &vocoder);
+        sp_test_add_sample(tst, vocoder);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_vocoder_destroy(&ud.vocoder);
+
+    for(i = 0; i < 3; i++) {
+        sp_blsaw_destroy(&ud.saw[i]);
+    }
+
+    sp_spa_destroy(&ud.diskin);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_waveset.c
@@ -1,0 +1,40 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_waveset *waveset;
+    sp_diskin *diskin;
+} UserData;
+
+int t_waveset(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT wav = 0, waveset = 0;
+
+    UserData ud;
+    sp_srand(sp, 1234567);
+
+    sp_waveset_create(&ud.waveset);
+    sp_diskin_create(&ud.diskin);
+
+    sp_waveset_init(sp, ud.waveset, 1.0);
+    ud.waveset->rep = 3.0;
+    sp_diskin_init(sp, ud.diskin, SAMPDIR "oneart.wav");
+
+    for(n = 0; n < tst->size; n++) {
+        wav = 0; waveset = 0;
+        sp_diskin_compute(sp, ud.diskin, NULL, &wav);
+        sp_waveset_compute(sp, ud.waveset, &wav, &waveset);
+        sp_test_add_sample(tst, waveset);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_waveset_destroy(&ud.waveset);
+    sp_diskin_destroy(&ud.diskin);
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_wavin.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_wavin(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_wavout.c
@@ -1,0 +1,25 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+int t_wavout(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    /* allocate / initialize modules here */
+
+    for(n = 0; n < tst->size; n++) {
+        /* compute samples and add to test buffer */
+        sp_test_add_sample(tst, 0);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    /* destroy functions here */
+
+    if(fail) return SP_NOT_OK;
+    /* fail by default */
+    else return SP_NOT_OK;
+}
--- /dev/null
+++ b/test/t/t_wpkorg35.c
@@ -1,0 +1,53 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_wpkorg35 *wpkorg35;
+    sp_noise *noise;
+    sp_randi *randi;
+} UserData;
+
+int t_wpkorg35(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+    SPFLOAT noise = 0, wpkorg35 = 0, randi = 0;
+
+    sp_srand(sp, 1234567);
+    UserData ud;
+
+    sp_wpkorg35_create(&ud.wpkorg35);
+    sp_noise_create(&ud.noise);
+    sp_randi_create(&ud.randi);
+
+    sp_wpkorg35_init(sp, ud.wpkorg35);
+    ud.wpkorg35->res = 1.99;
+    sp_noise_init(sp, ud.noise);
+    ud.noise->amp = 0.01;
+    sp_randi_init(sp, ud.randi);
+    ud.randi->min = 100;
+    ud.randi->max = 3000;
+    ud.randi->cps = 10;
+
+    for(n = 0; n < tst->size; n++) {
+        noise = 0;
+        wpkorg35 = 0;
+        randi = 0;
+        sp_randi_compute(sp, ud.randi, NULL, &randi);
+        sp_noise_compute(sp, ud.noise, NULL, &noise);
+        ud.wpkorg35->cutoff = randi;
+        sp_wpkorg35_compute(sp, ud.wpkorg35, &noise, &wpkorg35);
+        sp_test_add_sample(tst, wpkorg35);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_wpkorg35_destroy(&ud.wpkorg35);
+    sp_noise_destroy(&ud.noise);
+    sp_randi_destroy(&ud.randi);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/t/t_zitarev.c
@@ -1,0 +1,49 @@
+#include "soundpipe.h"
+#include "md5.h"
+#include "tap.h"
+#include "test.h"
+
+typedef struct {
+    sp_diskin *disk;
+    sp_zitarev *rev;
+    int counter;
+} UserData;
+
+int t_zitarev(sp_test *tst, sp_data *sp, const char *hash)
+{
+    uint32_t n;
+    int fail = 0;
+
+    SPFLOAT in = 0;
+    SPFLOAT out = 0;
+    SPFLOAT foo = 0;
+
+    sp_srand(sp,12345);
+    UserData ud;
+    ud.counter = 0;
+    sp_diskin_create(&ud.disk);
+    sp_zitarev_create(&ud.rev);
+
+    sp_diskin_init(sp, ud.disk, SAMPDIR "oneart.wav");
+    sp_zitarev_init(sp, ud.rev);
+    *ud.rev->level = 0;
+    *ud.rev->in_delay = 20;
+
+    for(n = 0; n < tst->size; n++) {
+        in = 0;
+        out = 0;
+        foo = 0;
+
+        sp_diskin_compute(sp, ud.disk, NULL, &in);
+        sp_zitarev_compute(sp, ud.rev, &in, &in, &out, &foo);
+        sp_test_add_sample(tst, out);
+    }
+
+    fail = sp_test_verify(tst, hash);
+
+    sp_diskin_destroy(&ud.disk);
+    sp_zitarev_destroy(&ud.rev);
+
+    if(fail) return SP_NOT_OK;
+    else return SP_OK;
+}
--- /dev/null
+++ b/test/tap.h
@@ -1,0 +1,12 @@
+/*
+ * Copyright (c) 2013, 2014, Louis P. Santillan <lpsantil@gmail.com>
+ * All rights reserved.
+ */
+#ifndef TAP_H
+#define TAP_H
+
+void plan( unsigned int num );
+
+unsigned int ok( unsigned int ok, const char* msg );
+
+#endif
--- /dev/null
+++ b/test/test.c
@@ -1,0 +1,98 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "soundpipe.h"
+#include "md5.h"
+#include "test.h"
+
+
+int sp_test_create(sp_test **t, uint32_t bufsize)
+{
+    uint32_t i;
+    *t = malloc(sizeof(sp_test));
+    sp_test *tp = *t;
+
+    SPFLOAT *buf = malloc(sizeof(SPFLOAT) * bufsize);
+    for(i = 0; i < bufsize; i++) tp->buf = 0;
+
+    tp->buf = buf;
+    tp->size = bufsize;
+    tp->pos = 0;
+    md5_init(&tp->state);
+    tp->md5string[32] = '\0';
+    tp->md5 = tp->md5string;
+    tp->mode = NORMAL;
+    return SP_OK;
+}
+
+int sp_test_destroy(sp_test **t)
+{
+    sp_test *tp = *t;
+    free(tp->buf);
+    free(*t);
+    return SP_OK;
+}
+
+int sp_test_add_sample(sp_test *t, SPFLOAT sample)
+{
+    if(t->pos < t->size) {
+        t->buf[t->pos] = sample;
+        t->pos++;
+    }
+    return SP_OK;
+}
+
+int sp_test_compare(sp_test *t, const char *md5hash)
+{
+    md5_append(&t->state, (const md5_byte_t *)t->buf, sizeof(SPFLOAT) * t->size);
+    md5_finish(&t->state, t->digest);
+    int i;
+    char in[3], out[3];
+    int fail = 0;
+    for(i = 0; i < 16; i++) {
+        in[0] = md5hash[2 * i];
+        in[1] = md5hash[2 * i + 1];
+        in[2] = '\0';
+        sprintf(out, "%02x", t->digest[i]);
+        t->md5string[2 * i] = out[0];
+        t->md5string[2 * i + 1] = out[1];
+        if(strcmp(in, out)) {
+            fail = 1;
+        }
+    }
+
+    if(fail) {
+        return SP_NOT_OK;
+    } else {
+        return SP_OK;
+    }
+}
+
+int sp_test_write_raw(sp_test *t, uint32_t index)
+{
+    char fname[20];
+    sprintf(fname, "%04d.raw", index);
+    FILE *fp = fopen(fname, "wb");
+    fwrite(t->buf, sizeof(SPFLOAT), t->size, fp);
+    fclose(fp);
+    return SP_OK;
+}
+
+int sp_test_verify(sp_test *t, const char *refhash)
+{
+    if(t->mode == NORMAL) {
+        int fail = 0;
+        if(sp_test_compare(t, refhash) == SP_NOT_OK) {
+            printf("Generated hash %s does not match reference hash %s\n",
+                    t->md5string, refhash);
+            fail = 1;
+        }
+        return fail;
+    } else {
+        sp_test_entry *tst = t->cur_entry;
+        sp_test_compare(t, refhash);
+        printf("TEST(t_%s, \"%s\", \"%s\")\n",
+                tst->desc, tst->desc, t->md5string);
+        return 0;
+    }
+}
--- /dev/null
+++ b/test/test.h
@@ -1,0 +1,34 @@
+#ifndef SAMPDIR
+#define SAMPDIR "../examples/"
+#endif
+
+enum {
+NORMAL,
+HEADER
+};
+typedef struct {
+    SPFLOAT *buf;
+    uint32_t size;
+    uint32_t pos;
+    md5_state_t state;
+    md5_byte_t digest[16];
+    char md5string[33];
+    char *md5;
+    int mode;
+    struct sp_test_entry *cur_entry;
+} sp_test;
+
+typedef struct sp_test_entry {
+    int (* func)(sp_test *, sp_data *, const char*);
+    const char *desc;
+    const char *hash;
+} sp_test_entry;
+
+int sp_test_create(sp_test **t, uint32_t bufsize);
+int sp_test_destroy(sp_test **t);
+int sp_test_add_sample(sp_test *t, SPFLOAT sample);
+/* Compares buffer with reference hash */
+int sp_test_compare(sp_test *t, const char *md5hash);
+/* verify wraps compare and error message up together */
+int sp_test_verify(sp_test *t, const char *refhash);
+int sp_test_write_raw(sp_test *t, uint32_t index);
--- /dev/null
+++ b/test/write_wav.sh
@@ -1,0 +1,15 @@
+#/bin/sh
+
+# This utility is a wrapper around sox which converts 32-bit LE raw data into a 
+# mono 44.1 kHz wav.
+
+if [ "$#" -eq 0 ]
+then
+    echo "./write_wave.sh filename.raw"
+    exit
+fi
+
+sox -t raw -c 1 -r 44100 -e floating-point -b 32 $1 out.wav
+
+echo "converted $1 to out.wav"
+
--- /dev/null
+++ b/util/css/normalize.css
@@ -1,0 +1,427 @@
+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
+ *    user zoom.
+ */
+
+html {
+  font-family: sans-serif; /* 1 */
+  -ms-text-size-adjust: 100%; /* 2 */
+  -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+  margin: 0;
+}
+
+/* HTML5 display definitions
+   ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+  display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+  display: inline-block; /* 1 */
+  vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+  display: none;
+  height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+  display: none;
+}
+
+/* Links
+   ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+  background-color: transparent;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+  outline: 0;
+}
+
+/* Text-level semantics
+   ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+  border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b,
+strong {
+  font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+  font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+/*
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+*/
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+  background: #ff0;
+  color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+  font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sup {
+  top: -0.5em;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+/* Embedded content
+   ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+
+img {
+  border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+  overflow: hidden;
+}
+
+/* Grouping content
+   ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+  margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+  -moz-box-sizing: content-box;
+  box-sizing: content-box;
+  height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+  overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code,
+kbd,
+pre,
+samp {
+  font-family: monospace, monospace;
+  font-size: 1em;
+}
+
+/* Forms
+   ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ *    Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  color: inherit; /* 1 */
+  font: inherit; /* 2 */
+  margin: 0; /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+  overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+  text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ *    and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ *    `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+  -webkit-appearance: button; /* 2 */
+  cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+  cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+  border: 0;
+  padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+  line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+  box-sizing: border-box; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
+ * `font-size` values of the `input`, it causes the cursor style of the
+ * decrement button to change from `default` to `text`.
+ */
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
+ *    (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+  -webkit-appearance: textfield; /* 1 */
+  -moz-box-sizing: content-box;
+  -webkit-box-sizing: content-box; /* 2 */
+  box-sizing: content-box;
+}
+
+/**
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
+ * Safari (but not Chrome) clips the cancel button when the search input has
+ * padding (and `textfield` appearance).
+ */
+
+input[type="search"]::-webkit-search-cancel-button,
+input[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+  border: 1px solid #c0c0c0;
+  margin: 0 2px;
+  padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+  border: 0; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+  overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+  font-weight: bold;
+}
+
+/* Tables
+   ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+td,
+th {
+  padding: 0;
+}
\ No newline at end of file
--- /dev/null
+++ b/util/css/skeleton.css
@@ -1,0 +1,418 @@
+/*
+* Skeleton V2.0.4
+* Copyright 2014, Dave Gamache
+* www.getskeleton.com
+* Free to use under the MIT license.
+* http://www.opensource.org/licenses/mit-license.php
+* 12/29/2014
+*/
+
+
+/* Table of contents
+––––––––––––––––––––––––––––––––––––––––––––––––––
+- Grid
+- Base Styles
+- Typography
+- Links
+- Buttons
+- Forms
+- Lists
+- Code
+- Tables
+- Spacing
+- Utilities
+- Clearing
+- Media Queries
+*/
+
+
+/* Grid
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.container {
+  position: relative;
+  width: 100%;
+  max-width: 960px;
+  margin: 0 auto;
+  padding: 0 20px;
+  box-sizing: border-box; }
+.column,
+.columns {
+  width: 100%;
+  float: left;
+  box-sizing: border-box; }
+
+/* For devices larger than 400px */
+@media (min-width: 400px) {
+  .container {
+    width: 85%;
+    padding: 0; }
+}
+
+/* For devices larger than 550px */
+@media (min-width: 550px) {
+  .container {
+    width: 80%; }
+  .column,
+  .columns {
+    margin-left: 4%; }
+  .column:first-child,
+  .columns:first-child {
+    margin-left: 0; }
+
+  .one.column,
+  .one.columns                    { width: 4.66666666667%; }
+  .two.columns                    { width: 13.3333333333%; }
+  .three.columns                  { width: 22%;            }
+  .four.columns                   { width: 30.6666666667%; }
+  .five.columns                   { width: 39.3333333333%; }
+  .six.columns                    { width: 48%;            }
+  .seven.columns                  { width: 56.6666666667%; }
+  .eight.columns                  { width: 65.3333333333%; }
+  .nine.columns                   { width: 74.0%;          }
+  .ten.columns                    { width: 82.6666666667%; }
+  .eleven.columns                 { width: 91.3333333333%; }
+  .twelve.columns                 { width: 100%; margin-left: 0; }
+
+  .one-third.column               { width: 30.6666666667%; }
+  .two-thirds.column              { width: 65.3333333333%; }
+
+  .one-half.column                { width: 48%; }
+
+  /* Offsets */
+  .offset-by-one.column,
+  .offset-by-one.columns          { margin-left: 8.66666666667%; }
+  .offset-by-two.column,
+  .offset-by-two.columns          { margin-left: 17.3333333333%; }
+  .offset-by-three.column,
+  .offset-by-three.columns        { margin-left: 26%;            }
+  .offset-by-four.column,
+  .offset-by-four.columns         { margin-left: 34.6666666667%; }
+  .offset-by-five.column,
+  .offset-by-five.columns         { margin-left: 43.3333333333%; }
+  .offset-by-six.column,
+  .offset-by-six.columns          { margin-left: 52%;            }
+  .offset-by-seven.column,
+  .offset-by-seven.columns        { margin-left: 60.6666666667%; }
+  .offset-by-eight.column,
+  .offset-by-eight.columns        { margin-left: 69.3333333333%; }
+  .offset-by-nine.column,
+  .offset-by-nine.columns         { margin-left: 78.0%;          }
+  .offset-by-ten.column,
+  .offset-by-ten.columns          { margin-left: 86.6666666667%; }
+  .offset-by-eleven.column,
+  .offset-by-eleven.columns       { margin-left: 95.3333333333%; }
+
+  .offset-by-one-third.column,
+  .offset-by-one-third.columns    { margin-left: 34.6666666667%; }
+  .offset-by-two-thirds.column,
+  .offset-by-two-thirds.columns   { margin-left: 69.3333333333%; }
+
+  .offset-by-one-half.column,
+  .offset-by-one-half.columns     { margin-left: 52%; }
+
+}
+
+
+/* Base Styles
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+/* NOTE
+html is set to 62.5% so that all the REM measurements throughout Skeleton
+are based on 10px sizing. So basically 1.5rem = 15px :) */
+html {
+  font-size: 62.5%; }
+body {
+  font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
+  line-height: 1.6;
+  font-weight: 400;
+  font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
+  color: #222; }
+
+
+/* Typography
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+h1, h2, h3, h4, h5, h6 {
+  margin-top: 0;
+  margin-bottom: 2rem;
+  font-weight: 300; }
+h1 { font-size: 4.0rem; line-height: 1.2;  letter-spacing: -.1rem;}
+h2 { font-size: 2.6rem; line-height: 1.25; letter-spacing: -.1rem; }
+h3 { font-size: 3.0rem; line-height: 1.3;  letter-spacing: -.1rem; }
+h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
+h5 { font-size: 1.8rem; line-height: 1.5;  letter-spacing: -.05rem; }
+h6 { font-size: 1.5rem; line-height: 1.6;  letter-spacing: 0; }
+
+/* Larger than phablet */
+@media (min-width: 550px) {
+  h1 { font-size: 3.0rem; }
+  h2 { font-size: 2.6rem; }
+  h3 { font-size: 2.5rem; }
+  h4 { font-size: 1.5rem; }
+  h5 { font-size: 1.2rem; }
+  h6 { font-size: 0.5rem; }
+}
+
+p {
+  margin-top: 0; }
+
+
+/* Links
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+a {
+  color: #1EAEDB; }
+a:hover {
+  color: #0FA0CE; }
+
+
+/* Buttons
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.button,
+button,
+input[type="submit"],
+input[type="reset"],
+input[type="button"] {
+  display: inline-block;
+  height: 38px;
+  padding: 0 30px;
+  color: #555;
+  text-align: center;
+  font-size: 11px;
+  font-weight: 600;
+  line-height: 38px;
+  letter-spacing: .1rem;
+  text-transform: uppercase;
+  text-decoration: none;
+  white-space: nowrap;
+  background-color: transparent;
+  border-radius: 4px;
+  border: 1px solid #bbb;
+  cursor: pointer;
+  box-sizing: border-box; }
+.button:hover,
+button:hover,
+input[type="submit"]:hover,
+input[type="reset"]:hover,
+input[type="button"]:hover,
+.button:focus,
+button:focus,
+input[type="submit"]:focus,
+input[type="reset"]:focus,
+input[type="button"]:focus {
+  color: #333;
+  border-color: #888;
+  outline: 0; }
+.button.button-primary,
+button.button-primary,
+input[type="submit"].button-primary,
+input[type="reset"].button-primary,
+input[type="button"].button-primary {
+  color: #FFF;
+  background-color: #33C3F0;
+  border-color: #33C3F0; }
+.button.button-primary:hover,
+button.button-primary:hover,
+input[type="submit"].button-primary:hover,
+input[type="reset"].button-primary:hover,
+input[type="button"].button-primary:hover,
+.button.button-primary:focus,
+button.button-primary:focus,
+input[type="submit"].button-primary:focus,
+input[type="reset"].button-primary:focus,
+input[type="button"].button-primary:focus {
+  color: #FFF;
+  background-color: #1EAEDB;
+  border-color: #1EAEDB; }
+
+
+/* Forms
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea,
+select {
+  height: 38px;
+  padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
+  background-color: #fff;
+  border: 1px solid #D1D1D1;
+  border-radius: 4px;
+  box-shadow: none;
+  box-sizing: border-box; }
+/* Removes awkward default styles on some inputs for iOS */
+input[type="email"],
+input[type="number"],
+input[type="search"],
+input[type="text"],
+input[type="tel"],
+input[type="url"],
+input[type="password"],
+textarea {
+  -webkit-appearance: none;
+     -moz-appearance: none;
+          appearance: none; }
+textarea {
+  min-height: 65px;
+  padding-top: 6px;
+  padding-bottom: 6px; }
+input[type="email"]:focus,
+input[type="number"]:focus,
+input[type="search"]:focus,
+input[type="text"]:focus,
+input[type="tel"]:focus,
+input[type="url"]:focus,
+input[type="password"]:focus,
+textarea:focus,
+select:focus {
+  border: 1px solid #33C3F0;
+  outline: 0; }
+label,
+legend {
+  display: block;
+  margin-bottom: .5rem;
+  font-weight: 600; }
+fieldset {
+  padding: 0;
+  border-width: 0; }
+input[type="checkbox"],
+input[type="radio"] {
+  display: inline; }
+label > .label-body {
+  display: inline-block;
+  margin-left: .5rem;
+  font-weight: normal; }
+
+
+/* Lists
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+ul {
+  list-style: circle inside; }
+ol {
+  list-style: decimal inside; }
+ol, ul {
+  padding-left: 0;
+  margin-top: 0; }
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+  margin: 1.5rem 0 1.5rem 3rem;
+  font-size: 90%; }
+li {
+  margin-bottom: 1rem; }
+
+
+/* Code
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+code {
+  padding: .2rem .5rem;
+  margin: 0 .2rem;
+  font-size: 90%;
+  white-space: nowrap;
+  background: #F1F1F1;
+  border: 1px solid #E1E1E1;
+  border-radius: 4px; }
+pre > code {
+  display: block;
+  padding: 1rem 1.5rem;
+  white-space: pre; }
+
+
+/* Tables
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+th,
+td {
+  padding: 12px 15px 12px 15px;
+  text-align: left;
+  border-bottom: 1px solid #E1E1E1; }
+th:first-child,
+td:first-child {
+  padding-left: 0; }
+th:last-child,
+td:last-child {
+  padding-right: 0; }
+
+
+/* Spacing
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+button,
+.button {
+  margin-bottom: 1rem; }
+input,
+textarea,
+select,
+fieldset {
+  margin-bottom: 1.5rem; }
+pre,
+blockquote,
+dl,
+figure,
+table,
+p,
+ul,
+ol,
+form {
+  margin-bottom: 2.5rem; }
+
+
+/* Utilities
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+.u-full-width {
+  width: 100%;
+  box-sizing: border-box; }
+.u-max-full-width {
+  max-width: 100%;
+  box-sizing: border-box; }
+.u-pull-right {
+  float: right; }
+.u-pull-left {
+  float: left; }
+
+
+/* Misc
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+hr {
+  margin-top: 3rem;
+  margin-bottom: 3.5rem;
+  border-width: 0;
+  border-top: 1px solid #E1E1E1; }
+
+
+/* Clearing
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+
+/* Self Clearing Goodness */
+.container:after,
+.row:after,
+.u-cf {
+  content: "";
+  display: table;
+  clear: both; }
+
+
+/* Media Queries
+–––––––––––––––––––––––––––––––––––––––––––––––––– */
+/*
+Note: The best way to structure the use of media queries is to create the queries
+near the relevant code. For example, if you wanted to change the styles for buttons
+on small devices, paste the mobile query code up in the buttons section and style it
+there.
+*/
+
+
+/* Larger than mobile */
+@media (min-width: 400px) {}
+
+/* Larger than phablet (also point when grid becomes active) */
+@media (min-width: 550px) {}
+
+/* Larger than tablet */
+@media (min-width: 750px) {}
+
+/* Larger than desktop */
+@media (min-width: 1000px) {}
+
+/* Larger than Desktop HD */
+@media (min-width: 1200px) {}
--- /dev/null
+++ b/util/data2html.lua
@@ -1,0 +1,310 @@
+#!/usr/bin/env lua
+
+-- Parse a lua table in modules/data and write text
+-- to run: lua sp.lua "foo"
+
+sptbl = {}
+module = arg[1]
+dofile(string.format("modules/data/%s.lua", module))
+PG = { name = module }
+
+function PG.printheader(self, str)
+    io.write("<div class=\"row\">\n")
+    io.write("<h2>" .. str .. "</h2>")
+    io.write("</div>\n")
+end
+
+function PG.printoption(self, str)
+    io.write("<i>" .. str .. ":</i> ")
+end
+
+function PG.title(self, sp)
+    io.write("<i><h1>" .. self.name .. "</h1></i>\n")
+end
+
+function PG.desc(self, sp)
+    str,_ =  string.gsub(sp[self.name].description, "\n\n","<br>")
+    print(str)
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.createf(self, sp)
+    local tbl = sp[self.name]
+    print(string.format("%s(sp_%s **%s)",
+        tbl.func.create, self.name, self.name, tbl.func.init))
+end
+
+function PG.destroyf(self, sp)
+    local tbl = sp[self.name]
+    print(string.format("%s(sp_%s **%s)",
+        tbl.func.destroy, self.name, self.name, tbl.func.init))
+end
+
+function PG.initf(self, sp)
+    local tbl = sp[self.name]
+
+    io.write(string.format("%s(sp_data *sp, sp_%s *%s",
+    tbl.func.init, self.name, self.name))
+
+    if(tbl.params.mandatory ~= nil) then
+
+        for _, v in pairs(tbl.params.mandatory) do
+            if(string.byte(v.type, string.len(v.type)) == 42) then
+    	        arg = string.format(", %s%s", v.type, v.name)
+            else
+    	        arg = string.format(", %s %s", v.type, v.name)
+            end
+            io.write(arg)
+        end
+    end
+
+    io.write(")\n")
+end
+
+function PG.genf(self, sp)
+    local tbl = sp[self.name]
+
+    io.write(string.format("%s(sp_data *sp, sp_ftbl *ft ", tbl.func.name))
+
+    if(tbl.params ~= nil) then
+        for _, v in pairs(tbl.params) do
+            if(string.byte(v.type, string.len(v.type)) == 42) then
+    	        arg = string.format(", %s%s", v.type, v.name)
+            else
+    	        arg = string.format(", %s %s", v.type, v.name)
+            end
+            io.write(arg)
+        end
+    end
+
+    io.write(")\n")
+end
+
+function PG.computef(self, sp)
+    local tbl = sp[self.name]
+    io.write(string.format("%s(sp_data *sp, sp_%s *%s",
+        tbl.func.compute, self.name, self.name, tbl.func.init))
+
+    if tbl.inputs ~= nil then
+        for _, input in pairs(tbl.inputs) do
+            io.write(string.format(", SPFLOAT *%s", input.name))
+        end
+    end
+
+    if tbl.outputs ~= nil then
+        for _, output in pairs(tbl.outputs) do
+            io.write(string.format(", SPFLOAT *%s", output.name))
+        end
+    end
+
+    io.write(")\n")
+end
+
+
+function PG.funcs(self, sp)
+    io.write("<div class=\"row\">\n")
+    self:printheader("Functions")
+    io.write("</div>\n")
+    io.write("<div class=\"row\">\n")
+    self:createf(sp)
+    io.write("</div>\n")
+    io.write("<div class=\"row\">\n")
+    self:initf(sp)
+    io.write("</div>\n")
+    io.write("<div class=\"row\">\n")
+    self:computef(sp)
+    io.write("</div>\n")
+    io.write("<div class=\"row\">\n")
+    self:destroyf(sp)
+    io.write("</div>\n")
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.genfuncs(self, sp)
+    io.write("<div class=\"row\">\n")
+    self:printheader("Functions")
+    io.write("</div>\n")
+    io.write("<div class=\"row\">\n")
+    self:genf(sp)
+    io.write("</div>\n")
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.man_params(self,sp)
+    local tbl = sp[self.name].params.mandatory
+	if (tbl == nil) then return end
+    self:printheader("Mandatory Parameters")
+    for _, v in pairs(tbl) do
+        io.write("<div class=\"row\">\n")
+        self:printoption(v.name)
+        io.write(v.description)
+        io.write("</div>\n")
+        io.write("<div class=\"row\">\n")
+        io.write(string.format("\n(Recommended value: %s)\n",
+            v.default))
+        io.write("</div>\n")
+    end
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.genparams(self,sp)
+    local tbl = sp[self.name].params
+	if (tbl == nil) then return end
+    self:printheader("Parameters")
+    for _, v in pairs(tbl) do
+        io.write("<div class=\"row\">\n")
+        self:printoption(v.name)
+        io.write(v.description)
+        io.write("</div>\n")
+        io.write("<div class=\"row\">\n")
+        io.write(string.format("\n(Recommended value: %s)\n",
+            v.default))
+        io.write("</div>\n")
+    end
+    io.write("<div class=\"row\"><br></div>\n")
+ end
+function PG.opt_params(self,sp)
+    local tbl = sp[self.name].params.optional
+
+    if (tbl == nil) then return end
+    self:printheader("Optional Parameters")
+
+    for _, v in pairs(tbl) do
+        io.write("<div class=\"row\">\n")
+        self:printoption(v.name)
+        io.write(v.description)
+        io.write("</div>\n")
+
+        io.write("<div class=\"row\">\n")
+        io.write(string.format("\n(Default value: %s)\n",
+            v.default))
+        io.write("</div>\n")
+
+    end
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.inputs(self, sp)
+    if sp[self.name].ninputs == 0 then return end;
+    self:printheader("Inputs")
+    local tbl = sp[self.name].inputs
+    for _, v in pairs(tbl) do
+        io.write("<div class=\"row\">\n")
+        self:printoption(v.name)
+        io.write(v.description .. "\n")
+        io.write("</div>\n")
+    end
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.outputs(self, sp)
+    self:printheader("Outputs")
+    local tbl = sp[self.name].outputs
+    for _, v in pairs(tbl) do
+    io.write("<div class=\"row\">\n")
+        self:printoption(v.name)
+        io.write(v.description .. "\n")
+    io.write("</div>\n")
+    end
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.other(self, sp)
+    local tbl = sp[self.name].func.other
+    if(tbl == nil) then return end
+    self:printheader("Other Functions:")
+    for func,params in pairs(tbl) do
+        io.write("<div class=\"row\">\n")
+        io.write(string.format("%s(sp_data *sp, sp_%s *%s", func, self.name, self.name))
+        for _,p in pairs(params.args) do
+            io.write(string.format(", %s %s", p.type, p.name))
+        end
+
+        io.write(")\n")
+        io.write("</div>\n")
+
+        io.write("<div class=\"row\">\n")
+        io.write(params.description)
+        io.write("</div>\n")
+        for _,p in pairs(params.args) do
+            io.write("<div class=\"row\">\n")
+            io.write("<div class=\"one column\"></div>\n")
+            io.write("<div class=\"elevent columns\">\n")
+            self:printoption(p.name)
+            io.write(p.description.. "\n")
+            io.write("</div></div>\n")
+
+            io.write("<div class=\"row\">\n")
+            io.write("<div class=\"one column\"></div>\n")
+            io.write("<div class=\"elevent columns\">\n")
+            io.write("(Suggested default: " .. p.default .. ")\n\n")
+            io.write("</div></div>\n")
+        end
+    end
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+function PG.params(self, sp)
+    PG:man_params(sp)
+    PG:opt_params(sp)
+    io.write("\n")
+end
+
+function PG.files(self, sp)
+    local tbl = sp[self.name].files
+    io.write("<div class=\"row\">\n")
+    io.write(string.format("Files: <i>%s, %s</i>", tbl.header, tbl.module))
+    io.write("</div>\n")
+    io.write("<div class=\"row\"><br></div>\n")
+end
+
+-- Examples have been removed now
+-- function PG.example(self, sp)
+--     local example = sp[self.name].files.example
+--     if (example == nil) then return end
+--     self:printheader("Example Code")
+--     file = io.open("examples/" .. example)
+--     io.write("<pre><code>")
+--     for line in file:lines() do
+--         io.write(string.gsub(line:gsub("<", "&lt;"), ">", "&gt;") .. "\n")
+--     end
+--     io.write("</code></pre>")
+--     file:close()
+-- end
+
+function PG.makepage(self, sp)
+    io.write("<html>\n")
+    io.write("<title>" .. self.name .. "</title>\n")
+    io.write("<head>\n")
+    io.write("<link rel=\"stylesheet\" href=\"css/skeleton.css\">\n")
+    io.write("<link rel=\"stylesheet\" href=\"css/normalize.css\">\n")
+    io.write("</head>\n")
+    io.write("<body>\n")
+    io.write("<div class=\"container\">\n")
+    if(string.match(sptbl[self.name].modtype, "^module$")) then
+        PG:title(sptbl)
+        PG:files(sptbl)
+        PG:desc(sptbl)
+        PG:funcs(sptbl)
+        PG:params(sptbl)
+        PG:inputs(sptbl)
+        PG:outputs(sptbl)
+        PG:other(sptbl)
+        -- Examples have been removed for now
+        -- PG:example(sptbl)
+    end
+    if(string.match(sptbl[self.name].modtype, "^gen$")) then
+        PG:title(sptbl)
+        PG:files(sptbl)
+        PG:desc(sptbl)
+        PG:genfuncs(sptbl)
+        PG:genparams(sptbl)
+        -- Examples have been removed for now
+        -- PG:example(sptbl)
+    end
+    io.write("</div>")
+    io.write("</body>")
+    io.write("</html>\n")
+end
+
+PG:makepage(sptbl)
--- /dev/null
+++ b/util/data2txt.lua
@@ -1,0 +1,160 @@
+#!/usr/local/bin/lua
+
+-- Parse a lua table in modules/data and write text
+-- to run: lua sp.lua "foo"
+
+sptbl = {}
+module = arg[1]
+dofile(string.format("modules/data/%s.lua", module))
+PG = { name = module }
+
+function PG.printheader(self, str)
+    io.write(str .. "\n")
+    for i = 1, string.len(str) do
+        io.write("-")
+    end
+    io.write("\n\n")
+end
+
+function PG.title(self, sp)
+    io.write(self.name .. "\n")
+    for i = 1, string.len(self.name) do
+        io.write("=")
+    end
+    io.write("\n\n")
+end
+
+function PG.desc(self, sp)
+    print(sp[self.name].description)
+    io.write("\n")
+end
+
+function PG.createf(self, sp)
+    local tbl = sp[self.name]
+    print(string.format("%s(sp_%s **%s)", 
+        tbl.func.create, self.name, self.name, tbl.func.init))
+end
+
+function PG.destroyf(self, sp)
+    local tbl = sp[self.name]
+    print(string.format("%s(sp_%s **%s)", 
+        tbl.func.destroy, self.name, self.name, tbl.func.init))
+end
+
+function PG.initf(self, sp)
+    local tbl = sp[self.name]
+    
+    io.write(string.format("%s(sp_data *sp, sp_%s *%s", 
+        tbl.func.init, self.name, self.name))
+    
+    for _, v in pairs(tbl.params.mandatory) do
+        if(string.byte(v.type, string.len(v.type)) == 42) then
+        arg = string.format(", %s%s", v.type, v.name)
+        else
+        arg = string.format(", %s %s", v.type, v.name)
+        end
+        io.write(arg)
+    end
+
+    io.write(")\n")
+end
+
+function PG.computef(self, sp)
+    local tbl = sp[self.name]
+    io.write(string.format("%s(sp_data *sp, sp_%s *%s", 
+        tbl.func.compute, self.name, self.name, tbl.func.init))
+        
+    for _, input in pairs(tbl.inputs) do
+        io.write(string.format(", SPFLOAT *%s", input.name))
+    end
+
+    io.write(")\n")
+end
+
+
+function PG.funcs(self, sp)
+    self:printheader("Functions")    
+	self:createf(sp)   
+	self:initf(sp)   
+	self:computef(sp)
+	self:destroyf(sp)   
+	io.write("\n")
+end
+
+function PG.man_params(self,sp)
+    self:printheader("Mandatory Parameters")
+    local tbl = sp[self.name].params.mandatory
+    for _, v in pairs(tbl) do
+        io.write(string.format("%s: ", v.name))
+        io.write(v.description)
+        io.write(string.format("\n(Recommended value: %s)\n\n", v.default))
+    end
+ end
+
+function PG.opt_params(self,sp)
+    self:printheader("Optional Parameters:")
+    local tbl = sp[self.name].params.optional
+    for _, v in pairs(tbl) do
+        io.write(string.format("*%s*: ", v.name))
+        io.write(v.description)
+        io.write(string.format("\n(Default value: %s)\n\n", v.default))
+    end
+end
+
+function PG.inputs(self, sp)
+    self:printheader("Inputs:")
+    local tbl = sp[self.name].inputs
+    for _, v in pairs(tbl) do
+        io.write(string.format("*%s*: ", v.name))
+        io.write(v.description .. "\n\n")
+    end
+	io.write("\n")
+end
+	
+function PG.outputs(self, sp)
+    self:printheader("Outputs:")
+    local tbl = sp[self.name].outputs
+    for _, v in pairs(tbl) do
+        io.write(string.format("*%s*: ", v.name))
+        io.write(v.description .. "\n\n")
+    end
+	io.write("\n")
+end
+
+function PG.other(self, sp)
+    self:printheader("Other Functions:")
+    local tbl = sp[self.name].func.other
+    
+    for func,params in pairs(tbl) do
+        io.write(string.format("%s(sp_%s %s", func, self.name, self.name))
+        for _,p in pairs(params) do
+            io.write(string.format(", %s %s", p.type, p.name))
+        end
+        io.write(")\n\n")
+        for _,p in pairs(params) do
+            io.write("*" .. p.name .. ":* ")
+            io.write(p.description.. "\n")
+            io.write("(Suggested default: " .. p.default .. ")\n\n")
+            
+        end
+    end
+    io.write("\n")
+end
+	
+function PG.params(self, sp)
+    PG:man_params(sp)
+    PG:opt_params(sp)
+    io.write("\n")
+end
+
+function PG.makepage(self, sp)
+	PG:title(sptbl)
+	PG:desc(sptbl)
+	PG:funcs(sptbl)
+	PG:params(sptbl)
+	PG:inputs(sptbl)
+	PG:outputs(sptbl)
+	PG:other(sptbl)
+end
+
+PG:makepage(sptbl)
\ No newline at end of file
--- /dev/null
+++ b/util/faust/autowah.dsp
@@ -1,0 +1,22 @@
+declare id "auto"; // selector crybaby / autowah
+declare name "auto";
+
+//-----------------------------------------------
+//     Auto-Wah
+//-----------------------------------------------
+
+import("effect.lib"); //for crybaby definition
+import("guitarix.lib");
+
+l = crybaby_ctrl.level;
+a = crybaby_ctrl.wah;
+w = crybaby_ctrl.wet_dry;
+
+d = 1-w;
+Sum(n,x) = +(x - (x @ n)) ~_ ;
+
+Average(n,x) = x * (1<<22) : int : abs : Sum(n) : float : /(1<<22)
+                 : /(n);
+
+Map(x) = x * a : max(0) : min(1) ;
+process(x) = x : _<:*(d),(*(w):*(l) :a * crybaby(x : amp_follower_ud(0.01,0.1) : min(1)) + (1.0-a) * x):>_ ;
--- /dev/null
+++ b/util/faust/compile.sh
@@ -1,0 +1,11 @@
+#!/bin/sh
+
+if [ "$#" -eq 0 ]
+then
+echo "Please specify the name of the DSP module"
+exit 1
+fi
+
+NAME=$1
+faust -cn $NAME -json -lang c -a sp.c $NAME.dsp -o $NAME.c 
+go run parse.go $NAME $NAME.dsp.json >> $NAME.c 
--- /dev/null
+++ b/util/faust/compressor.dsp
@@ -1,0 +1,8 @@
+import("effect.lib");
+
+ratio = hslider("[0] ratio", 1, 1, 40, 0.001);
+thresh = hslider("[1] thresh", 0, -80, 0, 0.001);
+atk = hslider("[2] atk", 0.1, 0, 10, 0.001);
+rel = hslider("[3] rel", 0.1, 0, 10, 0.001);
+
+process = compressor_mono(ratio, thresh, atk, rel);
--- /dev/null
+++ b/util/faust/parse.go
@@ -1,0 +1,47 @@
+package main
+
+import "encoding/json"
+import "io/ioutil"
+import "fmt"
+import "os"
+import "text/template"
+
+type Blah struct {
+	Count int
+	Name string
+	Params []string
+}
+
+func main() {
+	
+	if len(os.Args) < 1 {
+		fmt.Println("Please specify the name, then a filename")
+		os.Exit(1)
+	}
+
+	var cnt Blah	
+	
+	tmpl, err := template.ParseFiles("sp_faust.c.template")
+	
+	if err != nil { panic(err) }	
+	
+	byt, _ := ioutil.ReadFile(os.Args[2])
+
+	var dat map[string]interface{}
+
+	if err := json.Unmarshal(byt, &dat); err != nil {
+		panic(err)
+	}
+
+	
+	items := dat["ui"].([]interface{})[0].(map[string]interface{})["items"].([]interface{})
+
+	cnt.Count = len(items)
+	cnt.Name = os.Args[1]
+	for _, val := range items {
+		mymap := val.(map[string]interface{})
+		cnt.Params = append(cnt.Params, mymap["label"].(string))
+	}
+
+	tmpl.ExecuteTemplate(os.Stdout, "sp_faust.c.template", cnt)
+}
--- /dev/null
+++ b/util/faust/pinknoise.dsp
@@ -1,0 +1,3 @@
+import("oscillator.lib");
+amp = hslider("amp", 1, 0, 1, 0.0001);
+process = pink_noise * amp;
--- /dev/null
+++ b/util/faust/saw.dsp
@@ -1,0 +1,4 @@
+import("oscillator.lib");
+freq = hslider("[0]freq", 440, 0, 20000, 0.0001);
+amp = hslider("[1]amp", 1, 0, 1, 0.0001);
+process = sawtooth(freq) * amp;
--- /dev/null
+++ b/util/faust/sp.c
@@ -1,0 +1,74 @@
+#include <math.h>
+#include "CUI.h"
+
+#define max(a,b) ((a < b) ? b : a)
+#define min(a,b) ((a < b) ? a : b)
+
+<<includeIntrinsic>>
+
+<<includeclass>>
+
+/* -- layout groups */
+
+static void openTabBox (void* ui_interface, const char* label)
+{
+
+}
+
+static void openHorizontalBox (void* ui_interface, const char* label)
+{
+
+}
+static void openVerticalBox (void* ui_interface, const char* label)
+{
+
+}
+
+static void closeBox (void* ui_interface)
+{
+
+}
+
+/* -- active widgets */
+
+static void addButton (void* ui_interface, const char* label, FAUSTFLOAT* zone)
+{
+
+}
+
+static void addCheckButton (void* ui_interface, const char* label, FAUSTFLOAT* zone)
+{
+
+}
+
+static void addVerticalSlider (void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+
+}
+
+static void addHorizontalSlider (void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+
+}
+
+static void addNumEntry (void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+
+}
+
+/* -- passive display widgets */
+
+static void addHorizontalBargraph (void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+{
+
+}
+
+static void addVerticalBargraph (void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+{
+
+}
+
+static void declare (void* ui_interface, FAUSTFLOAT* zone, const char* key, const char* value)
+{
+
+}
--- /dev/null
+++ b/util/faust/sp_faust.c.template
@@ -1,0 +1,65 @@
+typedef struct {
+    void *faust;
+    int argpos;
+    SPFLOAT *args[{{.Count}}];
+    {{range $index, $element := .Params}}SPFLOAT *{{$element}};
+    {{end}}
+} sp_{{.Name}};
+
+int sp_{{.Name}}_create(sp_{{.Name}} **p);
+int sp_{{.Name}}_destroy(sp_{{.Name}} **p);
+int sp_{{.Name}}_init(sp_data *sp, sp_{{.Name}} *p);
+int sp_{{.Name}}_compute(sp_data *sp, sp_{{.Name}} *p, SPFLOAT *in, SPFLOAT *out);
+
+
+static void addHorizontalSlider(void* ui_interface, const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+{
+    sp_{{.Name}} *p = ui_interface;
+    p->args[p->argpos] = zone;
+    p->argpos++;
+}
+
+int sp_{{.Name}}_create(sp_{{.Name}} **p)
+{
+    *p = malloc(sizeof(sp_{{.Name}}));
+    return SP_OK;
+}
+
+int sp_{{.Name}}_destroy(sp_{{.Name}} **p)
+{
+    sp_{{.Name}} *pp = *p;
+    {{.Name}} *dsp = pp->faust;
+    delete{{.Name}} (dsp);
+    free(*p);
+    return SP_OK;
+}
+
+int sp_{{.Name}}_init(sp_data *sp, sp_{{.Name}} *p)
+{
+    {{.Name}} *dsp = new{{.Name}}(); 
+    UIGlue UI;
+    p->argpos = 0;
+    UI.addHorizontalSlider= addHorizontalSlider;
+    UI.uiInterface = p;
+    buildUserInterface{{.Name}}(dsp, &UI);
+    init{{.Name}}(dsp, sp->sr);
+
+    {{range $index, $element := .Params}} 
+    p->{{$element}} = p->args[{{$index}}];{{end}}
+
+    p->faust = dsp;
+    return SP_OK;
+}
+
+int sp_{{.Name}}_compute(sp_data *sp, sp_{{.Name}} *p, SPFLOAT *in, SPFLOAT *out) 
+{
+
+    {{.Name}} *dsp = p->faust;
+    SPFLOAT out1 = 0;
+    SPFLOAT *faust_out[] = {&out1};
+    SPFLOAT *faust_in[] = {in};
+    compute{{.Name}}(dsp, 1, faust_in, faust_out);
+
+    *out = out1;
+    return SP_OK;
+}
--- /dev/null
+++ b/util/faust/square.dsp
@@ -1,0 +1,7 @@
+import("oscillator.lib");
+
+freq = hslider("[1]frequency", 440, 0, 20000, 0.0001);
+amp = hslider("[2]amp", 1, 0, 1, 0.00001);
+width = hslider("[3]width", 0.5, 0, 1, 0.0000);
+
+process = pulsetrainN(2, freq, width) * amp;
--- /dev/null
+++ b/util/faust/triangle.dsp
@@ -1,0 +1,6 @@
+import("oscillator.lib");
+
+freq = hslider("[0]freq", 440, 0, 20000, 0.0001);
+amp = hslider("[1]amp", 1, 0, 1, 0.00001);
+
+process = triangle(freq) * amp;
--- /dev/null
+++ b/util/faust/vocoder.dsp
@@ -1,0 +1,6 @@
+import("effect.lib");
+
+atk = hslider("[0] atk", 0.01, 0.0001, 0.5, 0.00001);
+rel = hslider("[1] rel", 0.01, 0.0001, 0.5, 0.00001);
+bwratio = hslider("[2] bwratio", 0.5, 0.1, 2, 0.001);
+process = vocoder(16, atk, rel, bwratio);
--- /dev/null
+++ b/util/faust/zitarev.dsp
@@ -1,0 +1,89 @@
+import("effect.lib");
+
+my_zita(x,y) = zita_rev1_stereo(rdel,f1,f2,t60dc,t60m,fsmax,x,y)
+	  : out_eq : dry_wet(x,y) : out_level
+with {
+
+  fsmax = 96000.0;  // highest sampling rate that will be used
+
+
+  rdel = hslider("[00] in_delay [unit:ms] [style:knob]
+                  [tooltip: Delay in ms before reverberation begins]",
+                  60,10,100,1);
+
+
+  f1 = hslider("[01] lf_x [unit:Hz] [style:knob] [scale:log]
+       [tooltip: Crossover frequency (Hz) separating low and middle frequencies]",
+       200, 50, 1000, 1);
+
+  t60dc = hslider("[02] rt60_low [unit:s] [style:knob] [scale:log]
+          [style:knob] [tooltip: T60 = time (in seconds) to decay 60dB in low-frequency band]",
+	  3, 1, 8, 0.1);
+
+  t60m = hslider("[03] rt60_mid [unit:s] [style:knob] [scale:log]
+          [tooltip: T60 = time (in seconds) to decay 60dB in middle band]",
+	  2, 1, 8, 0.1);
+
+  f2 = hslider("[04] hf_damping [unit:Hz] [style:knob] [scale:log]
+       [tooltip: Frequency (Hz) at which the high-frequency T60 is half the middle-band's T60]",
+       6000, 1500, 0.49*fsmax, 1);
+
+  out_eq = pareq_stereo(eq1f,eq1l,eq1q) : pareq_stereo(eq2f,eq2l,eq2q);
+// Zolzer style peaking eq (not used in zita-rev1) (filter.lib):
+// pareq_stereo(eqf,eql,Q) = peak_eq(eql,eqf,eqf/Q), peak_eq(eql,eqf,eqf/Q);
+// Regalia-Mitra peaking eq with "Q" hard-wired near sqrt(g)/2 (filter.lib):
+  pareq_stereo(eqf,eql,Q) = peak_eq_rm(eql,eqf,tpbt), peak_eq_rm(eql,eqf,tpbt)
+  with {
+    tpbt = wcT/sqrt(max(0,g)); // tan(PI*B/SR), B bw in Hz (Q^2 ~ g/4)
+    wcT = 2*PI*eqf/SR;  // peak frequency in rad/sample
+    g = db2linear(eql); // peak gain
+  };
+
+  eq1f = hslider("[05] eq1_freq [unit:Hz] [style:knob] [scale:log]
+       [tooltip: Center-frequency of second-order Regalia-Mitra peaking equalizer section 1]",
+       315, 40, 2500, 1);
+
+  eq1l = hslider("[06] eq1_level [unit:dB] [style:knob]
+       [tooltip: Peak level in dB of second-order Regalia-Mitra peaking equalizer section 1]",
+       0, -15, 15, 0.1);
+
+  eq1q = hslider("[07] eq1_q [style:knob]
+       [tooltip: Q = centerFrequency/bandwidth of second-order peaking equalizer section 1]",
+       3, 0.1, 10, 0.1);
+
+  //eq2_group(x) = hgroup("[08] RM Peaking Equalizer 2", x);
+
+  eq2f = hslider("[09] eq2_freq [unit:Hz] [style:knob] [scale:log]
+       [tooltip: Center-frequency of second-order Regalia-Mitra peaking equalizer section 2]",
+       1500, 160, 10000, 1);
+
+  eq2l = hslider("[10] eq2_level [unit:dB] [style:knob]
+       [tooltip: Peak level in dB of second-order Regalia-Mitra peaking equalizer section 2]",
+       0, -15, 15, 0.1);
+
+  eq2q = hslider("[11] Eq2_Q [style:knob]
+       [tooltip: Q = centerFrequency/bandwidth of second-order peaking equalizer section 2]",
+       3, 0.1, 10, 0.1);
+
+  //dry_wet(x,y) = *(wet) + dry*x, *(wet) + dry*y with {
+  //  wet = 0.5*(drywet+1.0);
+  //  dry = 1.0-wet;
+  //};
+  dry_wet(x,y) = *(wet) + dry*x, *(wet) + dry*y with {
+    wet = drywet;
+    dry = 1.0-wet;
+  };
+
+  drywet = hslider("[12] mix [style:knob]
+       [tooltip: 0 = dry, 1 = wet]",
+       1, 0.0, 1.0, 0.001) : smooth(0.999);
+
+  out_level = *(gain),*(gain);
+
+  gain = hslider("[13] level [unit:dB] [style:knob]
+    [tooltip: Output scale factor]", -20, -70, 40, 0.1)
+    : db2linear : smooth(0.999);
+
+};
+
+process = my_zita;
--- /dev/null
+++ b/util/gen_index.lua
@@ -1,0 +1,27 @@
+#!/usr/bin/env lua
+
+
+file = io.open(arg[1])
+io.write("<html>\n")
+io.write("<head>\n")
+io.write("<title>Soundpipe</title>\n")
+io.write("<link rel=\"stylesheet\" href=\"css/skeleton.css\">\n")
+io.write("<link rel=\"stylesheet\" href=\"css/normalize.css\">\n")
+io.write("</head>\n")
+io.write("<body>\n<div class=\"container\">\n")
+io.write("<h1>Soundpipe Modules</h1><table>\n")
+for line in file:lines() do
+    sptbl = {}
+    dofile(string.format("modules/data/%s.lua", line))
+	io.write("<tr><td>\n")
+	io.write(string.format("<a href=\"%s.html\">%s</a></td><td><nobr>\n", line, line))
+  firstline = string.gsub(sptbl[line].description, "\n.+", "")
+  -- newstring = string.gsub(string,"Tutorial","Language")
+	io.write(string.format("%s\n", string.sub(firstline, 0, 80)))
+  if string.len(firstline) > 80 then
+    io.write("...")
+  end
+	io.write("</nobr></td></tr>\n")
+end
+
+io.write("</table></body></html>\n")
--- /dev/null
+++ b/util/gendocs.sh
@@ -1,0 +1,16 @@
+#!/bin/sh
+
+mkdir -p docs
+cp -r util/css docs
+
+> docs/modules.txt
+
+for d in modules/data/*.lua
+do
+    module=$(basename ${d%.*})
+    echo "writing $module"
+    util/data2html.lua $module > docs/$module.html
+    echo $module >> docs/modules.txt
+done
+
+util/gen_index.lua docs/modules.txt > docs/index.html
--- /dev/null
+++ b/util/module_bootstrap.sh
@@ -1,0 +1,38 @@
+#!/bin/sh
+
+makefile () {
+    local NAME=$1
+    local FILEPATH=$2
+    local EXT=$3
+
+    local FOO="$FILEPATH"foo."$EXT"
+
+    if [ ! -f "$FILEPATH$NAME.$EXT" ]
+    then
+        echo "creating $FILEPATH$NAME.$EXT"
+        cp $FOO $FILEPATH$NAME.$EXT
+        sed -i -e s/foo/$NAME/g $FILEPATH$NAME.$EXT 
+    else
+        echo "Error: file $FILEPATH$NAME.$EXT already exists."
+        exit 1
+    fi
+}
+
+if [ "$#" -ne 1 ]
+then
+    echo "Usage: make bootstrap MODULE_NAME=name"
+    exit 1
+fi
+
+MODNAME=$1
+
+# Source
+makefile $MODNAME modules/ c
+# Header
+makefile $MODNAME h/ h
+# Documentation
+makefile $MODNAME modules/data/ lua
+# Example
+makefile $MODNAME examples/ex_ c
+# Test file
+makefile $MODNAME test/t/t_ c
--- /dev/null
+++ b/util/module_howto.md
@@ -1,0 +1,176 @@
+How to Create a Soundpipe Module
+================================
+
+Creating new modules in Soundpipe is a relatively straightforward process.
+
+For this tutorial, we are going to create a gain module called "gain". 
+
+## Bootstrapping
+
+Soundpipe has a script that automatically creates the necessary template files
+needed to create a module. 
+
+This can be invoked with "make" with the following command:
+
+make bootstrap MODULE_NAME="gain"
+
+Make sure the module name you choose is unique.
+
+If successful, this script will create 4 boiler plate files:
+- modules/gain.c: the main c code. 
+- h/gain.h: the header file
+- examples/ex_gain.c: an example file utilizing gain
+- modules/data/gain.lua: metadata for gain, used to create a doc page
+
+A fully implemented module file will have these components:
+
+## The Header File
+
+Typically, the only thing here you would need to implement is the data struct 
+(empty by default). However, it is okay to tack on variables to the end of the
+init function if you need to do things like create delay lines. 
+
+```
+typedef struct {
+    SPFLOAT gain;
+} sp_gain;
+```
+
+## The Module File
+
+```
+int sp_gain_init(sp_data *sp, sp_gain *p)
+{
+    p->gain = 0;
+    return SP_OK;
+}
+
+int sp_gain_compute(sp_data *sp, sp_gain *p, SPFLOAT *in, SPFLOAT *out)
+{
+    *out = *in * p->gain;
+    return SP_OK;
+}
+```
+
+## The example
+
+```
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "soundpipe.h"
+
+typedef struct {
+    sp_gain *gain;
+    sp_osc *osc;
+    sp_ftbl *ft; 
+} UserData;
+
+void process(sp_data *sp, void *udata) {
+    UserData *ud = udata;
+    SPFLOAT osc = 0, gain = 0;
+    sp_osc_compute(sp, ud->osc, NULL, &osc);
+    sp_gain_compute(sp, ud->gain, &osc, &gain);
+    sp->out[0] = gain;
+}
+
+int main() {
+    srand(1234567);
+    UserData ud;
+    sp_data *sp;
+    sp_create(&sp);
+
+    sp_gain_create(&ud.gain);
+    sp_osc_create(&ud.osc);
+    sp_ftbl_create(sp, &ud.ft, 2048);
+
+    ud.gain->gain = 0.3;
+
+    sp_gain_init(sp, ud.gain);
+    sp_gen_sine(sp, ud.ft);
+    sp_osc_init(sp, ud.osc, ud.ft);
+
+    sp->len = 44100 * 5;
+    sp_process(sp, &ud, process);
+
+    sp_gain_destroy(&ud.gain);
+    sp_ftbl_destroy(&ud.ft);
+    sp_osc_destroy(&ud.osc);
+
+    sp_destroy(&sp);
+    return 0;
+}
+```
+
+## Metadata / Documentation
+
+```
+sptbl["gain"] = {
+
+    files = { 
+        module = "gain.c",
+        header = "gain.h",
+        example = "ex_gain.c",
+    },
+    
+    func = {
+        create = "sp_gain_create",
+        destroy = "sp_gain_destroy",
+        init = "sp_gain_init",
+        compute = "sp_gain_compute"
+    },
+    
+    params = {
+        optional = {
+            {
+                name = "gain",
+                type = "SPFLOAT",
+                description = "Sets the gain",
+                default = 0
+            },
+        }
+    },
+    
+    modtype = "module",
+    
+    description = [[Scale an incoming signal.]], 
+    
+    ninputs = 1,
+    noutputs = 1,
+    
+    inputs = { 
+        {
+            name = "input",
+            description = "this is the audio input for a made up plugin."
+        },
+    },
+    
+    outputs = {
+        {
+            name = "out",
+            description = "Signal output",
+        },
+    }
+
+}
+```
+
+## Adding to Soundpipe
+To add your module to Soundpipe, run the following command:
+
+add to config.mk
+compile
+
+## Buffers in Soundpipe
+
+Coming soon!
+
+## Using ftables in Soundpipe
+
+Coming soon!
+
+## Creating GEN routines in Soundpipe
+
+Coming soon! 
+
+
--- /dev/null
+++ b/util/stretcher.c
@@ -1,0 +1,95 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sndfile.h>
+#include "soundpipe.h"
+
+
+sp_data *sp;
+sp_ftbl *ft;
+sp_paulstretch *ps;
+
+static void process(sp_data *sp, void *ud)
+{
+    SPFLOAT out;
+    sp_paulstretch_compute(sp, ps, NULL, &out);
+    sp_out(sp, 0, out);
+}
+
+
+/* a little kluge to get file info */
+static int get_info(const char *fname,
+                    int *sr,
+                    unsigned long *len)
+{
+    SF_INFO info;
+    SNDFILE *snd;
+
+    snd = sf_open(fname, SFM_READ, &info);
+    if (snd == NULL) return 0;
+
+    *sr = info.samplerate;
+    *len = info.frames;
+    sf_close(snd);
+    return 1;
+}
+
+int main(int argc, char *argv[])
+{
+    SPFLOAT stretch;
+    SPFLOAT window;
+    uint32_t out_dur;
+    const char *fin;
+    const char *fout;
+    unsigned long len;
+    int rc;
+
+    if(argc < 5) {
+        fprintf(stderr,
+            "Usage: %s window_size stretch in.wav out.wav\n",
+            argv[0]
+        );
+        return 1;
+    }
+
+    sp_create(&sp);
+
+    printf("samplerate = %d\n", atoi(argv[1]));
+
+    sp_paulstretch_create(&ps);
+
+    fin = argv[3];
+    fout = argv[4];
+    rc = get_info(fin, &sp->sr, &sp->len);
+
+    if (!rc) {
+        printf("There was a problem with the file '%s'\n",
+               fin);
+        goto cleanup;
+    }
+
+    printf("window = %g\n", atof(argv[1]));
+    window = atof(argv[1]);
+    printf("stretch = %g\n", atof(argv[2]));
+    stretch = atof(argv[2]);
+    sp->len *= stretch;
+    printf("total dur = %gs\n", (SPFLOAT)sp->len / sp->sr);
+    printf("input = %s\n", fin);
+    sp_ftbl_loadfile(sp, &ft, fin);
+    printf("output = %s\n", fout);
+
+    strncpy(sp->filename, fout, 60);
+
+    sp_paulstretch_init(sp, ps, ft, window, stretch);
+
+    ps->wrap = 0;
+
+    sp_process(sp, NULL, process);
+
+    cleanup:
+
+    sp_ftbl_destroy(&ft);
+    sp_paulstretch_destroy(&ps);
+    sp_destroy(&sp);
+    return 0;
+}
--- /dev/null
+++ b/util/wav2smp.c
@@ -1,0 +1,93 @@
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sndfile.h>
+
+void write_sample(SNDFILE *snd, FILE *fp, char *wav, char *name,
+        float *buf, int bufsize, uint32_t *pos, int sr)
+{
+    SF_INFO info;
+    memset(&info, 0, sizeof(SF_INFO));
+    info.format = 0;
+    int count;
+    SNDFILE *in = sf_open(wav, SFM_READ, &info);
+    fprintf(fp, "[%s]\npos = %g\n", name, 1.0 * (*pos) / sr);
+    uint32_t start = *pos;
+    while((count = sf_read_float(in, buf, bufsize))) {
+        sf_write_float(snd, buf, count);
+        *pos += count;
+    }
+    fprintf(fp, "size = %g\n\n", (1.0 * (*pos) - start) / sr);
+    sf_close(in);
+}
+
+int main(int argc, char *argv[])
+{
+    if(argc <= 1) {
+        printf("Usage: [options] wav2smp in1.wav in1_name in2.wav in2_name...\n\n");
+        printf("Flags:\n");
+        printf("\t-w\tWAV file to write to (default: out.wav)\n");
+        printf("\t-o\tINI file to write to (default: out.ini)\n");
+        printf("\t-r\tSet samplerate. (default: 96000)\n");
+        return 0;
+    }
+
+
+    int argpos = 1;
+    int i;
+    int sr = 96000;
+    char wavfile[30] = "out.wav";
+    char inifile[30] = "out.ini";
+    float buf[4096];
+
+    argv++;
+
+    while(argv[0][0] == '-') {
+        switch(argv[0][1]) {
+            case 'w':
+                strncpy(wavfile, argv[1], 30);
+                argv++;
+                argpos++;
+                break;
+
+            case 'o':
+                strncpy(inifile, argv[1], 30);
+                argv++;
+                argpos++;
+                break;
+
+            case 'r':
+                sr = atoi(argv[1]);
+                argv++;
+                argpos++;
+                break;
+
+            default:
+                fprintf(stderr, "Uknown option '%c'\n", argv[0][1]);
+                break;
+
+        }
+        argv++;
+        argpos++;
+    }
+
+    SF_INFO info;
+    info.samplerate = sr;
+    info.channels = 1;
+    info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
+    SNDFILE *snd = sf_open(wavfile, SFM_WRITE, &info);
+    FILE *fp = fopen(inifile, "w");
+    uint32_t pos = 0;
+
+
+    for(i = argpos; i < argc; ) {
+        write_sample(snd, fp, argv[0], argv[1], buf, 4096, &pos, sr);
+        argv += 2;
+        i += 2;
+    }
+
+    fclose(fp);
+    sf_close(snd);
+    return 0;
+}