/*
Calf Box, an open source musical instrument.
Copyright (C) 2010 Krzysztof Foltman
This program 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 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef CBOX_DSPMATH_H
#define CBOX_DSPMATH_H
#define CBOX_BLOCK_SIZE 16
#include
#include
#include
#include
#include
#ifndef M_PI
#include
#define M_PI G_PI
#endif
typedef float cbox_sample_t;
struct cbox_sincos
{
float sine;
float cosine;
float prewarp;
float prewarp2;
};
static inline float hz2w(float hz, float sr)
{
return M_PI * hz / (2 * sr);
}
static inline float cerp_naive(float v0, float v1, float v2, float v3, float f)
{
float x0 = -1;
float x1 = 0;
float x2 = 1;
float x3 = 2;
float l0 = ((f - x1) * (f - x2) * (f - x3)) / ( (x0 - x1) * (x0 - x2) * (x0 - x3));
float l1 = ((f - x0) * (f - x2) * (f - x3)) / ((x1 - x0) * (x1 - x2) * (x1 - x3));
float l2 = ((f - x0) * (f - x1) * (f - x3)) / ((x2 - x0) * (x2 - x1) * (x2 - x3));
float l3 = ((f - x0) * (f - x1) * (f - x2)) / ((x3 - x0) * (x3 - x1) * (x3 - x2) );
return v0 * l0 + v1 * l1 + v2 * l2 + v3 * l3;
}
static inline float cerp(float v0, float v1, float v2, float v3, float f)
{
f += 1;
float d0 = (f - 0);
float d1 = (f - 1);
float d2 = (f - 2);
float d3 = (f - 3);
float d03 = (d0 * d3) * (1.0 / 2.0);
float d12 = (d03 + 1) * (1.0 / 3.0);
float l0 = -d12 * d3;
float l1 = d03 * d2;
float l2 = -d03 * d1;
float l3 = d12 * d0;
float y = v0 * l0 + v1 * l1 + v2 * l2 + v3 * l3;
// printf("%f\n", y - cerp_naive(v0, v1, v2, v3, f - 1));
return y;
}
static inline float sanef(float v)
{
if (fabs(v) < (1.0 / (65536.0 * 65536.0)))
return 0;
return v;
}
static inline void sanebf(float *buf)
{
int i;
for (i = 0; i < CBOX_BLOCK_SIZE; i++)
buf[i] = sanef(buf[i]);
}
static inline void copybf(float *to, float *from)
{
memcpy(to, from, sizeof(float) * CBOX_BLOCK_SIZE);
}
static inline float cent2factor(float cent)
{
return powf(2.0, cent * (1.f / 1200.f)); // I think this may be optimised using exp()
}
static inline float dB2gain(float dB)
{
return powf(2.f, dB * (1.f / 6.f));
}
static inline float dB2gain_simple(float dB)
{
if (dB <= -96)
return 0;
return powf(2.f, dB * (1.f / 6.f));
}
static inline float gain2dB_simple(float gain)
{
static const float sixoverlog2 = 8.656170245333781; // 6.0 / logf(2.f);
if (gain < (1.f / 65536.f))
return -96.f;
return sixoverlog2 * logf(gain);
}
static inline float deg2rad(float deg)
{
return deg * (float)(M_PI / 180.f);
}
static inline float rad2deg(float rad)
{
return rad * (float)(180.f / M_PI);
}
// Do a butterfly operation:
// dst1 = src1 + e^iw_1*src2
// dst2 = src1 + e^iw_2*src2 (w = phase * 2pi / ANALYSIS_BUFFER_SIZE)
static inline void butterfly(complex float *dst1, complex float *dst2, complex float src1, complex float src2, complex float eiw1, complex float eiw2)
{
*dst1 = src1 + eiw1 * src2;
*dst2 = src1 + eiw2 * src2;
}
struct cbox_gain
{
float db_gain;
float lin_gain;
float old_lin_gain;
float pos;
float delta;
};
static inline void cbox_gain_init(struct cbox_gain *gain)
{
gain->db_gain = 0;
gain->lin_gain = 1;
gain->old_lin_gain = 1;
gain->pos = 1;
gain->delta = 1 / (44100 * 0.1); // XXXKF ballpark
}
static inline void cbox_gain_set_db(struct cbox_gain *gain, float db)
{
if (gain->db_gain == db)
return;
gain->db_gain = db;
gain->old_lin_gain = gain->old_lin_gain + (gain->lin_gain - gain->old_lin_gain) * gain->pos;
gain->lin_gain = dB2gain(db);
gain->pos = 0;
}
#define CBOX_GAIN_APPLY_LOOP(gain, nsamples, code) \
{ \
double pos = (gain)->pos; \
double span = (gain)->lin_gain - (gain)->old_lin_gain; \
double start = (gain)->old_lin_gain; \
double step = (gain)->delta; \
if (pos >= 1) { \
double tgain = gain->lin_gain; \
for (uint32_t i = 0; i < (nsamples); ++i) { \
code(i, tgain) \
} \
} else { \
if (pos + (nsamples) * step < 1.0) { \
for (uint32_t i = 0; i < (nsamples); ++i) { \
double tgain = start + (pos + i * step) * span; \
code(i, tgain) \
} \
gain->pos += (nsamples) * step; \
} \
else { \
for (uint32_t i = 0; i < (nsamples); ++i) { \
code(i, (start + pos * span)) \
pos = (pos + step < 1.0 ? pos + step : 1.0); \
} \
gain->pos = 1.0; \
} \
} \
}
#define CBOX_GAIN_ADD_MONO(i, gain) \
dest1[i] += src1[i] * gain;
static inline void cbox_gain_add_mono(struct cbox_gain *gain, float *dest1, const float *src1, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_ADD_MONO);
}
#define CBOX_GAIN_ADD_STEREO(i, gain) \
dest1[i] += src1[i] * gain, dest2[i] += src2[i] * gain;
static inline void cbox_gain_add_stereo(struct cbox_gain *gain, float *dest1, const float *src1, float *dest2, const float *src2, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_ADD_STEREO);
}
#define CBOX_GAIN_COPY_MONO(i, gain) \
dest1[i] = src1[i] * gain;
static inline void cbox_gain_copy_mono(struct cbox_gain *gain, float *dest1, const float *src1, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_COPY_MONO);
}
#define CBOX_GAIN_COPY_STEREO(i, gain) \
dest1[i] = src1[i] * gain, dest2[i] = src2[i] * gain;
static inline void cbox_gain_copy_stereo(struct cbox_gain *gain, float *dest1, const float *src1, float *dest2, const float *src2, uint32_t nsamples)
{
CBOX_GAIN_APPLY_LOOP(gain, nsamples, CBOX_GAIN_COPY_STEREO);
}
#endif