aboutsummaryrefslogtreecommitdiffstats
path: root/src/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/include')
-rw-r--r--src/include/common.h54
-rw-r--r--src/include/interpolate.h74
-rw-r--r--src/include/lp4pole_filter.h137
-rw-r--r--src/include/math_func.h48
-rw-r--r--src/include/uris.h59
-rw-r--r--src/include/vector_op.h44
-rw-r--r--src/include/wavedata.h193
-rw-r--r--src/include/wdatutil.h141
8 files changed, 750 insertions, 0 deletions
diff --git a/src/include/common.h b/src/include/common.h
new file mode 100644
index 0000000..26a405a
--- /dev/null
+++ b/src/include/common.h
@@ -0,0 +1,54 @@
+/*
+ Common definitions.
+ Copyright 2011 David Robillard
+ Copyright 2002 Mike Rawes
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef blop_common_h
+#define blop_common_h
+
+#include "math_func.h"
+
+/* Handy constants and macros */
+
+#ifndef SMALLEST_FLOAT
+/** Smallest generated non-zero float, used for pre-empting denormals */
+#define SMALLEST_FLOAT (1.0 / (float)0xFFFFFFFF)
+#endif
+
+/*
+ * Clip without branch (from http://musicdsp.org)
+ */
+
+static inline float
+f_min (float x, float a)
+{
+ return a - (a - x + FABSF (a - x)) * 0.5f;
+}
+
+static inline float
+f_max (float x, float b)
+{
+ return (x - b + FABSF (x - b)) * 0.5f + b;
+}
+
+static inline float
+f_clip (float x, float a, float b)
+{
+ return 0.5f * (FABSF (x - a) + a + b - FABSF (x - b));
+}
+
+#endif /* blop_common_h */
diff --git a/src/include/interpolate.h b/src/include/interpolate.h
new file mode 100644
index 0000000..237008c
--- /dev/null
+++ b/src/include/interpolate.h
@@ -0,0 +1,74 @@
+#ifndef blop_interpolate_h
+#define blop_interpolate_h
+
+#include "blop_config.h"
+#include "math_func.h"
+
+/**
+ Interpolate between p0 and n0 taking the previous (p1) and next (n1) points
+ into account, using a 3rd order polynomial (a.k.a. cubic spline).
+ @param interval Normalised time interval between intepolated sample and p0
+ @param p1 Sample two previous to interpolated one
+ @param p0 Previous sample to interpolated one
+ @param n0 Sample following interpolated one
+ @param n1 Sample following n0
+ @return Interpolated sample.
+
+ Adapted from Steve Harris' plugin code
+ swh-plugins-0.2.7/ladspa-util.h::cube_interp
+ http://plugin.org.uk/releases/0.2.7/
+*/
+static inline float
+interpolate_cubic(float interval,
+ float p1,
+ float p0,
+ float n0,
+ float n1)
+{
+ return p0 + 0.5f * interval * (n0 - p1 +
+ interval * (4.0f * n0 + 2.0f * p1 - 5.0f * p0 - n1 +
+ interval * (3.0f * (p0 - n0) - p1 + n1)));
+}
+
+/**
+ Interpolate between p0 and n0 taking the previous (p1) and next (n1) points
+ into account, using a 5th order polynomial.
+ @param interval Normalised time interval between intepolated sample and p0
+ @param p1 Sample two previous to interpolated one
+ @param p0 Previous sample to interpolated one
+ @param n0 Sample following interpolated one
+ @param n1 Sample following n0
+ @return Interpolated sample.
+
+ Adapted from http://www.musicdsp.org/archive.php?classid=5#62
+*/
+static inline float
+interpolate_quintic(float interval,
+ float p1,
+ float p0,
+ float n0,
+ float n1)
+{
+ return p0 + 0.5f * interval * (n0 - p1 +
+ interval * (n0 - 2.0f * p0 + p1 +
+ interval * ( 9.0f * (n0 - p0) + 3.0f * (p1 - n1) +
+ interval * (15.0f * (p0 - n0) + 5.0f * (n1 - p1) +
+ interval * ( 6.0f * (n0 - p0) + 2.0f * (p1 - n1))))));
+}
+
+/**
+ Linear interpolation
+*/
+static inline float
+f_lerp (float value,
+ float v1,
+ float v2)
+{
+ value -= LRINTF (value - 0.5f);
+ value *= (v2 - v1);
+ value += v1;
+
+ return value;
+}
+
+#endif /* blop_interpolate_h */
diff --git a/src/include/lp4pole_filter.h b/src/include/lp4pole_filter.h
new file mode 100644
index 0000000..310fbbe
--- /dev/null
+++ b/src/include/lp4pole_filter.h
@@ -0,0 +1,137 @@
+/*
+ Header for lp4pole_filter struct, and functions to run instance.
+ Copyright 2011 David Robillard
+ Copyright 2003 Mike Rawes
+
+ Originally originally appeared in CSound as Timo Tossavainen's (sp?)
+ implementation from the Stilson/Smith CCRMA paper.
+
+ See http://musicdsp.org/archive.php?classid=3#26
+
+ Originally appeared in the arts softsynth by Stefan Westerfeld:
+ http://www.arts-project.org/
+
+ First ported to LADSPA by Reiner Klenk (pdq808[at]t-online.de)
+
+ Tuning and stability issues (output NaN) and additional audio-rate
+ variant added by Mike Rawes (mike_rawes[at]yahoo.co.uk)
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef blop_lp4pole_filter_h
+#define blop_lp4pole_filter_h
+
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+#include "common.h"
+
+typedef struct {
+ float f;
+ float coeff;
+ float fb;
+ float in1;
+ float in2;
+ float in3;
+ float in4;
+ float inv_nyquist;
+ float out1;
+ float out2;
+ float out3;
+ float out4;
+ float max_abs_in;
+} LP4PoleFilter;
+
+/**
+ Allocate a new LP4PoleFilter instance.
+ @param sample_rate Intended playback (DAC) rate
+ @return Allocated LP4PoleFilter instance
+*/
+LP4PoleFilter* lp4pole_new(double sample_rate);
+
+/**
+ Cleanup an existing LP4PoleFilter instance.
+ @param lpf Pointer to LP4PoleFilter instance allocated with initFilter
+*/
+void lp4pole_cleanup(LP4PoleFilter* lpf);
+
+/**
+ Initialise filter.
+ @param lpf Pointer to LP4PoleFilter instance allocated with initFilter
+*/
+void lp4pole_init(LP4PoleFilter* lpf);
+
+/**
+ Set up filter coefficients for given LP4Pole instance.
+ @param lpf Pointer to LP4PoleFilter instance
+ @param cutoff Cutoff frequency in Hz
+ @param resonance Resonance [Min=0.0, Max=4.0]
+*/
+static inline void
+lp4pole_set_params(LP4PoleFilter* lpf,
+ float cutoff,
+ float resonance)
+{
+ float fsqd;
+ float tuning;
+
+ /* Normalise cutoff and find tuning - Magic numbers found empirically :) */
+ lpf->f = cutoff * lpf->inv_nyquist;
+ tuning = f_clip(3.13f - (lpf->f * 4.24703592f), 1.56503274f, 3.13f);
+
+ /* Clip to bounds */
+ lpf->f = f_clip(lpf->f * tuning, lpf->inv_nyquist, 1.16f);
+
+ fsqd = lpf->f * lpf->f;
+ lpf->coeff = fsqd * fsqd * 0.35013f;
+
+ lpf->fb = f_clip(resonance, -1.3f, 4.0f) * (1.0f - 0.15f * fsqd);
+
+ lpf->f = 1.0f - lpf->f;
+}
+
+/**
+ Run given LP4PoleFilter instance for a single sample.
+ @param lpf Pointer to LP4PoleFilter instance
+ @param in Input sample
+ @return Filtered sample
+*/
+static inline float
+lp4pole_run(LP4PoleFilter* lpf,
+ float in)
+{
+ const float abs_in = fabsf(16.0f * in); /* ~24dB unclipped headroom */
+
+ lpf->max_abs_in = f_max(lpf->max_abs_in, abs_in);
+
+ in -= lpf->out4 * lpf->fb;
+ in *= lpf->coeff;
+
+ lpf->out1 = in + 0.3f * lpf->in1 + lpf->f * lpf->out1; /* Pole 1 */
+ lpf->in1 = in;
+ lpf->out2 = lpf->out1 + 0.3f * lpf->in2 + lpf->f * lpf->out2; /* Pole 2 */
+ lpf->in2 = lpf->out1;
+ lpf->out3 = lpf->out2 + 0.3f * lpf->in3 + lpf->f * lpf->out3; /* Pole 3 */
+ lpf->in3 = lpf->out2;
+ lpf->out4 = lpf->out3 + 0.3f * lpf->in4 + lpf->f * lpf->out4; /* Pole 4 */
+ lpf->in4 = lpf->out3;
+
+ /* Simple hard clip to prevent NaN */
+ lpf->out4 = f_clip(lpf->out4, -lpf->max_abs_in, lpf->max_abs_in);
+
+ lpf->max_abs_in *= 0.999f;
+
+ return lpf->out4;
+}
+
+#endif /* blop_lp4pole_filter_h */
diff --git a/src/include/math_func.h b/src/include/math_func.h
new file mode 100644
index 0000000..60f7ce0
--- /dev/null
+++ b/src/include/math_func.h
@@ -0,0 +1,48 @@
+/*
+ * Provide double fallbacks for environments lacking sinf and
+ * friends (e.g. Solaris)
+ */
+
+#ifndef math_func_h
+#define math_func_h
+
+#include <math.h>
+#include "blop_config.h"
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846 /* pi */
+#endif
+
+#ifndef M_LN10
+# define M_LN10 2.30258509299404568402 /* log_e(10) */
+#endif
+
+#ifndef M_LN2
+# define M_LN2 0.69314718055994530942 /* log_e(2) */
+#endif
+
+#ifdef HAVE_SINF
+/* Use float functions */
+#define SINF(x) sinf(x)
+#define COSF(x) cosf(x)
+#define FABSF(x) fabsf(x)
+#define FLOORF(x) floorf(x)
+#define EXPF(x) expf(x)
+#define POWF(x,p) powf(x,p)
+#define COPYSIGNF(s,d) copysignf(s,d)
+#define LRINTF(x) lrintf(x)
+
+#else
+/* Use double functions */
+#define SINF(x) sin(x)
+#define COSF(x) cos(x)
+#define FABSF(x) fabs(x)
+#define FLOORF(x) floor(x)
+#define EXPF(x) exp(x)
+#define POWF(x,p) pow(x)
+#define COPYSIGNF(s,d) copysign(s,d)
+#define LRINTF(x) lrint(x)
+
+#endif
+
+#endif
diff --git a/src/include/uris.h b/src/include/uris.h
new file mode 100644
index 0000000..0c35628
--- /dev/null
+++ b/src/include/uris.h
@@ -0,0 +1,59 @@
+/*
+ Common URIs used by plugins.
+ Copyright 2012 David Robillard
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef blop_uris_h
+#define blop_uris_h
+
+#include <string.h>
+#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
+#include "lv2/lv2plug.in/ns/ext/morph/morph.h"
+#include "lv2/lv2plug.in/ns/ext/urid/urid.h"
+#include "lv2/lv2plug.in/ns/lv2core/lv2.h"
+
+typedef struct {
+ LV2_URID atom_URID;
+ LV2_URID lv2_AudioPort;
+ LV2_URID lv2_CVPort;
+ LV2_URID lv2_ControlPort;
+ LV2_URID morph_currentType;
+} URIs;
+
+static inline void
+map_uris(URIs* uris,
+ const LV2_Feature* const* features)
+{
+ LV2_URID_Map* map = NULL;
+ for (int i = 0; features[i]; ++i) {
+ if (!strcmp(features[i]->URI, LV2_URID__map)) {
+ map = (LV2_URID_Map*)features[i]->data;
+ break;
+ }
+ }
+
+ if (map) {
+ uris->atom_URID = map->map(map->handle, LV2_ATOM__URID);
+ uris->lv2_AudioPort = map->map(map->handle, LV2_CORE__AudioPort);
+ uris->lv2_CVPort = map->map(map->handle, LV2_CORE__CVPort);
+ uris->lv2_ControlPort = map->map(map->handle, LV2_CORE__ControlPort);
+ uris->morph_currentType = map->map(map->handle, LV2_MORPH__currentType);
+ } else {
+ memset(uris, 0, sizeof(*uris));
+ }
+}
+
+#endif /* blop_uris_h */
diff --git a/src/include/vector_op.h b/src/include/vector_op.h
new file mode 100644
index 0000000..f261ff8
--- /dev/null
+++ b/src/include/vector_op.h
@@ -0,0 +1,44 @@
+/*
+ Apply a C arithmetical operator to two sample buffers.
+ Copyright 2012-2014 David Robillard
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BLOP_VECTOR_OP_H
+#define BLOP_VECTOR_OP_H
+
+#define VECTOR_OP(op, output, input1, input1_is_cv, input2, input2_is_cv) \
+ switch ((input1_is_cv << 1) + input2_is_cv) { \
+ case 0: /* 00 (control * control) */ \
+ output[0] = input1[0] op input2[0]; \
+ break; \
+ case 1: /* 01 (control * cv) */ \
+ for (uint32_t s = 0; s < sample_count; ++s) { \
+ output[s] = input1[0] op input2[s]; \
+ } \
+ break; \
+ case 2: /* 10 (cv * control) */ \
+ for (uint32_t s = 0; s < sample_count; ++s) { \
+ output[s] = input1[s] op input2[0]; \
+ } \
+ break; \
+ case 3: /* 11 (cv * cv) */ \
+ for (uint32_t s = 0; s < sample_count; ++s) { \
+ output[s] = input1[s] op input2[s]; \
+ } \
+ break; \
+ }
+
+#endif /* BLOP_VECTOR_OP_H */
diff --git a/src/include/wavedata.h b/src/include/wavedata.h
new file mode 100644
index 0000000..97b2986
--- /dev/null
+++ b/src/include/wavedata.h
@@ -0,0 +1,193 @@
+/*
+ Structures to represent a set of wavetables.
+ Copyright 2011 David Robillard
+ Copyright 2003 Mike Rawes
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef blop_wavedata_h
+#define blop_wavedata_h
+
+#include "blop_config.h"
+#include "math_func.h"
+#include "interpolate.h"
+#include "common.h"
+
+/* Functions identifying wavedata dlls */
+#define BLOP_DLSYM_SAWTOOTH "blop_get_sawtooth"
+#define BLOP_DLSYM_SQUARE "blop_get_square"
+#define BLOP_DLSYM_PARABOLA "blop_get_parabola"
+
+/*
+ * Structure holding a single segment of sample data
+ * along with information relating to playback.
+ */
+typedef struct {
+ unsigned long sample_count; /* Sample count */
+ float* samples_lf; /* Sample data played back at amplitude
+ inversely proportional to frequency */
+ float* samples_hf; /* Sample data played back at amplitude
+ proportional to frequency */
+ unsigned long harmonics; /* Max harmonic content of sample data */
+
+ float phase_scale_factor; /* Phase scale factor for playback */
+ float min_frequency; /* Minimum playback frequency */
+ float max_frequency; /* Maximum playback frequency */
+ float range_scale_factor; /* Blend scale factor for cross fading */
+} Wavetable;
+
+/*
+ * Structure holding the wavetable data and playback state
+ */
+typedef struct {
+ void* data_handle; /* Data DLL handle */
+ unsigned long table_count; /* Number of wavetables in wavedata */
+ Wavetable** tables; /* One or more wavetables, plus pair of
+ extra tables for frequency extremes */
+ unsigned long* lookup; /* Wavetable lookup vector */
+ unsigned long lookup_max; /* For clipping lookup indices */
+
+ float sample_rate; /* Sample rate */
+ float nyquist; /* Nyquist rate (sample_rate / 2) */
+
+ /* Playback state */
+ float frequency; /* Current playback frequency */
+ float abs_freq; /* Absolute playback frequency */
+ float xfade; /* Crossfade factor for fading */
+ Wavetable* table; /* Wavetable to playback */
+} Wavedata;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int wavedata_load(Wavedata* w,
+ const char* bundle_path,
+ const char* lib_name,
+ const char* wdat_descriptor_name,
+ double sample_rate);
+
+void wavedata_unload(Wavedata* w);
+
+/*****************************************************************************
+ * Description: Get interpolated sample from current wavetable in wavedata
+ * at given phase offset
+ *
+ * Arguments: w Wavedata containing playback state and data
+ * phase Phase offset [0.0, sample_rate]
+ *
+ * Returns: Interpolated sample
+ *
+ * Notes: Cubic (or quintic) interpolation requires four consecutive
+ * samples for operation:
+ *
+ * phase
+ * :
+ * p1 p0 : n0 n1
+ * | | x | |
+ * : :
+ * <-o->
+ * :
+ * interval
+ *
+ * Phase values less than one make p0 the first sample in
+ * the table - p1 will be the last sample, as a previous
+ * sample does not exist. To avoid checking for this case,
+ * a copy of the last sample is stored before the first
+ * sample in each table.
+ * Likewise, if the phase means p0 is the last sample, n0
+ * and n1 will be the first and second samples respectively.
+ * Copies of these samples are stored after the last sample
+ * in each table.
+ *
+ *****************************************************************************/
+static inline float
+wavedata_get_sample(Wavedata* w,
+ float phase)
+{
+ float* samples_hf = w->table->samples_hf;
+ float* samples_lf = w->table->samples_lf;
+ float p1, p0, n0, n1;
+ float phase_f;
+ long int index;
+
+ /* Scale phase to map to position in wavetable */
+ phase *= w->table->phase_scale_factor;
+
+ /* Get position of first contributing sample (p1) */
+ index = LRINTF((float)phase - 0.5f);
+ phase_f = (float)index;
+
+ index %= w->table->sample_count;
+
+ /* Cross-fade table pairs */
+ /* Previous two samples */
+ p1 = w->xfade * (samples_lf[index] - samples_hf[index]) + samples_hf[index];
+ index++;
+ p0 = w->xfade * (samples_lf[index] - samples_hf[index]) + samples_hf[index];
+ index++;
+ /* Next two samples */
+ n0 = w->xfade * (samples_lf[index] - samples_hf[index]) + samples_hf[index];
+ index++;
+ n1 = w->xfade * (samples_lf[index] - samples_hf[index]) + samples_hf[index];
+
+ /* Return interpolated sample */
+ return interpolate_cubic(phase - phase_f, p1, p0, n0, n1);
+}
+
+/*****************************************************************************
+ * Description: Get wavetable to use for playback frequency.
+ *
+ * Arguments: w Wavedata object (contains all table info)
+ * frequency Playback frequency
+ *
+ * Notes: The lookup vector used to determine the wavetable
+ * is indexed by harmonic number.
+ *
+ * The maximum playback frequency for a wavetable is
+ * determined by its harmonic content and the sample rate,
+ * and equals sample_rate / 2 / max_harmonic_in_table.
+ *
+ *****************************************************************************/
+static inline void
+wavedata_get_table(Wavedata* w,
+ float frequency)
+{
+ unsigned long harmonic;
+
+ w->frequency = frequency;
+ w->abs_freq = (float)FABSF((float)frequency);
+
+ /* Get highest harmonic possible in frequency */
+ harmonic = LRINTF(w->nyquist / w->abs_freq - 0.5f);
+
+ /* Clip so lookup is within bounds */
+ if (harmonic > w->lookup_max) {
+ harmonic = w->lookup_max;
+ }
+
+ /* Set playback table */
+ w->table = w->tables[w->lookup[harmonic]];
+
+ /* Get cross fade factor */
+ w->xfade = f_max(w->table->max_frequency - w->abs_freq, 0.0f) * w->table->range_scale_factor;
+ w->xfade = f_min(w->xfade, 1.0f);
+}
+
+#ifdef __cplusplus
+} /* extern "C" { */
+#endif
+
+#endif /* blop_wavedata_h */
diff --git a/src/include/wdatutil.h b/src/include/wdatutil.h
new file mode 100644
index 0000000..9a0810a
--- /dev/null
+++ b/src/include/wdatutil.h
@@ -0,0 +1,141 @@
+/*
+ Code to generate wavedata dl containing pre-calculated wavetables.
+ Copyright 2011 David Robillard
+ Copyright 2003 Mike Rawes
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This software is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this software. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef blop_wdatutil_h
+#define blop_wdatutil_h
+
+#include <stdio.h>
+#include <stdint.h>
+#include "math_func.h"
+#include "wavedata.h"
+
+#define WAVE_TYPE_COUNT 3
+
+extern const char* wave_names[];
+extern const char* wave_descriptions[];
+extern unsigned long wave_first_harmonics[];
+extern unsigned long wave_harmonic_intervals[];
+
+/** Get actual maximum harmonic from given harmonic, h, and wavetype, w */
+#define ACTUAL_HARM(h, w) h - (h - wave_first_harmonics[w]) % wave_harmonic_intervals[w]
+
+/** Get minimum harmonic content in given wavetype, w */
+#define MIN_HARM(w) wave_first_harmonics[w]
+
+/** Get minimum extra harmonic content possible in given wavetype, w */
+#define MIN_EXTRA_HARM(w) wave_harmonic_intervals[w]
+
+/** Get frequency from MIDI note, n */
+#define FREQ_FROM_NOTE(n) 6.875f * POWF(2.0f, (float)(n + 3) / 12.0f)
+
+/** Get max harmonic from given frequency, f, at sample rate, r */
+#define HARM_FROM_FREQ(f, r) (unsigned long)((float)r / f / 2.0f)
+
+/*
+ * A single wavetable will have a range of pitches at which their samples
+ * may be played back.
+ *
+ * The upper bound is determined by the maximum harmonic present in the
+ * waveform - above this frequency, the higher harmonics will alias.
+ *
+ * The lower bound is chosen to be the higher bound of the previous wavetable
+ * (or a pre-defined limit if there is no such table).
+ */
+
+typedef enum {
+ SAW,
+ SQUARE,
+ PARABOLA
+} Wavetype;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*******************************************************************************
+ * Description: Allocate new wavedata struct
+ *
+ * Arguments: sample_rate Sample rate to use when generating data
+ *
+ * Returns: Pointer to wavedata on success
+ * NULL (0) on failure
+ *
+ * Notes: No wavetables are allocated. Use wavedata_add_table
+ ******************************************************************************/
+Wavedata* wavedata_new(double sample_rate);
+
+/*******************************************************************************
+ * Description: Destroy allocated wavedata and any tables
+ *
+ * Arguments: w Wavedata struct to cleanup
+ ******************************************************************************/
+void wavedata_cleanup(Wavedata* w);
+
+/*******************************************************************************
+ * Description: Add new wavetable information to wavedata file object
+ *
+ * Arguments: w Wavedata to add table to
+ * sample_count Number of samples in wavetable
+ * harmonics Maximum harmonics present in table
+ *
+ * Returns: 0 on success
+ * -1 otherwise
+ ******************************************************************************/
+int wavedata_add_table(Wavedata* w,
+ uint32_t sample_count,
+ unsigned long harmonics);
+
+/*******************************************************************************
+ * Description: Initialise all wavetables in wavedata with a waveform
+ * generated from Fourier series.
+ *
+ * Arguments: w Wavedata to generate data for
+ * wavetype Wavetype to generate
+ * gibbs_comp Compensation for Gibbs' effect:
+ * 0.0: none (wave will overshoot)
+ * 1.0: full (wave will not overshoot)
+ *
+ * Notes: Compensation for Gibbs' Effect will reduce the degree
+ * of overshoot and ripple at the transitions. A value of 1.0
+ * will pretty much eliminate it.
+ ******************************************************************************/
+void wavedata_generate_tables(Wavedata* w,
+ Wavetype wavetype,
+ float gibbs_comp);
+
+/*******************************************************************************
+ * Description: Write wavedata as a c header file
+ *
+ * Arguments: w Wavedata to write
+ * wdat_fp Pointer to output file
+ * prefix Prefix to use in declarations. If this is null
+ * declarations are prefixed with 'wdat'.
+ *
+ * Returns: 0 on success
+ * -1 otherwise
+ ******************************************************************************/
+int wavedata_write(Wavedata* w,
+ FILE* wdat_fp,
+ const char* prefix);
+
+#ifdef __cplusplus
+} /* extern "C" { */
+#endif
+
+#endif /* blop_wdatutil_h */