#include <config.h>
#include <useconfig.h>
#include <stdio.h>
#define __USE_ISOC99 1
#include <math.h>
#ifndef PI
#define PI 3.1415927
#endif
#include "rsynth.h"
#define SYNC_CASCADE
#define PVT(x) rsynth->pvt->x
#define RES(x) &PVT(x),#x
#if defined(__linux__)
#define FPCHECK(x) do { \
if (fpclassify(x) < FP_ZERO) \
{ \
fprintf(stderr, #x "=%g (%s:%d)\n",x,__FILE__,__LINE__); \
abort(); \
} \
} while (0)
#else
#define FPCHECK(x)
#endif
#ifdef DO_RANGE_CHECKS
static float range_max = 0.0;
static int range_ln = 0;
#define RGCHECK(x) do { \
FPCHECK(x); \
if (abs(x) > range_max) \
{ \
range_max = abs(x); \
if (range_max > 32767) \
fprintf(stdout, #x "=%g (%s:%d)\n",range_max,__FILE__,__LINE__); \
range_ln = __LINE__; \
} \
} while (0)
#else
#define RGCHECK(x)
#endif
typedef struct {
float a;
float b;
float c;
float p1;
float p2;
} resonator_t, *resonator_ptr;
typedef struct {
float a;
float b;
float p1;
} lowpass_t, *lowpass_ptr;
struct rsynth_private {
long nper;
long T0;
long nopen;
float F0Hz;
float amp_av;
float amp_bypass;
float amp_asp;
float amp_af;
float amp_avc;
float amp_turb;
unsigned long seed;
unsigned long ns;
long clip_max;
unsigned usrsamp;
resonator_t rgl;
resonator_t rnz;
resonator_t rnpc;
resonator_t r5c;
resonator_t rsc;
resonator_t r4c;
resonator_t r3c;
resonator_t r2c;
resonator_t r1c;
resonator_t r6p;
resonator_t r5p;
resonator_t r4p;
resonator_t r3p;
resonator_t r2p;
resonator_t rout;
};
static void
set_pole_fbw(long sr, float f, float bw, resonator_ptr rp, char *name,
int casc)
{
float minus_pi_t = -PI / sr;
float two_pi_t = -2.0 * minus_pi_t;
if (2 * f - bw <= sr) {
double arg;
float r;
if (2 * (f + bw) > sr) {
float low = f - bw;
#if 0#endif
f = (sr / 2 + low) / 2;
bw = f - low;
#if 0#endif
}
arg = minus_pi_t * bw;
r = exp(arg);
rp->c = -(r * r);
arg = two_pi_t * f;
rp->b = r * cos(arg) * 2.0;
rp->a = 1.0 - rp->b - rp->c;
}
else {
#if 0#endif
rp->a = casc;
rp->b = 0.0;
rp->c = 0.0;
}
}
static void
set_pole_fbwg(long sr, float f, float bw, resonator_ptr rp, char *name,
float gain, int casc)
{
set_pole_fbw(sr, f, bw, rp, name, casc);
rp->a *= gain;
}
static void
set_zero_fbw(long sr, float f, float bw, resonator_ptr rp, char *name)
{
set_pole_fbw(sr, f, bw, rp, name, 1);
rp->a = 1.0 / rp->a;
rp->b *= -rp->a;
rp->c *= -rp->a;
}
static float
resonator(resonator_ptr r, char *name, float input)
{
register float x = r->a * input + r->b * r->p1 + r->c * r->p2;
FPCHECK(input);
FPCHECK(r->a);
FPCHECK(r->b);
FPCHECK(r->c);
r->p2 = r->p1;
r->p1 = x;
return x;
}
static float
antiresonator(resonator_ptr r, char *name, float input)
{
register float x = r->a * input + r->b * r->p1 + r->c * r->p2;
FPCHECK(input);
FPCHECK(r->a);
FPCHECK(r->b);
FPCHECK(r->c);
r->p2 = r->p1;
r->p1 = input;
return x;
}
static float
DBtoLIN(float dB)
{
if (dB > 0) {
float val = 32768 * pow(10.0, (dB - 87) / 20 - 3);
FPCHECK(val);
return val;
}
return 0.0;
}
static void
set_cascade(rsynth_t * rsynth)
{
long sr = rsynth->sr;
set_pole_fbw(sr, rsynth->speaker->FNPhz, rsynth->speaker->BNhz,
RES(rnpc), 1);
set_zero_fbw(sr, rsynth->ep[fn], rsynth->speaker->BNhz, RES(rnz));
set_pole_fbw(sr, 3500, 1800, RES(rsc), 1);
set_pole_fbw(sr, rsynth->speaker->F5hz, rsynth->speaker->B5hz,
RES(r5c), 1);
set_pole_fbw(sr, rsynth->speaker->F4hz, rsynth->speaker->B4hz,
RES(r4c), 1);
set_pole_fbw(sr, rsynth->ep[f3], rsynth->ep[b3], RES(r3c), 1);
set_pole_fbw(sr, rsynth->ep[f2], rsynth->ep[b2], RES(r2c), 1);
set_pole_fbw(sr, rsynth->ep[f1], rsynth->ep[b1], RES(r1c), 1);
}
static void
pitch_sync(rsynth_t * rsynth)
{
float F0Hz = PVT(F0Hz);
if (rsynth->ep[av] > 0 || rsynth->ep[avc] > 0) {
PVT(T0) = (long) ((4 * rsynth->sr) / F0Hz);
PVT(amp_av) = DBtoLIN(rsynth->ep[av]);
PVT(amp_avc) = DBtoLIN(rsynth->ep[avc]);
PVT(amp_turb) = PVT(amp_avc) * 0.1;
PVT(nopen) = PVT(T0) / 3;
}
else {
PVT(T0) = 4;
PVT(nopen) = PVT(T0);
PVT(amp_av) = 0.0;
PVT(amp_avc) = 0.0;
}
if ((PVT(T0) != 4) || (PVT(ns) == 0)) {
if (rsynth->voice_file) {
fprintf(rsynth->voice_file, "# pitch sync T0=%ld\n", PVT(T0));
}
set_pole_fbw(rsynth->sr, 0L, (long) (2 * F0Hz), RES(rgl), 1);
#ifdef SYNC_CASCADE
set_cascade(rsynth);
#endif
}
}
static float
gen_voice(rsynth_t * rsynth, float noise)
{
int i;
float voice;
for (i = 0; i < 4; i++) {
float alpha;
const float amp = 4096.0;
if (PVT(nper) >= PVT(T0)) {
PVT(nper) = 0;
pitch_sync(rsynth);
}
alpha = (float) PVT(nper) / PVT(T0);
if (alpha <= 1.0 / 3) {
voice = 3 * amp * alpha;
}
else {
voice = amp * ((9 * alpha - 12) * alpha + 3);
}
PVT(nper)++;
}
FPCHECK(voice);
return voice;
}
float
gen_noise(rsynth_t * rsynth)
{
float noise = 0.0;
int i;
for (i = 0; i < 16; i++) {
long nrand;
PVT(seed) = PVT(seed) * 1664525 + 1;
if (8 * sizeof(unsigned long) > 32)
PVT(seed) &= 0xFFFFFFFFL;
nrand =
(((long) PVT(seed)) << (8 * sizeof(long) -
32)) >> (8 * sizeof(long) - 14);
noise += nrand;
}
return noise / 2;
}
static void
setup_frame(rsynth_t * rsynth)
{
long sr = rsynth->sr;
float Gain0 = rsynth->speaker->Gain0 - 3;
#ifndef SYNC_CASCADE
set_cascade(sr, frame);
#endif
set_pole_fbwg(sr, rsynth->ep[f2], rsynth->ep[b2], RES(r2p),
DBtoLIN(rsynth->ep[a2]), 0);
set_pole_fbwg(sr, rsynth->ep[f3], rsynth->ep[b3], RES(r3p),
DBtoLIN(rsynth->ep[a3]), 0);
set_pole_fbwg(sr, rsynth->speaker->F4hz, rsynth->speaker->B4phz,
RES(r4p), DBtoLIN(rsynth->ep[a4]), 0);
set_pole_fbwg(sr, rsynth->speaker->F5hz, rsynth->speaker->B5phz,
RES(r5p), DBtoLIN(rsynth->ep[a5]), 0);
set_pole_fbwg(sr, rsynth->speaker->F6hz, rsynth->speaker->B6phz,
RES(r6p), DBtoLIN(rsynth->ep[a6]), 0);
PVT(amp_bypass) = DBtoLIN(rsynth->ep[ab]);
PVT(amp_asp) = DBtoLIN(rsynth->ep[asp]);
PVT(amp_af) = DBtoLIN(rsynth->ep[af]);
if (Gain0 <= 0)
Gain0 = 57;
set_pole_fbwg(sr, 0L, sr / 2, RES(rout), DBtoLIN(Gain0), 1);
}
float
rsynth_filter(rsynth_t * rsynth, float voice, float noise)
{
RGCHECK(noise);
RGCHECK(voice);
voice = resonator(RES(rnpc), voice);
RGCHECK(voice);
voice = antiresonator(RES(rnz), voice);
RGCHECK(voice);
voice = resonator(RES(r1c), voice);
RGCHECK(voice);
voice = resonator(RES(r2c), voice);
RGCHECK(voice);
voice = resonator(RES(r3c), voice);
RGCHECK(voice);
voice = resonator(RES(r4c), voice);
RGCHECK(voice);
voice = resonator(RES(rsc), voice);
RGCHECK(voice);
if (rsynth->sr > 8000) {
voice = resonator(RES(r5c), voice);
RGCHECK(voice);
}
voice = resonator(RES(r2p), noise) - voice;
RGCHECK(voice);
voice = resonator(RES(r3p), noise) - voice;
RGCHECK(voice);
voice = resonator(RES(r4p), noise) - voice;
RGCHECK(voice);
voice = resonator(RES(r5p), noise) - voice;
RGCHECK(voice);
voice = resonator(RES(r6p), noise) - voice;
RGCHECK(voice);
voice = PVT(amp_bypass) * noise - voice;
RGCHECK(voice);
voice = resonator(RES(rout), voice);
RGCHECK(voice);
return voice;
}
long
rsynth_frame(rsynth_t * rsynth, float F0Hz, float *frame, const char *name)
{
unsigned long es;
rsynth->ep = frame;
setup_frame(rsynth);
if (rsynth->voice_file) {
fprintf(rsynth->voice_file, "# voice lpvoc noise out");
fprintf(rsynth->voice_file, "\n");
if (name) {
fprintf(rsynth->voice_file, "# %s\n", name);
}
}
PVT(F0Hz) = F0Hz;
for (es = PVT(ns) + rsynth->samples_frame; PVT(ns) < es; PVT(ns)++) {
float noise = gen_noise(rsynth);
float voice = gen_voice(rsynth, noise);
float lpvoice = resonator(RES(rgl), voice);
if (PVT(nper) < PVT(nopen)) {
voice += PVT(amp_turb) * noise;
}
RGCHECK(noise);
if (PVT(nper) < PVT(nopen)) {
noise *= 0.5;
}
voice *= PVT(amp_av);
voice += (PVT(amp_asp) * noise);
#if 1
voice += (PVT(amp_avc) * lpvoice);
#endif
noise *= PVT(amp_af);
if (rsynth->voice_file) {
fprintf(rsynth->voice_file, "%6g %6g %6g", voice, lpvoice,
noise);
}
voice = rsynth_filter(rsynth, voice, noise);
if (rsynth->voice_file) {
fprintf(rsynth->voice_file, " %6g\n", voice);
}
if (rsynth->sample_p)
rsynth->user_data =
(*rsynth->sample_p) (rsynth->user_data, voice,
PVT(usrsamp)++, rsynth);
}
return PVT(usrsamp) + rsynth->samples_frame;
}
void
rsynth_flush(rsynth_t * rsynth, unsigned nsamp)
{
if (!nsamp)
nsamp = PVT(usrsamp);
if (rsynth->flush_p)
rsynth->user_data =
(*rsynth->flush_p) (rsynth->user_data, nsamp, rsynth);
PVT(usrsamp) = 0;
}
rsynth_t *
rsynth_init(long sr, float ms_per_frame, speaker_t * speaker,
rsynth_sample_p * sample_p,
rsynth_flush_p * flush_p, void *user_data)
{
rsynth_t *rsynth = (rsynth_t *) malloc(sizeof(rsynth_t));
struct rsynth_private *pvt = (struct rsynth_private *)
malloc(sizeof(struct rsynth_private));
if (rsynth && pvt) {
memset(rsynth, 0, sizeof(*rsynth));
memset(pvt, 0, sizeof(*pvt));
rsynth->pvt = pvt;
PVT(seed) = 5;
rsynth->sr = sr;
rsynth->samples_frame = (long) ((sr * ms_per_frame) / 1000);
rsynth->speaker = speaker;
rsynth->sample_p = sample_p;
rsynth->flush_p = flush_p;
rsynth->user_data = user_data;
rsynth->smooth = 0.5F;
rsynth->speed = 1.0F;
}
return rsynth;
}