You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
6.3 KiB
238 lines
6.3 KiB
5 years ago
|
/*
|
||
|
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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
#ifndef CBOX_DSPMATH_H
|
||
|
#define CBOX_DSPMATH_H
|
||
|
|
||
|
#define CBOX_BLOCK_SIZE 16
|
||
|
|
||
|
#include <complex.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <math.h>
|
||
|
#include <memory.h>
|
||
|
|
||
|
#ifndef M_PI
|
||
|
#include <glib.h>
|
||
|
#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
|