[SCM] calf/master: + internal cleanups + Organ: first, crappy (no bandlimiting) implementation of ready-made long looped waveforms for drawbars (those waveforms are produced using a very clever algorithm called PADsynth, discovered/invented by Nasca Octavian Paul, http://zynaddsubfx.sourceforge.net/doc/PADsynth/PADsynth.htm)
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:37:14 UTC 2013
The following commit has been merged in the master branch:
commit 9e199e7528113619bcf6ce066cb3d28dbebc69cf
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Sat May 17 23:02:59 2008 +0000
+ internal cleanups
+ Organ: first, crappy (no bandlimiting) implementation of ready-made long looped waveforms for drawbars (those waveforms are produced using a
very clever algorithm called PADsynth, discovered/invented by Nasca Octavian Paul, http://zynaddsubfx.sourceforge.net/doc/PADsynth/PADsynth.htm)
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@183 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/src/calf/fixed_point.h b/src/calf/fixed_point.h
index 189756a..93bcfa9 100644
--- a/src/calf/fixed_point.h
+++ b/src/calf/fixed_point.h
@@ -159,28 +159,28 @@ public:
}
/// return integer part
- inline T ipart() {
+ inline T ipart() const {
return value >> FracBits;
}
/// return integer part as unsigned int
- inline unsigned int uipart() {
+ inline unsigned int uipart() const {
return ((unsigned)value) >> FracBits;
}
/// return integer part as unsigned int
- inline unsigned int ui64part() {
+ inline unsigned int ui64part() const {
return ((uint64_t)value) >> FracBits;
}
/// return fractional part as 0..(2^FracBits-1)
- inline T fpart() {
+ inline T fpart() const {
return value & ((1 << FracBits)-1);
}
/// return fractional part as 0..(2^Bits-1)
template<int Bits>
- inline T fpart() {
+ inline T fpart() const {
int fbits = value & ((1 << FracBits)-1);
if (Bits == FracBits) return fbits;
int shift = abs(Bits-FracBits);
@@ -188,7 +188,7 @@ public:
}
/// return fractional part as 0..1
- inline double fpart_as_double() {
+ inline double fpart_as_double() const {
return (value & ((1 << FracBits)-1)) * (1.0 / (1 << FracBits));
}
@@ -196,7 +196,7 @@ public:
/// note that it uses integer arithmetic only, and isn't suitable for floating point or fixed point U!
/// @param UseBits can be used when there's a risk of exceeding range of U because max(fpart)*max(v1 or v2) > range of U
template<class U, int UseBits, class MulType>
- inline U lerp_by_fract_int(U v1, U v2) {
+ inline U lerp_by_fract_int(U v1, U v2) const {
int fp = fpart<UseBits>();
assert ( fp >=0 && fp <= (1<<UseBits));
// printf("diff =
@@ -204,7 +204,7 @@ public:
}
template<class U, int UseBits>
- inline U lerp_table_lookup_int(U data[(1<<IntBits)+1]) {
+ inline U lerp_table_lookup_int(U data[(1<<IntBits)+1]) const {
unsigned int pos = uipart();
return lerp_by_fract_int<U, UseBits>(data[pos], data[pos+1]);
}
@@ -218,20 +218,26 @@ public:
}
template<class U>
- inline U lerp_table_lookup_float(U data[(1<<IntBits)+1]) {
+ inline U lerp_table_lookup_float(U data[(1<<IntBits)+1]) const {
unsigned int pos = uipart();
return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
}
+ template<class U>
+ inline U lerp_table_lookup_float_mask(U data[(1<<IntBits)+1], unsigned int mask) const {
+ unsigned int pos = ui64part() & mask;
+ // printf("full = %lld pos = %d + %f\n", value, pos, fpart_as_double());
+ return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
+ }
+
template<class U, int UseBits, class MulType>
- inline U lerp_ptr_lookup_int(U *data) {
+ inline U lerp_ptr_lookup_int(U *data) const {
unsigned int pos = ui64part();
- assert(data);
return lerp_by_fract_int<U, UseBits, MulType>(data[pos], data[pos+1]);
}
template<class U>
- inline U lerp_ptr_lookup_float(U *data) {
+ inline U lerp_ptr_lookup_float(U *data) const {
unsigned int pos = ui64part();
return data[pos] + (data[pos+1]-data[pos]) * fpart_as_double();
}
diff --git a/src/calf/giface.h b/src/calf/giface.h
index 04cd397..b0ae5de 100644
--- a/src/calf/giface.h
+++ b/src/calf/giface.h
@@ -138,7 +138,7 @@ struct plugin_ctl_iface
virtual int get_input_count()=0;
virtual int get_output_count()=0;
virtual bool get_midi()=0;
- virtual float get_level(int port)=0;
+ virtual float get_level(unsigned int port)=0;
virtual ~plugin_ctl_iface() {}
virtual plugin_command_info *get_commands() { return NULL; }
virtual void execute(int cmd_no)=0;
@@ -234,7 +234,7 @@ struct ladspa_instance: public Module, public plugin_ctl_iface
virtual int get_input_count() { return Module::in_count; }
virtual int get_output_count() { return Module::out_count; }
virtual bool get_midi() { return Module::support_midi; }
- virtual float get_level(int port) { return 0.f; }
+ virtual float get_level(unsigned int port) { return 0.f; }
virtual void execute(int cmd_no) {
Module::execute(cmd_no);
}
diff --git a/src/calf/jackhost.h b/src/calf/jackhost.h
index 99f4ba1..4859212 100644
--- a/src/calf/jackhost.h
+++ b/src/calf/jackhost.h
@@ -305,7 +305,7 @@ public:
new_meter = 0;
midi_meter = new_meter;
}
- virtual float get_level(int port) {
+ virtual float get_level(unsigned int port) {
if (port < Module::in_count)
return input_vus[port].level;
port -= Module::in_count;
diff --git a/src/calf/lv2wrap.h b/src/calf/lv2wrap.h
index d78dd23..be16461 100644
--- a/src/calf/lv2wrap.h
+++ b/src/calf/lv2wrap.h
@@ -79,7 +79,7 @@ struct lv2_instance: public Module, public plugin_ctl_iface
virtual int get_input_count() { return Module::in_count; }
virtual int get_output_count() { return Module::out_count; }
virtual bool get_midi() { return Module::support_midi; }
- virtual float get_level(int port) { return 0.f; }
+ virtual float get_level(unsigned int port) { return 0.f; }
virtual void execute(int cmd_no) {
Module::execute(cmd_no);
}
diff --git a/src/calf/organ.h b/src/calf/organ.h
index f9413c3..2dfc359 100644
--- a/src/calf/organ.h
+++ b/src/calf/organ.h
@@ -76,6 +76,8 @@ struct organ_parameters {
#define ORGAN_WAVE_BITS 12
#define ORGAN_WAVE_SIZE 4096
+#define ORGAN_BIG_WAVE_BITS 17
+#define ORGAN_BIG_WAVE_SIZE 131072
class organ_voice_base
{
@@ -86,7 +88,16 @@ public:
wave_ssaw, wave_ssqr, wave_spls, wave_saw, wave_sqr, wave_pulse, wave_sinepl05, wave_sqr05, wave_halfsin, wave_clvg, wave_bell, wave_bell2,
wave_w1, wave_w2, wave_w3, wave_w4, wave_w5, wave_w6, wave_w7, wave_w8, wave_w9,
wave_dsaw, wave_dsqr, wave_dpls,
- wave_count };
+ wave_count_small,
+ wave_strings = wave_count_small,
+ wave_strings2,
+ wave_sinepad,
+ wave_bellpad,
+ wave_space,
+ wave_choir,
+ wave_count,
+ wave_count_big = wave_count - wave_count_small
+ };
enum {
ampctl_none,
ampctl_direct,
@@ -110,8 +121,11 @@ public:
perctrig_eachplus,
perctrig_count
};
+ typedef float big_wave_data[ORGAN_BIG_WAVE_SIZE + 1];
protected:
- static waveform_family<ORGAN_WAVE_BITS> waves[wave_count];
+ static waveform_family<ORGAN_WAVE_BITS> waves[wave_count_small];
+ static big_wave_data big_waves[wave_count_big];
+
// dsp::sine_table<float, ORGAN_WAVE_SIZE, 1> sine_wave;
int note;
dsp::decay amp;
@@ -121,11 +135,18 @@ protected:
inline float wave(float *data, dsp::fixed_point<int, 20> ph) {
return ph.lerp_table_lookup_float(data);
}
+ inline float big_wave(float *data, dsp::fixed_point<int64_t, 20> &ph) {
+ // wrap to fit within the wave
+ return ph.lerp_table_lookup_float_mask(data, ORGAN_BIG_WAVE_SIZE - 1);
+ }
public:
organ_parameters *parameters;
static inline waveform_family<ORGAN_WAVE_BITS> &get_wave(int wave) {
return waves[wave];
}
+ static inline big_wave_data &get_big_wave(int wave) {
+ return big_waves[wave];
+ }
};
class organ_vibrato
diff --git a/src/dssigui.cpp b/src/dssigui.cpp
index ad378c9..0e7e84c 100644
--- a/src/dssigui.cpp
+++ b/src/dssigui.cpp
@@ -154,7 +154,7 @@ struct plugin_proxy: public plugin_proxy_base, public line_graph_iface
virtual int get_input_count() { return Module::in_count; }
virtual int get_output_count() { return Module::out_count; }
virtual bool get_midi() { return Module::support_midi; }
- virtual float get_level(int port) { return 0.f; }
+ virtual float get_level(unsigned int port) { return 0.f; }
virtual plugin_command_info *get_commands() {
return Module::get_commands();
}
diff --git a/src/lv2gui.cpp b/src/lv2gui.cpp
index 0c92412..fecf621 100644
--- a/src/lv2gui.cpp
+++ b/src/lv2gui.cpp
@@ -124,7 +124,7 @@ struct plugin_proxy: public plugin_proxy_base, public line_graph_iface
virtual int get_input_count() { return Module::in_count; }
virtual int get_output_count() { return Module::out_count; }
virtual bool get_midi() { return Module::support_midi; }
- virtual float get_level(int port) { return 0.f; }
+ virtual float get_level(unsigned int port) { return 0.f; }
virtual void execute(int command_no) { assert(0); }
virtual plugin_command_info *get_commands() {
return Module::get_commands();
diff --git a/src/organ.cpp b/src/organ.cpp
index c021f4a..513ddea 100644
--- a/src/organ.cpp
+++ b/src/organ.cpp
@@ -300,20 +300,31 @@ bool organ_audio_module::get_graph(int index, int subindex, float *data, int poi
if (index == par_master) {
if (subindex)
return false;
- enum { S = 1 << ORGAN_WAVE_BITS };
float *waveforms[9];
+ int S[9], S2[9];
+ enum { small_waves = organ_voice_base::wave_count_small};
for (int i = 0; i < 9; i++)
{
int wave = dsp::clip((int)(parameters->waveforms[i]), 0, (int)organ_voice_base::wave_count - 1);
- waveforms[i] = organ_voice_base::get_wave(wave).original;
+ if (wave >= small_waves)
+ {
+ waveforms[i] = organ_voice_base::get_big_wave(wave - small_waves);
+ S[i] = ORGAN_BIG_WAVE_SIZE;
+ S2[i] = ORGAN_WAVE_SIZE / 64;
+ }
+ else
+ {
+ waveforms[i] = organ_voice_base::get_wave(wave).original;
+ S[i] = S2[i] = ORGAN_WAVE_SIZE;
+ }
}
for (int i = 0; i < points; i++)
{
float sum = 0.f;
for (int j = 0; j < 9; j++)
{
- float shift = parameters->phase[j] * S / 360.0;
- sum += parameters->drawbars[j] * waveforms[j][int(parameters->harmonics[j] * i * S / points + shift) & (S - 1)];
+ float shift = parameters->phase[j] * S[j] / 360.0;
+ sum += parameters->drawbars[j] * waveforms[j][int(parameters->harmonics[j] * i * S2[j] / points + shift) & (S[j] - 1)];
}
data[i] = sum * 2 / (9 * 8);
}
@@ -339,6 +350,7 @@ const char *organ_wave_names[] = {
"Bell", "Bell2",
"W1", "W2", "W3", "W4", "W5", "W6", "W7", "W8", "W9",
"DSaw", "DSqr", "DPls",
+ "P:SynStr","P:WideStr","P:Sine","P:Bell","P:Space","P:Voice"
};
const char *organ_routing_names[] = { "Out", "Flt 1", "Flt 2" };
@@ -476,8 +488,8 @@ parameter_properties organ_audio_module::param_props[] = {
////////////////////////////////////////////////////////////////////////////
-waveform_family<ORGAN_WAVE_BITS> organ_voice_base::waves[organ_voice_base::wave_count];
-
+waveform_family<ORGAN_WAVE_BITS> organ_voice_base::waves[organ_voice_base::wave_count_small];
+organ_voice_base::big_wave_data organ_voice_base::big_waves[organ_voice_base::wave_count_big];
static void smoothen(bandlimiter<ORGAN_WAVE_BITS> &bl, float tmp[ORGAN_WAVE_SIZE])
{
@@ -504,6 +516,69 @@ static void phaseshift(bandlimiter<ORGAN_WAVE_BITS> &bl, float tmp[ORGAN_WAVE_SI
normalize_waveform(tmp, ORGAN_WAVE_SIZE);
}
+static void padsynth(bandlimiter<ORGAN_WAVE_BITS> blSrc, bandlimiter<ORGAN_BIG_WAVE_BITS> &blDest, organ_voice_base::big_wave_data result, int bwscale = 20, float bell_factor = 0)
+{
+ complex<float> orig_spectrum[ORGAN_WAVE_SIZE / 2];
+ for (int i = 0; i < ORGAN_WAVE_SIZE / 2; i++)
+ {
+ orig_spectrum[i] = blSrc.spectrum[i];
+// printf("@%d = %f\n", i, abs(orig_spectrum[i]));
+ }
+
+ int periods = 64 * ORGAN_BIG_WAVE_SIZE / ORGAN_WAVE_SIZE;
+ for (int i = 0; i <= ORGAN_BIG_WAVE_SIZE; i++) {
+ blDest.spectrum[i] = 0;
+ }
+ for (int i = 1; i <= ORGAN_WAVE_SIZE / 2; i++) {
+ float amp = abs(blSrc.spectrum[i]);
+ int bw = 1 + 20 * i;
+ float sum = 1;
+ int delta = 1;
+ if (bw > 20) delta = bw / 20;
+ for (int j = delta; j <= bw; j+=delta)
+ {
+ float p = j * 1.0 / bw;
+ sum += exp(-p*p);
+ }
+ if (sum < 0.0001)
+ continue;
+ amp /= sum;
+ int orig = i * periods + bell_factor * cos(i);
+ if (orig > 0 && orig < ORGAN_BIG_WAVE_SIZE / 2)
+ blDest.spectrum[orig] += amp;
+ for (int j = delta; j <= bw; j += delta)
+ {
+ float p = j * 1.0 / bw;
+ float val = amp * exp(-p * p);
+ int pos = orig + j * bwscale / 20;
+ if (pos < 1 || pos >= ORGAN_BIG_WAVE_SIZE / 2)
+ continue;
+ int pos2 = 2 * orig - pos;
+ if (pos2 < 1 || pos2 >= ORGAN_BIG_WAVE_SIZE / 2)
+ continue;
+ blDest.spectrum[pos] += val;
+ if (j)
+ blDest.spectrum[pos2] += val;
+ }
+ }
+ for (int i = 1; i <= ORGAN_BIG_WAVE_SIZE / 2; i++) {
+ float phase = M_PI * 2 * (rand() & 127) / 128;
+ complex<float> shift = complex<float>(cos(phase), sin(phase));
+ blDest.spectrum[i] *= shift;
+// printf("@%d = %f\n", i, abs(blDest.spectrum[i]));
+
+ blDest.spectrum[ORGAN_BIG_WAVE_SIZE - i] = conj(blDest.spectrum[i]);
+ }
+
+ blDest.compute_waveform(result);
+ normalize_waveform(result, ORGAN_BIG_WAVE_SIZE);
+ result[ORGAN_BIG_WAVE_SIZE] = result[0];
+ #if 0
+ for (int i =0 ; i<ORGAN_BIG_WAVE_SIZE + 1; i++)
+ printf("%f\n", result[i]);
+ #endif
+}
+
organ_voice_base::organ_voice_base(organ_parameters *_parameters)
: parameters(_parameters)
@@ -514,6 +589,7 @@ organ_voice_base::organ_voice_base(organ_parameters *_parameters)
{
float tmp[ORGAN_WAVE_SIZE];
bandlimiter<ORGAN_WAVE_BITS> bl;
+ bandlimiter<ORGAN_BIG_WAVE_BITS> blBig;
inited = true;
for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
tmp[i] = sin(i * 2 * M_PI / ORGAN_WAVE_SIZE);
@@ -671,6 +747,67 @@ organ_voice_base::organ_voice_base(organ_parameters *_parameters)
normalize_waveform(tmp, ORGAN_WAVE_SIZE);
phaseshift(bl, tmp);
waves[wave_dpls].make(bl, tmp);
+
+ for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
+ tmp[i] = -1 + (i * 2.0 / ORGAN_WAVE_SIZE);
+ normalize_waveform(tmp, ORGAN_WAVE_SIZE);
+ bl.compute_spectrum(tmp);
+ padsynth(bl, blBig, big_waves[wave_strings - wave_count_small], 20);
+
+ for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
+ tmp[i] = -1 + (i * 2.0 / ORGAN_WAVE_SIZE);
+ normalize_waveform(tmp, ORGAN_WAVE_SIZE);
+ bl.compute_spectrum(tmp);
+ padsynth(bl, blBig, big_waves[wave_strings2 - wave_count_small], 40);
+
+ for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
+ tmp[i] = sin(i * 2 * M_PI / ORGAN_WAVE_SIZE);
+ normalize_waveform(tmp, ORGAN_WAVE_SIZE);
+ bl.compute_spectrum(tmp);
+ padsynth(bl, blBig, big_waves[wave_sinepad - wave_count_small], 20);
+
+ for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
+ {
+ float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
+ float fm = 0.3 * sin(6*ph) + 0.2 * sin(11*ph) + 0.2 * cos(17*ph) - 0.2 * cos(19*ph);
+ tmp[i] = sin(5*ph + fm) + 0.7 * cos(7*ph - fm);
+ }
+ normalize_waveform(tmp, ORGAN_WAVE_SIZE);
+ bl.compute_spectrum(tmp);
+ padsynth(bl, blBig, big_waves[wave_bellpad - wave_count_small], 30, 30);
+
+ for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
+ {
+ float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
+ float fm = 0.3 * sin(3*ph) + 0.2 * sin(4*ph) + 0.2 * cos(5*ph) - 0.2 * cos(6*ph);
+ tmp[i] = sin(2*ph + fm) + 0.7 * cos(3*ph - fm);
+ }
+ normalize_waveform(tmp, ORGAN_WAVE_SIZE);
+ bl.compute_spectrum(tmp);
+ padsynth(bl, blBig, big_waves[wave_space - wave_count_small], 30, 30);
+
+#if 0
+ for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
+ {
+ float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
+ float fm = 0.3 * sin(3*ph) + 0.3 * sin(4*ph) + 0.3 * sin(5*ph);
+ tmp[i] = sin(ph + fm) + 0.5 * cos(2*ph - fm);
+ }
+ normalize_waveform(tmp, ORGAN_WAVE_SIZE);
+ bl.compute_spectrum(tmp);
+ padsynth(bl, blBig, big_waves[wave_choir - wave_count_small], 50, 10);
+#endif
+
+ for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
+ {
+ float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
+ float fm = 0.5 * sin(ph) + 0.5 * sin(2*ph) + 0.5 * sin(3*ph);
+ tmp[i] = sin(ph + fm) + 0.5 * cos(7*ph - 2 * fm) + 0.25 * cos(13*ph - 4 * fm);
+ }
+ normalize_waveform(tmp, ORGAN_WAVE_SIZE);
+ bl.compute_spectrum(tmp);
+ padsynth(bl, blBig, big_waves[wave_choir - wave_count_small], 50, 10);
+
}
}
@@ -726,7 +863,6 @@ void organ_voice::render_block() {
dsp::fixed_point<int, 20> tphase, tdphase;
unsigned int foldvalue = parameters->foldvalue;
int vibrato_mode = fastf2i_drm(parameters->lfo_mode);
- int muln = 0;
for (int h = 0; h < 9; h++)
{
float amp = parameters->drawbars[h];
@@ -739,29 +875,51 @@ void organ_voice::render_block() {
waveid = 0;
uint32_t rate = (dphase * hm).get();
- unsigned int foldback = 0;
- while (rate > foldvalue)
+ if (waveid >= wave_count_small)
{
- rate >>= 1;
- foldback++;
+ float *data = big_waves[waveid - wave_count_small];
+ if (!data)
+ continue;
+ hm.set(hm.get() >> 6);
+ dsp::fixed_point<int64_t, 20> tphase, tdphase;
+ tphase.set(((phase * hm).get()) + parameters->phaseshift[h]);
+ tdphase.set(rate >> 6);
+ float ampl = amp * 0.5f * (1 - parameters->pan[h]);
+ float ampr = amp * 0.5f * (1 + parameters->pan[h]);
+ float (*out)[Channels] = aux_buffers[dsp::fastf2i_drm(parameters->routing[h])];
+
+ for (int i=0; i < (int)BlockSize; i++) {
+ float wv = big_wave(data, tphase);
+ out[i][0] += wv * ampl;
+ out[i][1] += wv * ampr;
+ tphase += tdphase;
+ }
}
- hm.set(hm.get() >> foldback);
- data = waves[waveid].get_level(rate);
- if (!data)
- continue;
- tphase.set((uint32_t)((phase * hm).get()) + parameters->phaseshift[h]);
- tdphase.set((uint32_t)rate);
- float ampl = amp * 0.5f * (1 - parameters->pan[h]);
- float ampr = amp * 0.5f * (1 + parameters->pan[h]);
- float (*out)[Channels] = aux_buffers[dsp::fastf2i_drm(parameters->routing[h])];
- for (int i=0; i < (int)BlockSize; i++) {
- float wv = wave(data, tphase);
- out[i][0] += wv * ampl;
- out[i][1] += wv * ampr;
- tphase += tdphase;
+ else
+ {
+ unsigned int foldback = 0;
+ while (rate > foldvalue)
+ {
+ rate >>= 1;
+ foldback++;
+ }
+ hm.set(hm.get() >> foldback);
+ data = waves[waveid].get_level(rate);
+ if (!data)
+ continue;
+ tphase.set((uint32_t)((phase * hm).get()) + parameters->phaseshift[h]);
+ tdphase.set((uint32_t)rate);
+ float ampl = amp * 0.5f * (1 - parameters->pan[h]);
+ float ampr = amp * 0.5f * (1 + parameters->pan[h]);
+ float (*out)[Channels] = aux_buffers[dsp::fastf2i_drm(parameters->routing[h])];
+
+ for (int i=0; i < (int)BlockSize; i++) {
+ float wv = wave(data, tphase);
+ out[i][0] += wv * ampl;
+ out[i][1] += wv * ampr;
+ tphase += tdphase;
+ }
}
- if (h == 3 || h == 6)
- muln++;
}
expression.set_inertia(parameters->cutoff);
phase += dphase * BlockSize;
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list