Import existing source tree; original VCS history is no longer available. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
590 lines
12 KiB
C
590 lines
12 KiB
C
/*(LGPL)
|
|
---------------------------------------------------------------------------
|
|
a_wcaosc.h - Oscillators for the Wave Construction API
|
|
---------------------------------------------------------------------------
|
|
* Copyright (C) 2002, David Olofson
|
|
*
|
|
* This program 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 program 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 program; if not, write to the Free Software Foundation,
|
|
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
/*
|
|
* Not a "real" header - it just looks like one to great extent. ;-)
|
|
* It is best seen as a huge macro.
|
|
*/
|
|
|
|
static unsigned int rnd = 16576;
|
|
|
|
//Resets the noise generator
|
|
static void noise_reset(void)
|
|
{
|
|
rnd = 16576;
|
|
}
|
|
|
|
//Returns a pseudo random number in the range [-1.0, 1.0]
|
|
static inline float noise(void)
|
|
{
|
|
int out;
|
|
rnd *= 1566083941UL;
|
|
rnd++;
|
|
rnd &= 0xffffffffUL; /* NOP on 32 bit machines */
|
|
out = (int)(rnd * (rnd >> 16) >> 16);
|
|
return (float)(out - 32767) * ONEDIV32K;
|
|
}
|
|
|
|
|
|
#if 0
|
|
typedef struct soscillator_t
|
|
{
|
|
float a; /* amplitude */
|
|
float w; /* angular position */
|
|
float dwr; /* relative angular velocity */
|
|
} soscillator_t;
|
|
|
|
static int oscillators = 0;
|
|
static soscillator_t osc[MAX_SPECTRUM_OSCILLATORS];
|
|
|
|
static inline float osc_process(float dw0)
|
|
{
|
|
int i;
|
|
float acc = 0f;
|
|
for(i = 0; i < oscillators; ++i)
|
|
{
|
|
acc += sin(osc[i].w) * osc[i].a;
|
|
osc[i].w += dw0 * osc[i].dwr;
|
|
}
|
|
return acc;
|
|
}
|
|
#endif
|
|
|
|
|
|
static inline float rolloff(float f, float limit)
|
|
{
|
|
float a = f / limit;
|
|
return 1.0f - (.45 + .3*a)*a;
|
|
}
|
|
|
|
|
|
static double osc_w; /* Ohmega for most oscillators */
|
|
static float noise_out; /* S&H accumulator for noise */
|
|
static float osc_yit; /* State for recursive oscillators */
|
|
|
|
static inline void _osc_sine(char *sync, float *f,
|
|
float *mod1,
|
|
float *out, unsigned frames)
|
|
{
|
|
const float onediv8 = 1.0f / 8.0f;
|
|
unsigned s, os;
|
|
float dt = s_dt * onediv8;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float acc = 0.0f;
|
|
float dw = f[s] * dt;
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
if(mod1[s])
|
|
for(os = 8; os; --os)
|
|
{
|
|
float mod = sin(M_PI * 2.0f * osc_w) * mod1[s];
|
|
acc += sin(M_PI * 2.0f * (osc_w + mod));
|
|
osc_w += dw;
|
|
}
|
|
else
|
|
for(os = 8; os; --os)
|
|
{
|
|
acc += sin(M_PI * 2.0f * osc_w);
|
|
osc_w += dw;
|
|
}
|
|
out[s] = acc * onediv8;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_halfsine(char *sync, float *f,
|
|
float *mod1,
|
|
float *out, unsigned frames)
|
|
{
|
|
const float onediv2 = 1.0f / 2.0f;
|
|
unsigned s, os;
|
|
float dt = s_dt * onediv2;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float acc = 0.0f;
|
|
float dw = f[s] * dt;
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
for(os = 2; os; --os)
|
|
{
|
|
float v = sin(M_PI * 2.0f * osc_w);
|
|
if(v < mod1[s])
|
|
v = mod1[s];
|
|
v -= 0.5f + mod1[s] * 0.5f;
|
|
if(mod1[s] < 1.0f)
|
|
v *= 2.0f / (1.0f - mod1[s]);
|
|
else
|
|
v = 1.0f;
|
|
acc += v;
|
|
osc_w += dw;
|
|
}
|
|
out[s] = acc * onediv2;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_rectsine(char *sync, float *f,
|
|
float *mod1,
|
|
float *out, unsigned frames)
|
|
{
|
|
const float onediv4 = 1.0f / 4.0f;
|
|
unsigned s, os;
|
|
float dt = s_dt * onediv4;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float acc = 0.0f;
|
|
float dw = f[s] * dt;
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
for(os = 4; os; --os)
|
|
{
|
|
float v = fabs(sin(M_PI * 2.0f * osc_w) + mod1[s]);
|
|
v -= fabs(mod1[s] * 0.5f) + 0.5f;
|
|
v *= 2.0f - 2.0f * fabs(mod1[s]);
|
|
acc += v;
|
|
osc_w += dw;
|
|
}
|
|
out[s] = acc * onediv4;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_pulse(char *sync, float *f,
|
|
float *mod1,
|
|
float *out, unsigned frames)
|
|
{
|
|
const float onediv8 = 1.0f / 8.0f;
|
|
unsigned s, os;
|
|
float dt = s_dt * onediv8;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float acc = 0.0f;
|
|
float dw = f[s] * dt;
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
for(os = 8; os; --os)
|
|
{
|
|
float saw = osc_w - floor(osc_w);
|
|
acc += saw > mod1[s] ? 1.0f : -1.0f;
|
|
osc_w += dw;
|
|
}
|
|
out[s] = acc * onediv8;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_triangle(char *sync, float *f,
|
|
float *mod1,
|
|
float *out, unsigned frames)
|
|
{
|
|
const float onediv4 = 1.0f / 4.0f;
|
|
unsigned s, os;
|
|
float dt = s_dt * onediv4;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float acc = 0.0f;
|
|
float dw = f[s] * dt;
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
if(0.0f == mod1[s])
|
|
for(os = 4; os; --os)
|
|
{
|
|
acc += (osc_w - floor(osc_w)) * 2.0f - 1.0f;
|
|
osc_w += dw;
|
|
}
|
|
else
|
|
for(os = 4; os; --os)
|
|
{
|
|
float v = osc_w - floor(osc_w);
|
|
if(v < mod1[s])
|
|
v = v / mod1[s];
|
|
else
|
|
v = (1.0f - v) / (1.0f - mod1[s]);
|
|
v *= 2.0f;
|
|
v -= 1.0f;
|
|
acc += v;
|
|
osc_w += dw;
|
|
}
|
|
out[s] = acc * onediv4;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_sinemorph(char *sync, float *f,
|
|
float *mod1, float *mod2, float *limit,
|
|
float *out, unsigned frames)
|
|
{
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float m1, m2;
|
|
if(sync[s])
|
|
{
|
|
osc_w = 0.0f;
|
|
osc_yit = 0.0f;
|
|
}
|
|
if(f[s] > limit[s] * 0.5f)
|
|
m1 = m2 = 0.0f;
|
|
else
|
|
{
|
|
float scale = 1.0f - f[s] / (limit[s] * 0.5f);
|
|
if(mod1[s] + mod2[s] > 1.0f)
|
|
scale *= 1.0f / (mod1[s] + mod2[s]);
|
|
m1 = mod1[s] * scale;
|
|
m2 = mod2[s] * scale;
|
|
}
|
|
osc_yit = sin(M_PI*2.0f*osc_w + m1 * osc_yit +
|
|
m2 * osc_yit*osc_yit);
|
|
out[s] = osc_yit;
|
|
osc_w += f[s] * s_dt;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_blmorph(char *sync, float *f,
|
|
float *mod1, float *mod2, float *mod3, float *limit,
|
|
float *out, unsigned frames)
|
|
{
|
|
/*
|
|
FIXME: Frequency sweeping broken!
|
|
*/
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float hlimit1, hlimit2, hlimit3;
|
|
float ha;
|
|
float n = 2.0f;
|
|
int running = 1;
|
|
float m1 = mod1[s]*mod1[s];
|
|
float m2 = mod2[s]*mod2[s];
|
|
float m3 = mod3[s]*mod3[s];
|
|
int count = 0;
|
|
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
|
|
/* Fundamental */
|
|
out[s] = sin(M_PI * 2.0f * osc_w * f[s]);
|
|
|
|
while(running)
|
|
{
|
|
running = 0;
|
|
|
|
/* Even harmonics (sawtooth) */
|
|
hlimit1 = f[s] * (1.0f - m1) + (limit[s] * m1);
|
|
if(f[s] * n <= hlimit1)
|
|
{
|
|
out[s] += sin(M_PI * 2.0f * osc_w * f[s] * n) *
|
|
(1.0f / n) *
|
|
rolloff(f[s] * n, hlimit1);
|
|
running = 1;
|
|
}
|
|
n += 1.0f;
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
|
|
/* Odd harmonics (sawtooth, square & triangle) */
|
|
hlimit1 = f[s] * (1.0f - m1) + (limit[s] * m1);
|
|
if(f[s] * n <= hlimit1)
|
|
ha = 1.0f / n * rolloff(f[s] * n, hlimit1);
|
|
else
|
|
ha = 0;
|
|
hlimit2 = f[s] * (1.0f - m2) + (limit[s] * m2);
|
|
if(f[s] * n <= hlimit2)
|
|
ha += 1.0f / n * rolloff(f[s] * n, hlimit2);
|
|
hlimit3 = f[s] * (1.0f-m3) + (limit[s] * m3);
|
|
if(f[s] * n <= hlimit3)
|
|
ha += -1.0f / (n*n) *
|
|
rolloff(f[s] * n, hlimit3);
|
|
if(ha != 0)
|
|
{
|
|
out[s] += sin(M_PI * 2.0f * osc_w * f[s] * n)
|
|
* ha;
|
|
running = 1;
|
|
}
|
|
n += 1.0f;
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
}
|
|
osc_w += s_dt;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_blcross(char *sync, float *f,
|
|
float *mod1, float *mod2, float *mod3, float *limit,
|
|
float *out, unsigned frames)
|
|
{
|
|
/*
|
|
FIXME: Frequency sweeping broken!
|
|
*/
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float n = 2.0f;
|
|
float ha;
|
|
int count = 0;
|
|
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
|
|
/* Fundamental */
|
|
out[s] = sin(M_PI * 2.0f * osc_w * f[s]);
|
|
|
|
while(1)
|
|
{
|
|
/* Even harmonics (sawtooth) */
|
|
if(f[s] * n > limit[s])
|
|
break;
|
|
|
|
ha = mod1[s] / n;
|
|
out[s] += sin(M_PI * 2.0f * osc_w * f[s] * n) * ha *
|
|
rolloff(f[s] * n, limit[s]);
|
|
n += 1.0f;
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
|
|
/* Odd harmonics (sawtooth, square & triangle) */
|
|
if(f[s] * n > limit[s])
|
|
break;
|
|
|
|
ha = (mod1[s] + mod2[s]) / n - mod3[s] / (n*n);
|
|
out[s] += sin(M_PI * 2.0f * osc_w * f[s] * n) * ha *
|
|
rolloff(f[s] * n, limit[s]);
|
|
n += 1.0f;
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
}
|
|
osc_w += s_dt;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_noise(char *sync, float *f,
|
|
float *out, unsigned frames)
|
|
{
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
unsigned os;
|
|
float acc = 0.0f;
|
|
float dt = (2.0f * 0.25f) * f[s] * s_dt;
|
|
if(dt > 0.25f)
|
|
dt = 0.25f;
|
|
|
|
if(sync[s])
|
|
osc_w = 1.0f;
|
|
|
|
for(os = 4; os; --os)
|
|
{
|
|
if(osc_w >= 1.0f) /* new value every half period */
|
|
{
|
|
osc_w -= 1.0f;
|
|
noise_out = noise();
|
|
}
|
|
osc_w += dt;
|
|
acc += noise_out;
|
|
}
|
|
out[s] = 0.25f * acc;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_spectrum(char *sync, float *f,
|
|
float *mod1, float *mod2, float *limit,
|
|
float *out, unsigned frames)
|
|
{
|
|
/*
|
|
FIXME: Frequency sweeping broken!
|
|
*/
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float acc = 0.0f;
|
|
float sa = 1.0f;
|
|
float sf = 1.0f;
|
|
float m1 = mod1[s];
|
|
float lim;
|
|
int count = 0;
|
|
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
|
|
if(m1 <= 1.0f)
|
|
{
|
|
m1 = 10.0f;
|
|
lim = f[s];
|
|
}
|
|
else
|
|
lim = limit[s];
|
|
|
|
while(f[s] * sf <= lim)
|
|
{
|
|
acc += sin(M_PI * 2.0f * f[s] * osc_w * sf) * sa *
|
|
rolloff(sf, lim);
|
|
sf *= m1;
|
|
sa *= mod2[s];
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
}
|
|
out[s] = acc;
|
|
osc_w += s_dt;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_aspectrum(char *sync, float *f,
|
|
float *mod1, float *mod2, float *limit,
|
|
float *out, unsigned frames)
|
|
{
|
|
/*
|
|
FIXME: Frequency sweeping broken!
|
|
*/
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float acc = 0.0f;
|
|
float sa = 1.0f;
|
|
float sf = 1.0f;
|
|
float m1 = mod1[s];
|
|
float lim;
|
|
int count = 0;
|
|
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
|
|
if(m1 <= 1.0f)
|
|
{
|
|
m1 = 10.0f;
|
|
lim = f[s];
|
|
}
|
|
else
|
|
lim = limit[s];
|
|
|
|
while(f[s] * sf <= lim)
|
|
{
|
|
acc += sin(M_PI * 2.0f * f[s] * osc_w * sf) * sa *
|
|
rolloff(sf, lim);
|
|
sf += m1;
|
|
sa *= mod2[s];
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
}
|
|
out[s] = acc;
|
|
osc_w += s_dt;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_hspectrum(char *sync, float *f,
|
|
float *mod1, float *mod2, float *mod3, float *limit,
|
|
float *out, unsigned frames)
|
|
{
|
|
/*
|
|
FIXME: Frequency sweeping broken!
|
|
*/
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float sao = 1.0f;
|
|
float sae = mod2[s];
|
|
float n = 1.0f;
|
|
unsigned count = 0;
|
|
float acc = 0.0f;
|
|
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
|
|
while(1)
|
|
{
|
|
/* Odd overtones */
|
|
if(f[s] * n > limit[s])
|
|
break;
|
|
acc += sin(M_PI * 2.0f * osc_w * f[s] * n) * sao *
|
|
rolloff(f[s] * n, limit[s]);
|
|
n *= mod1[s];
|
|
sao *= mod2[s];
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
|
|
/* Even overtones */
|
|
if(f[s] * n > limit[s])
|
|
break;
|
|
acc += sin(M_PI * 2.0f * osc_w * f[s] * n) * sae *
|
|
rolloff(f[s] * n, limit[s]);
|
|
n *= mod1[s];
|
|
sae *= mod3[s];
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
}
|
|
out[s] = acc;
|
|
osc_w += s_dt;
|
|
}
|
|
}
|
|
|
|
|
|
static inline void _osc_ahspectrum(char *sync, float *f,
|
|
float *mod1, float *mod2, float *mod3, float *limit,
|
|
float *out, unsigned frames)
|
|
{
|
|
/*
|
|
FIXME: Frequency sweeping broken!
|
|
*/
|
|
unsigned s;
|
|
for(s = 0; s < frames; ++s)
|
|
{
|
|
float sao = 1.0f;
|
|
float sae = mod2[s];
|
|
float n = 1.0f;
|
|
unsigned count = 0;
|
|
float acc = 0.0f;
|
|
|
|
if(sync[s])
|
|
osc_w = 0.0f;
|
|
|
|
while(1)
|
|
{
|
|
/* Odd overtones */
|
|
if(f[s] * n > limit[s])
|
|
break;
|
|
acc += sin(M_PI * 2.0f * osc_w * f[s] * n) * sao *
|
|
rolloff(f[s] * n, limit[s]);
|
|
n += mod1[s];
|
|
sao *= mod2[s];
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
|
|
/* Even overtones */
|
|
if(f[s] * n > limit[s])
|
|
break;
|
|
acc += sin(M_PI * 2.0f * osc_w * f[s] * n) * sae *
|
|
rolloff(f[s] * n, limit[s]);
|
|
n += mod1[s];
|
|
sae *= mod3[s];
|
|
if(++count > MAX_SPECTRUM_OSCILLATORS)
|
|
break;
|
|
}
|
|
out[s] = acc;
|
|
osc_w += s_dt;
|
|
}
|
|
}
|