kobodl/sound/a_wcaosc.h
Ville Lindholm dbc223eb84
Initial commit
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>
2026-05-28 16:35:31 +03:00

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;
}
}