/* 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