diff --git a/Frameworks/playptmod/playptmod.xcodeproj/project.pbxproj b/Frameworks/playptmod/playptmod.xcodeproj/project.pbxproj index be7e62b0f..9022d9648 100644 --- a/Frameworks/playptmod/playptmod.xcodeproj/project.pbxproj +++ b/Frameworks/playptmod/playptmod.xcodeproj/project.pbxproj @@ -7,19 +7,19 @@ objects = { /* Begin PBXBuildFile section */ + 83304C9B1A5F9A1C0066CDDA /* pt_blep.c in Sources */ = {isa = PBXBuildFile; fileRef = 83304C991A5F9A1C0066CDDA /* pt_blep.c */; }; + 83304C9C1A5F9A1C0066CDDA /* pt_blep.h in Headers */ = {isa = PBXBuildFile; fileRef = 83304C9A1A5F9A1C0066CDDA /* pt_blep.h */; }; 83A0F4A61816CEAD00119DB4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 83A0F4A41816CEAD00119DB4 /* InfoPlist.strings */; }; - 83A0F4D31816CF9500119DB4 /* blip_buf.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A0F4CF1816CF9500119DB4 /* blip_buf.c */; }; - 83A0F4D41816CF9500119DB4 /* blip_buf.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A0F4D01816CF9500119DB4 /* blip_buf.h */; settings = {ATTRIBUTES = (Public, ); }; }; 83A0F4D51816CF9500119DB4 /* playptmod.c in Sources */ = {isa = PBXBuildFile; fileRef = 83A0F4D11816CF9500119DB4 /* playptmod.c */; }; 83A0F4D61816CF9500119DB4 /* playptmod.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A0F4D21816CF9500119DB4 /* playptmod.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 83304C991A5F9A1C0066CDDA /* pt_blep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pt_blep.c; sourceTree = ""; }; + 83304C9A1A5F9A1C0066CDDA /* pt_blep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pt_blep.h; sourceTree = ""; }; 83A0F4981816CEAD00119DB4 /* playptmod.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = playptmod.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 83A0F4A31816CEAD00119DB4 /* playptmod-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "playptmod-Info.plist"; sourceTree = ""; }; 83A0F4A51816CEAD00119DB4 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 83A0F4CF1816CF9500119DB4 /* blip_buf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = blip_buf.c; sourceTree = ""; }; - 83A0F4D01816CF9500119DB4 /* blip_buf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = blip_buf.h; sourceTree = ""; }; 83A0F4D11816CF9500119DB4 /* playptmod.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = playptmod.c; sourceTree = ""; }; 83A0F4D21816CF9500119DB4 /* playptmod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playptmod.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -70,8 +70,8 @@ 83A0F4A11816CEAD00119DB4 /* playptmod */ = { isa = PBXGroup; children = ( - 83A0F4CF1816CF9500119DB4 /* blip_buf.c */, - 83A0F4D01816CF9500119DB4 /* blip_buf.h */, + 83304C991A5F9A1C0066CDDA /* pt_blep.c */, + 83304C9A1A5F9A1C0066CDDA /* pt_blep.h */, 83A0F4D11816CF9500119DB4 /* playptmod.c */, 83A0F4D21816CF9500119DB4 /* playptmod.h */, 83A0F4A21816CEAD00119DB4 /* Supporting Files */, @@ -95,8 +95,8 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 83A0F4D41816CF9500119DB4 /* blip_buf.h in Headers */, 83A0F4D61816CF9500119DB4 /* playptmod.h in Headers */, + 83304C9C1A5F9A1C0066CDDA /* pt_blep.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -163,8 +163,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 83304C9B1A5F9A1C0066CDDA /* pt_blep.c in Sources */, 83A0F4D51816CF9500119DB4 /* playptmod.c in Sources */, - 83A0F4D31816CF9500119DB4 /* blip_buf.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Frameworks/playptmod/playptmod/blip_buf.c b/Frameworks/playptmod/playptmod/blip_buf.c deleted file mode 100644 index 337a115a4..000000000 --- a/Frameworks/playptmod/playptmod/blip_buf.c +++ /dev/null @@ -1,196 +0,0 @@ -/* blip_buf 1.1.0. http://www.slack.net/~ant/ */ - -#include "blip_buf.h" - -#include -#include -#include - -/* Library Copyright (C) 2003-2009 Shay Green. This library is free software; -you can redistribute it and/or modify it under the terms of the GNU Lesser -General Public License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. This -library 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 Lesser General Public License for more -details. You should have received a copy of the GNU Lesser General Public -License along with this module; if not, write to the Free Software Foundation, -Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#if defined (BLARGG_TEST) && BLARGG_TEST - #include "blargg_test.h" -#endif - -enum { time_bits = pre_shift + 20 }; - -static fixed_t const time_unit = (fixed_t) 1 << time_bits; - -enum { bass_shift = 9 }; /* affects high-pass filter breakpoint frequency */ -enum { end_frame_extra = 2 }; /* allows deltas slightly after frame length */ - -enum { half_width = 8 }; -enum { buf_extra = half_width*2 + end_frame_extra }; -enum { phase_bits = 5 }; -enum { phase_count = 1 << phase_bits }; -enum { delta_bits = 15 }; -enum { delta_unit = 1 << delta_bits }; -enum { frac_bits = time_bits - pre_shift }; - -/* We could eliminate avail and encode whole samples in offset, but that would -limit the total buffered samples to blip_max_frame. That could only be -increased by decreasing time_bits, which would reduce resample ratio accuracy. -*/ - -/* probably not totally portable */ -#define SAMPLES( buf ) (buf->samples) - -/* Arithmetic (sign-preserving) right shift */ -#define ARITH_SHIFT( n, shift ) \ - ((n) >> (shift)) - -enum { max_sample = +32767 }; -enum { min_sample = -32768 }; - -#define CLAMP( n ) \ - {\ - if ( (short) n != n )\ - n = ARITH_SHIFT( n, 16 ) ^ max_sample;\ - } - -void ptm_blip_clear( blip_t* m ) -{ - /* We could set offset to 0, factor/2, or factor-1. 0 is suitable if - factor is rounded up. factor-1 is suitable if factor is rounded down. - Since we don't know rounding direction, factor/2 accommodates either, - with the slight loss of showing an error in half the time. Since for - a 64-bit factor this is years, the halving isn't a problem. */ - - m->offset = time_unit / 2; - m->index = 0; - m->integrator = 0; - m->last_value = 0; - memset( SAMPLES( m ), 0, 128 * sizeof (buf_t) ); -} - -int ptm_blip_read_sample( blip_t* m ) -{ - int retval; - - { - buf_t * in = SAMPLES( m ) + m->index; - int sum = m->integrator; - { - /* Eliminate fraction */ - int s = ARITH_SHIFT( sum, delta_bits ); - - sum += *in; - - retval = s; - } - m->integrator = sum; - - *in = 0; - - m->index = ( m->index + 1 ) % 128; - } - - return retval; -} - -/* Things that didn't help performance on x86: - __attribute__((aligned(128))) - #define short int - restrict -*/ - -static int const bl_step [phase_count + 1] [half_width] = -{ -{ 0, 0, 0, 0, 0, 0, 0,32768}, -{ -1, 9, -30, 79, -178, 380, -923,32713}, -{ -2, 17, -58, 153, -346, 739,-1775,32549}, -{ -3, 24, -83, 221, -503, 1073,-2555,32277}, -{ -4, 30, -107, 284, -647, 1382,-3259,31898}, -{ -5, 36, -127, 340, -778, 1662,-3887,31415}, -{ -5, 40, -145, 390, -895, 1913,-4439,30832}, -{ -6, 44, -160, 433, -998, 2133,-4914,30151}, -{ -6, 47, -172, 469,-1085, 2322,-5313,29377}, -{ -6, 49, -181, 499,-1158, 2479,-5636,28515}, -{ -6, 50, -188, 521,-1215, 2604,-5885,27570}, -{ -5, 51, -193, 537,-1257, 2697,-6063,26548}, -{ -5, 51, -195, 547,-1285, 2760,-6172,25455}, -{ -5, 50, -195, 550,-1298, 2792,-6214,24298}, -{ -4, 49, -192, 548,-1298, 2795,-6193,23084}, -{ -4, 47, -188, 540,-1284, 2770,-6112,21820}, -{ -3, 45, -182, 526,-1258, 2719,-5976,20513}, -{ -3, 42, -175, 508,-1221, 2643,-5788,19172}, -{ -2, 39, -166, 486,-1173, 2544,-5554,17805}, -{ -2, 36, -156, 460,-1116, 2425,-5277,16418}, -{ -1, 33, -145, 431,-1050, 2287,-4963,15020}, -{ -1, 30, -133, 399, -977, 2132,-4615,13618}, -{ -1, 26, -120, 365, -898, 1963,-4240,12221}, -{ 0, 23, -107, 329, -813, 1783,-3843,10836}, -{ 0, 20, -94, 292, -725, 1593,-3427, 9470}, -{ 0, 17, -81, 254, -633, 1396,-2998, 8131}, -{ 0, 14, -68, 215, -540, 1194,-2560, 6824}, -{ 0, 11, -56, 177, -446, 989,-2119, 5556}, -{ 0, 8, -43, 139, -353, 784,-1678, 4334}, -{ 0, 6, -31, 102, -260, 581,-1242, 3162}, -{ 0, 3, -20, 66, -170, 381, -814, 2046}, -{ 0, 1, -9, 32, -83, 187, -399, 991}, -{ 0, 0, 0, 0, 0, 0, 0, 0} -}; - -/* Shifting by pre_shift allows calculation using unsigned int rather than -possibly-wider fixed_t. On 32-bit platforms, this is likely more efficient. -And by having pre_shift 32, a 32-bit platform can easily do the shift by -simply ignoring the low half. */ - -void ptm_blip_add_delta( blip_t* m, float time, int delta ) -{ - unsigned fixed = (unsigned) ((int)(time * time_unit + m->offset) >> pre_shift); - buf_t* out = SAMPLES( m ) + (m->index + (fixed >> frac_bits)) % 128; - buf_t* end = SAMPLES( m ) + 128; - - int const phase_shift = frac_bits - phase_bits; - int phase = fixed >> phase_shift & (phase_count - 1); - int const* in = bl_step [phase]; - int const* rev = bl_step [phase_count - phase]; - - int interp = fixed >> (phase_shift - delta_bits) & (delta_unit - 1); - int delta2 = (delta * interp) >> delta_bits; - delta -= delta2; - - *out++ += in[0]*delta + in[half_width+0]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[1]*delta + in[half_width+1]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[2]*delta + in[half_width+2]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[3]*delta + in[half_width+3]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[4]*delta + in[half_width+4]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[5]*delta + in[half_width+5]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[6]*delta + in[half_width+6]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[7]*delta + in[half_width+7]*delta2; - if (out >= end) out = SAMPLES( m ); - - in = rev; - *out++ += in[7]*delta + in[7-half_width]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[6]*delta + in[6-half_width]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[5]*delta + in[5-half_width]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[4]*delta + in[4-half_width]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[3]*delta + in[3-half_width]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[2]*delta + in[2-half_width]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[1]*delta + in[1-half_width]*delta2; - if (out >= end) out = SAMPLES( m ); - *out++ += in[0]*delta + in[0-half_width]*delta2; -} diff --git a/Frameworks/playptmod/playptmod/blip_buf.h b/Frameworks/playptmod/playptmod/blip_buf.h deleted file mode 100644 index c772f8959..000000000 --- a/Frameworks/playptmod/playptmod/blip_buf.h +++ /dev/null @@ -1,72 +0,0 @@ -/** \file -Sample buffer that resamples from input clock rate to output sample rate */ - -/* blip_buf 1.1.0 */ -#ifndef BLIP_BUF_H -#define BLIP_BUF_H - -#include - -/* Equivalent to ULONG_MAX >= 0xFFFFFFFF00000000. -Avoids constants that don't fit in 32 bits. */ -#if ULONG_MAX/0xFFFFFFFF > 0xFFFFFFFF - typedef unsigned long fixed_t; - enum { pre_shift = 32 }; - -#elif defined(ULLONG_MAX) - typedef unsigned long long fixed_t; - enum { pre_shift = 32 }; - -#else - typedef unsigned fixed_t; - enum { pre_shift = 0 }; - -#endif - -typedef int buf_t; - -/** Sample buffer that resamples to output rate and accumulates samples -until they're read out */ -struct blip_t -{ - fixed_t offset; - int index; - int avail; - int size; - int integrator; - int last_value; - buf_t samples[128]; -}; - -#ifdef __cplusplus - extern "C" { -#endif - -/** First parameter of most functions is blip_t*, or const blip_t* if nothing -is changed. */ -typedef struct blip_t blip_t; - -/** Clears entire buffer. Afterwards, blip_samples_avail() == 0. */ -void ptm_blip_clear( blip_t* ); - -/** Adds positive/negative delta into buffer at specified clock time. */ -void ptm_blip_add_delta( blip_t*, float clock_time, int delta ); - -/** Number of buffered samples available for reading. */ -int ptm_blip_samples_avail( const blip_t* ); - -/** Reads and removes at most 'count' samples and writes them to 'out'. If -'stereo' is true, writes output to every other element of 'out', allowing easy -interleaving of two buffers into a stereo sample stream. Outputs 16-bit signed -samples. Returns number of samples actually read. */ -int ptm_blip_read_sample( blip_t* ); - - -/* Deprecated */ -typedef blip_t blip_buffer_t; - -#ifdef __cplusplus - } -#endif - -#endif diff --git a/Frameworks/playptmod/playptmod/playptmod.c b/Frameworks/playptmod/playptmod/playptmod.c index a353535c6..6501019e6 100644 --- a/Frameworks/playptmod/playptmod/playptmod.c +++ b/Frameworks/playptmod/playptmod/playptmod.c @@ -29,11 +29,12 @@ #define _USE_MATH_DEFINES // visual studio #include "playptmod.h" -#include "blip_buf.h" +#include "pt_blep.h" #include #include // memcpy() #include // malloc(), calloc(), free() +#include // INT_MAX, INT_MIN #include // floorf(), sinf() #define HI_NYBBLE(x) ((x) >> 4) @@ -240,8 +241,8 @@ typedef struct FilterC filterC; float *mixBufferL; float *mixBufferR; - blip_t blep[MAX_CHANNELS]; - blip_t blepVol[MAX_CHANNELS]; + BLEP blep[MAX_CHANNELS]; + BLEP blepVol[MAX_CHANNELS]; unsigned int orderPlayed[256]; MODULE *source; } player; @@ -524,8 +525,8 @@ static void mixerCutChannels(player *p) memset(p->v, 0, sizeof (p->v)); for (i = 0; i < MAX_CHANNELS; ++i) { - ptm_blip_clear(&p->blep[i]); - ptm_blip_clear(&p->blepVol[i]); + memset(&p->blep[i], 0, sizeof(BLEP)); + memset(&p->blepVol[i], 0, sizeof(BLEP)); } memset(&p->filter, 0, sizeof (p->filter)); @@ -564,8 +565,8 @@ static void outputAudio(player *p, int *target, int numSamples) float downscale; Voice *v; - blip_t *bSmp; - blip_t *bVol; + BLEP *bSmp; + BLEP *bVol; memset(p->mixBufferL, 0, numSamples * sizeof (float)); memset(p->mixBufferR, 0, numSamples * sizeof (float)); @@ -594,8 +595,8 @@ static void outputAudio(player *p, int *target, int numSamples) if (v->data) v->frac -= 1.0f; - t_vol += ptm_blip_read_sample(bVol); - t_smp += ptm_blip_read_sample(bSmp); + t_vol += blepRun(bVol); + t_smp += blepRun(bSmp); t_smp *= t_vol; i_smp = (signed int)t_smp; @@ -609,18 +610,18 @@ static void outputAudio(player *p, int *target, int numSamples) if (j >= numSamples) break; - if (tempSample != bSmp->last_value) + if (tempSample != bSmp->lastInput && v->frac >= 0.0f && v->frac < 1.0f) { - delta = tempSample - bSmp->last_value; - bSmp->last_value = tempSample; - ptm_blip_add_delta(bSmp, v->frac, delta); + delta = tempSample - bSmp->lastInput; + bSmp->lastInput = tempSample; + blepAdd(bSmp, v->frac, delta); } - if (tempVolume != bVol->last_value) + if (tempVolume != bVol->lastInput) { - delta = tempVolume - bVol->last_value; - bVol->last_value = tempVolume; - ptm_blip_add_delta(bVol, 0, delta); + delta = tempVolume - bVol->lastInput; + bVol->lastInput = tempVolume; + blepAdd(bVol, 0, delta); } if (v->data) @@ -696,11 +697,11 @@ static void outputAudio(player *p, int *target, int numSamples) { for (; j < numSamples; ++j) { - tempVolume = bVol->last_value; - tempSample = bSmp->last_value; + tempVolume = 0.0f; + tempSample = 0.0f; - tempVolume += ptm_blip_read_sample(bVol); - tempSample += ptm_blip_read_sample(bSmp); + tempVolume += blepRun(bVol); + tempSample += blepRun(bSmp); tempSample *= tempVolume; i_smp = (signed int)tempSample; diff --git a/Frameworks/playptmod/playptmod/pt_blep.c b/Frameworks/playptmod/playptmod/pt_blep.c new file mode 100644 index 000000000..6cbab3e80 --- /dev/null +++ b/Frameworks/playptmod/playptmod/pt_blep.c @@ -0,0 +1,93 @@ +/* +** This file is part of the ProTracker 2.3D port/clone +** project by Olav "8bitbubsy" Sorensen. +** +** It contains unstructured and unclean code, but I care +** more about how the program works than how the source +** code looks. Although, I do respect coders that can +** master the art of writing clean and structured code. +** I know I can't. +** +** All of the files are considered 'public domain', +** do whatever you want with it. +** +*/ + +#include +#include "pt_blep.h" + +#define _LERP(I, F) ((I[0]) + ((I[1]) - (I[0])) * (F)) + +static const uint32_t blepData[48] = +{ + 0x3F7FE1F1, 0x3F7FD548, 0x3F7FD6A3, 0x3F7FD4E3, + 0x3F7FAD85, 0x3F7F2152, 0x3F7DBFAE, 0x3F7ACCDF, + 0x3F752F1E, 0x3F6B7384, 0x3F5BFBCB, 0x3F455CF2, + 0x3F26E524, 0x3F0128C4, 0x3EACC7DC, 0x3E29E86B, + 0x3C1C1D29, 0xBDE4BBE6, 0xBE3AAE04, 0xBE48DEDD, + 0xBE22AD7E, 0xBDB2309A, 0xBB82B620, 0x3D881411, + 0x3DDADBF3, 0x3DE2C81D, 0x3DAAA01F, 0x3D1E769A, + 0xBBC116D7, 0xBD1402E8, 0xBD38A069, 0xBD0C53BB, + 0xBC3FFB8C, 0x3C465FD2, 0x3CEA5764, 0x3D0A51D6, + 0x3CEAE2D5, 0x3C92AC5A, 0x3BE4CBF7, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000 +}; + +void blepAdd(BLEP *b, float offset, float amplitude) +{ + int8_t n; + + uint32_t i; + + const float *src; + float f; + float a; + + float k[NS]; + + n = NS; + i = (uint32_t)(offset * SP); + src = (const float *)(blepData) + i + OS; + f = (offset * SP) - i; + i = b->index; + a = 0.0f; + + while (n--) + { + a += k[n] = _LERP(src, f); + src += SP; + } + + n = NS; + a = 1.0f / a; + + while (n--) + { + b->buffer[i] += (amplitude * k[n]) * a; + + i++; + i &= RNS; + } + + b->samplesLeft = NS; +} + +float blepRun(BLEP *b) +{ + float output; + + output = b->buffer[b->index]; + b->buffer[b->index] = 0.0f; + + b->index++; + b->index &= RNS; + + b->samplesLeft--; + + output += b->lastOutput; + b->lastOutput = output; + + return (output); +} + diff --git a/Frameworks/playptmod/playptmod/pt_blep.h b/Frameworks/playptmod/playptmod/pt_blep.h new file mode 100644 index 000000000..29538c617 --- /dev/null +++ b/Frameworks/playptmod/playptmod/pt_blep.h @@ -0,0 +1,55 @@ +/* +** This file is part of the ProTracker 2.3D port/clone +** project by Olav "8bitbubsy" Sorensen. +** +** It contains unstructured and unclean code, but I care +** more about how the program works than how the source +** code looks. Although, I do respect coders that can +** master the art of writing clean and structured code. +** I know I can't. +** +** All of the files are considered 'public domain', +** do whatever you want with it. +** +*/ + +#ifndef __PT_BLEP_H +#define __PT_BLEP_H + +#include + +// thanks to aciddose/ad/adejr for the blep/cutoff/filter stuff! + +// information on blep variables +// +// ZC = zero crossings, the number of ripples in the impulse +// OS = oversampling, how many samples per zero crossing are taken +// SP = step size per output sample, used to lower the cutoff (play the impulse slower) +// NS = number of samples of impulse to insert +// RNS = the lowest power of two greater than NS, minus one (used to wrap output buffer) +// +// ZC and OS are here only for reference, they depend upon the data in the table and can't be changed. +// SP, the step size can be any number lower or equal to OS, as long as the result NS remains an integer. +// for example, if ZC=8,OS=5, you can set SP=1, the result is NS=40, and RNS must then be 63. +// the result of that is the filter cutoff is set at nyquist * (SP/OS), in this case nyquist/5. + +#define ZC 8 +#define OS 5 +#define SP 5 +#define NS (ZC * OS / SP) +#define RNS 7 // RNS = (2^ > NS) - 1 + +typedef struct blep_data +{ + int32_t index; + int32_t samplesLeft; + float buffer[RNS + 1]; + float lastInput; + float lastOutput; +} BLEP; + +void blepAdd(BLEP *b, float offset, float amplitude); +float blepRun(BLEP *b); + +#endif +