[SCM] calf/master: + Added bandlimited osc classes + Internal cleanups/bugfixes
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:36:42 UTC 2013
The following commit has been merged in the master branch:
commit 1edb70baea586dd02adef7260426ef13e8003bb2
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Sat Dec 8 12:14:13 2007 +0000
+ Added bandlimited osc classes
+ Internal cleanups/bugfixes
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@8 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/src/calf/Makefile.am b/src/calf/Makefile.am
index 7f98730..e49e1f3 100644
--- a/src/calf/Makefile.am
+++ b/src/calf/Makefile.am
@@ -1,3 +1,3 @@
calfdir = $(includedir)/calf
-calf_HEADERS = audio_fx.h benchmark.h biquad.h buffer.h delay.h fixed_point.h giface.h inertia.h jackhost.h modules.h modules_dev.h onepole.h primitives.h wave.h
+calf_HEADERS = audio_fx.h benchmark.h biquad.h buffer.h delay.h fft.h fixed_point.h giface.h inertia.h jackhost.h modules.h modules_dev.h onepole.h osc.h primitives.h wave.h
diff --git a/src/calf/audio_fx.h b/src/calf/audio_fx.h
index 2da56d4..8844693 100644
--- a/src/calf/audio_fx.h
+++ b/src/calf/audio_fx.h
@@ -31,30 +31,6 @@ namespace dsp {
#endif
/**
- * typical precalculated sine table
- */
-template<class T, int N, int Multiplier>
-class sine_table
-{
-public:
- static bool initialized;
- static T data[N+1];
- sine_table() {
- if (initialized)
- return;
- initialized = true;
- for (int i=0; i<N+1; i++)
- data[i] = (T)(Multiplier*sin(i*2*M_PI*(1.0/N)));
- }
-};
-
-template<class T, int N, int Multiplier>
-bool sine_table<T,N,Multiplier>::initialized = false;
-
-template<class T, int N, int Multiplier>
-T sine_table<T,N,Multiplier>::data[N+1];
-
-/**
* Audio effect base class. Not really useful until it gets more developed.
*/
class audio_effect
diff --git a/src/calf/fft.h b/src/calf/fft.h
new file mode 100644
index 0000000..f8b79cf
--- /dev/null
+++ b/src/calf/fft.h
@@ -0,0 +1,103 @@
+/* Calf DSP Library
+ * FFT class
+ *
+ * Copyright (C) 2007 Krzysztof Foltman
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __CALF_FFT_H
+#define __CALF_FFT_H
+
+#include <complex>
+
+namespace dsp {
+
+/// FFT routine copied from my old OneSignal library, modified to
+/// match Calf's style. It's not fast at all, just a straightforward
+/// implementation.
+template<class T, int O>
+class fft
+{
+ typedef typename std::complex<T> complex;
+ int scramble[1<<O];
+ complex sines[1<<O];
+public:
+ fft()
+ {
+ int N=1<<O;
+ for (int i=0; i<N; i++)
+ {
+ int v=0;
+ for (int j=0; j<O; j++)
+ if (i&(1<<j))
+ v+=(N>>(j+1));
+ scramble[i]=v;
+ sines[i]=complex(cos(2*PI*i/N),sin(2*PI*i/N));
+ }
+ }
+ void calculate(complex *input, complex *output, bool inverse)
+ {
+ int N=1<<O;
+ int N1=N-1;
+ int i;
+ // Scramble the input data
+ if (inverse)
+ {
+ float mf=1.0/N;
+ for (i=0; i<N; i++)
+ {
+ complex &c=input[scramble[i]];
+ output[i]=mf*complex(c.imag(),c.real());
+ }
+ }
+ else
+ for (i=0; i<N; i++)
+ output[i]=input[scramble[i]];
+
+ // O butterfiles
+ for (i=0; i<O; i++)
+ {
+ int PO=1<<i, PNO=1<<(O-i-1);
+ int j,k;
+ for (j=0; j<PNO; j++)
+ {
+ int base=j<<(i+1);
+ for (k=0; k<PO; k++)
+ {
+ int B1=base+k;
+ int B2=base+k+(1<<i);
+ complex r1=output[B1];
+ complex r2=output[B2];
+ output[B1]=r1+r2*sines[(B1<<(O-i-1))&N1];
+ output[B2]=r1+r2*sines[(B2<<(O-i-1))&N1];
+ }
+ }
+ }
+ if (inverse)
+ {
+ for (i=0; i<N; i++)
+ {
+ const complex &c=output[i];
+ output[i]=complex(c.imag(),c.real());
+ }
+ }
+ }
+};
+
+};
+
+#endif
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index d10ab9a..4f696ee 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -148,6 +148,7 @@ public:
virtual void init_module() {
module.set_sample_rate(sample_rate);
+ module.activate();
module.params_changed();
}
diff --git a/src/calf/modules_dev.h b/src/calf/modules_dev.h
index da2a2ea..337ad19 100644
--- a/src/calf/modules_dev.h
+++ b/src/calf/modules_dev.h
@@ -27,32 +27,12 @@
#include "biquad.h"
#include "audio_fx.h"
#include "inertia.h"
+#include "osc.h"
namespace synth {
using namespace dsp;
-
-/// Very simple, non-bandlimited saw oscillator. Should not be used for anything
-/// else than testing/prototyping.
-struct simple_oscillator
-{
- uint32_t phase, phasedelta;
- void reset()
- {
- phase = 0;
- }
- void set_freq(float freq, float sr)
- {
- phasedelta = (int)(freq * 65536.0 * 256.0 * 16.0 / sr) << 4;
- }
- inline float get()
- {
- float value = (phase >> 16 ) / 65535.0 - 0.5;
- phase += phasedelta;
- return value;
- }
-};
-
+
/// Monosynth-in-making. Parameters may change at any point, so don't make songs with it!
class monosynth_audio_module
{
@@ -65,7 +45,9 @@ public:
float *outs[out_count];
float *params[param_count];
uint32_t srate, crate;
- simple_oscillator osc1, osc2;
+ dsp::sine_table<float, 2048, 1> waveform_sine;
+ waveform_family<11> waves_saw;
+ waveform_oscillator<11> osc1, osc2;
bool running;
int last_key;
@@ -92,6 +74,7 @@ public:
float freq = 440 * pow(2.0, (last_key - 69) / 12.0);
osc1.set_freq(freq*0.995, srate);
osc2.set_freq(freq*1.005, srate);
+ osc2.waveform = osc1.waveform = waves_saw.get_level(osc1.phasedelta);
if (!running)
{
osc1.reset();
@@ -121,6 +104,11 @@ public:
output_pos = 0;
filter.reset();
filter2.reset();
+ float data[2048];
+ for (int i = 0 ; i < 2048; i++)
+ data[i] = (float)(-1.f + i / 1024.f);
+ bandlimiter<11> bl;
+ waves_saw.make(bl, data);
}
void deactivate() {
}
diff --git a/src/calf/osc.h b/src/calf/osc.h
new file mode 100644
index 0000000..6efc107
--- /dev/null
+++ b/src/calf/osc.h
@@ -0,0 +1,141 @@
+/* Calf DSP Library
+ * Oscillators
+ *
+ * Copyright (C) 2001-2007 Krzysztof Foltman
+ *
+ * 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 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __CALF_OSC_H
+#define __CALF_OSC_H
+
+#include "fft.h"
+#include <map>
+
+namespace synth
+{
+
+/// Very simple, non-bandlimited saw oscillator. Should not be used for anything
+/// else than testing/prototyping.
+struct simple_oscillator
+{
+ uint32_t phase, phasedelta;
+ void reset()
+ {
+ phase = 0;
+ }
+ void set_freq(float freq, float sr)
+ {
+ phasedelta = (int)(freq * 65536.0 * 256.0 * 16.0 / sr) << 4;
+ }
+ inline float get()
+ {
+ float value = (phase >> 16 ) / 65535.0 - 0.5;
+ phase += phasedelta;
+ return value;
+ }
+};
+
+template<int SIZE_BITS>
+struct bandlimiter
+{
+ enum { SIZE = 1 << SIZE_BITS };
+ static dsp::fft<float, SIZE_BITS> fft;
+
+ std::complex<float> spectrum[SIZE];
+
+ void compute_spectrum(float input[SIZE])
+ {
+ std::complex<float> data[SIZE];
+ for (int i = 0; i < SIZE; i++)
+ data[i] = input[i];
+ fft.calculate(data, spectrum, false);
+ }
+
+ /// remove DC offset of the spectrum (it usually does more harm than good!)
+ void remove_dc()
+ {
+ spectrum[0] = 0.f;
+ }
+
+ /// very basic bandlimiting (brickwall filter)
+ /// might need to be improved much in future!
+ void make_waveform(float output[SIZE], int cutoff)
+ {
+ std::complex<float> new_spec[SIZE], iffted[SIZE];
+ for (int i = 0; i < cutoff; i++)
+ new_spec[i] = spectrum[i];
+ for (int i = cutoff; i < SIZE; i++)
+ new_spec[i] = 0.f;
+ fft.calculate(new_spec, iffted, true);
+ for (int i = 0; i < SIZE; i++)
+ output[i] = iffted[i].real();
+ }
+};
+
+template<int SIZE_BITS>
+dsp::fft<float, SIZE_BITS> bandlimiter<SIZE_BITS>::fft;
+
+/// Set of bandlimited wavetables
+template<int SIZE_BITS>
+struct waveform_family: public map<uint32_t, float *>
+{
+ enum { SIZE = 1 << SIZE_BITS };
+ using map<uint32_t, float *>::iterator;
+ using map<uint32_t, float *>::end;
+ using map<uint32_t, float *>::lower_bound;
+
+ void make(bandlimiter<SIZE_BITS> &bl, float input[SIZE])
+ {
+ bl.compute_spectrum(input);
+ bl.remove_dc();
+
+ uint32_t multiple = 1, base = 1 << (32 - SIZE_BITS);
+ while(multiple < SIZE / 2) {
+ float *wf = new float[SIZE];
+ bl.make_waveform(wf, (1 << SIZE_BITS) / multiple);
+ (*this)[base * multiple] = wf;
+ multiple = multiple << 1;
+ }
+ }
+
+ inline float *get_level(uint32_t phase_delta)
+ {
+ iterator i = upper_bound(phase_delta);
+ if (i == end())
+ return NULL;
+ // printf("Level = %08x\n", i->first);
+ return i->second;
+ }
+};
+
+template<int SIZE_BITS>
+struct waveform_oscillator: public simple_oscillator
+{
+ enum { SIZE = 1 << SIZE_BITS, MASK = SIZE - 1 };
+ float *waveform;
+ inline float get()
+ {
+ uint32_t wpos = phase >> (32 - SIZE_BITS);
+ float value = lerp(waveform[wpos], waveform[(wpos + 1) & MASK], (phase & (SIZE - 1)) * (1.0f / SIZE));
+ phase += phasedelta;
+ return value;
+ }
+};
+
+};
+
+#endif
diff --git a/src/calf/primitives.h b/src/calf/primitives.h
index 9969a4b..5af0800 100644
--- a/src/calf/primitives.h
+++ b/src/calf/primitives.h
@@ -373,6 +373,30 @@ inline float fract16(unsigned int value)
return (value & 0xFFFF) * (1.0 / 65536.0);
}
+/**
+ * typical precalculated sine table
+ */
+template<class T, int N, int Multiplier>
+class sine_table
+{
+public:
+ static bool initialized;
+ static T data[N+1];
+ sine_table() {
+ if (initialized)
+ return;
+ initialized = true;
+ for (int i=0; i<N+1; i++)
+ data[i] = (T)(Multiplier*sin(i*2*M_PI*(1.0/N)));
+ }
+};
+
+template<class T, int N, int Multiplier>
+bool sine_table<T,N,Multiplier>::initialized = false;
+
+template<class T, int N, int Multiplier>
+T sine_table<T,N,Multiplier>::data[N+1];
+
};
#endif
diff --git a/src/modules.cpp b/src/modules.cpp
index 08c649a..4a0fc24 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -109,9 +109,9 @@ const char *monosynth_audio_module::param_names[] = {"Out L", "Out R", "Cutoff",
parameter_properties monosynth_audio_module::param_props[] = {
{ 33, 10,16000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL },
- { 3, 0.7, 4, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL },
- { 6000, 0,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL },
- { 2000, 10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+ { 2, 0.7, 4, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB, NULL },
+ { 8000, 0,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL },
+ { 350, 10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
};
static synth::ladspa_info monosynth_info = { 0x8480, "Monosynth", "Calf Monosynth", "Krzysztof Foltman", copyright, "SynthesizerPlugin" };
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list