[SCM] calf/master: + Organ: percussion enhancements, first attempt at foldover bandlimiting for 'bell' waves
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:37:11 UTC 2013
The following commit has been merged in the master branch:
commit 564991172be68fd1a6e7dc15af9957fb90f5ff14
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Sat May 3 23:32:08 2008 +0000
+ Organ: percussion enhancements, first attempt at foldover bandlimiting for 'bell' waves
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@168 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/src/calf/biquad.h b/src/calf/biquad.h
index bc4f73e..0e1c049 100644
--- a/src/calf/biquad.h
+++ b/src/calf/biquad.h
@@ -277,6 +277,18 @@ public:
dsp::zero(y2);
dsp::zero(w2);
}
+ inline void reset_d1()
+ {
+ dsp::zero(x1);
+ dsp::zero(y1);
+ }
+ inline void reset_d2()
+ {
+ dsp::zero(w1);
+ dsp::zero(x2);
+ dsp::zero(y2);
+ dsp::zero(w2);
+ }
};
};
diff --git a/src/calf/organ.h b/src/calf/organ.h
index 51040c7..2dacf85 100644
--- a/src/calf/organ.h
+++ b/src/calf/organ.h
@@ -52,7 +52,8 @@ struct organ_parameters {
float foldover;
float percussion_time;
float percussion_level;
- float percussion_harmonic;
+ float percussion_timbre;
+ float percussion_trigger;
float master;
organ_filter_parameters filters[organ_parameters::FilterCount];
@@ -69,7 +70,7 @@ struct organ_parameters {
float cutoff;
unsigned int foldvalue;
- inline int get_percussion_harmonic() { return dsp::fastf2i_drm(percussion_harmonic); }
+ inline int get_percussion_timbre() { return dsp::fastf2i_drm(percussion_timbre); }
};
#define ORGAN_WAVE_BITS 12
@@ -78,7 +79,7 @@ struct organ_parameters {
class organ_voice_base
{
public:
- enum {
+ enum organ_waveform {
wave_sine,
wave_sinepl1, wave_sinepl2, wave_sinepl3,
wave_ssaw, wave_ssqr, wave_spls, wave_saw, wave_sqr, wave_pulse, wave_sinepl05, wave_sqr05, wave_halfsin, wave_clvg, wave_bell, wave_bell2,
@@ -102,6 +103,12 @@ public:
lfomode_global,
lfomode_count
};
+ enum {
+ perctrig_first = 0,
+ perctrig_each,
+ perctrig_eachplus,
+ perctrig_count
+ };
protected:
static waveform_family<ORGAN_WAVE_BITS> waves[wave_count];
// dsp::sine_table<float, ORGAN_WAVE_SIZE, 1> sine_wave;
@@ -196,6 +203,7 @@ class percussion_voice: public organ_voice_base {
public:
int sample_rate;
dsp::fixed_point<int64_t, 20> phase, dphase;
+ dsp::biquad<float> filter;
percussion_voice(organ_parameters *_parameters)
: organ_voice_base(_parameters)
@@ -208,9 +216,16 @@ public:
}
void note_on(int note, int /*vel*/) {
- reset();
+ // do not reset phase if voice is still running (to prevent clicks, even at cost of slight loss of "percussiveness")
+ if (!amp.get_active())
+ {
+ phase = 0;
+ filter.reset_d1();
+ }
this->note = note;
- dphase.set(synth::midi_note_to_phase(note, 0, sample_rate));
+ int timbre = parameters->get_percussion_timbre();
+ static const int harm_muls[8] = { 1, 2, 3, 4, 8, 1, 2, 4 };
+ dphase.set(synth::midi_note_to_phase(note, 0, sample_rate) * harm_muls[timbre]);
amp.set(1.0f);
}
@@ -223,23 +238,44 @@ public:
return;
if (parameters->percussion_level < small_value<float>())
return;
- int percussion_harmonic = 2 * parameters->get_percussion_harmonic();
+ static const organ_waveform wave_ids[] = { wave_sine, wave_sine, wave_sine, wave_bell, wave_bell, wave_sqr, wave_sqr, wave_sqr };
float level = parameters->percussion_level * 9;
// XXXKF the decay needs work!
double age_const = parameters->perc_decay_const;
- float *data = waves[wave_sine].begin()->second;
- for (int i = 0; i < nsamples; i++) {
- float osc = level * wave(data, percussion_harmonic * phase);
- osc *= level * amp.get();
- buf[i][0] += osc;
- buf[i][1] += osc;
- amp.age_exp(age_const, 1.0 / 32768.0);
- phase += dphase;
+ int timbre = parameters->get_percussion_timbre();
+ float *data = waves[wave_ids[timbre]].get_level(dphase.get());
+ if (timbre < 3)
+ {
+ for (int i = 0; i < nsamples; i++) {
+ float osc = level * wave(data, phase);
+ osc *= level * amp.get();
+ buf[i][0] += osc;
+ buf[i][1] += osc;
+ amp.age_exp(age_const, 1.0 / 32768.0);
+ phase += dphase;
+ }
+ }
+ else
+ {
+ float av = amp.get();
+ filter.set_lp_rbj(400 + 5000 * (av * 0.2 + av * av * 0.8), 0.707, sample_rate);
+ for (int i = 0; i < nsamples; i++) {
+ float osc = filter.process_d1(level * wave(data, phase));
+ osc *= level * amp.get();
+ buf[i][0] += osc;
+ buf[i][1] += osc;
+ amp.age_exp(age_const, 1.0 / 32768.0);
+ phase += dphase;
+ }
+ filter.sanitize_d1();
}
}
bool get_active() {
return (note != -1) && amp.get_active();
}
+ bool get_noticable() {
+ return (note != -1) && (amp.get() > 0.2);
+ }
void setup(int sr) {
sample_rate = sr;
}
@@ -259,7 +295,8 @@ struct drawbar_organ: public synth::basic_synth {
par_pan1, par_pan2, par_pan3, par_pan4, par_pan5, par_pan6, par_pan7, par_pan8, par_pan9,
par_routing1, par_routing2, par_routing3, par_routing4, par_routing5, par_routing6, par_routing7, par_routing8, par_routing9,
par_foldover,
- par_percdecay, par_perclevel, par_percharm, par_master,
+ par_percdecay, par_perclevel, par_perctimbre, par_perctrigger,
+ par_master,
par_f1cutoff, par_f1res, par_f1env1, par_f1env2, par_f1env3, par_f1keyf,
par_f2cutoff, par_f2res, par_f2env1, par_f2env2, par_f2env3, par_f2keyf,
par_eg1attack, par_eg1decay, par_eg1sustain, par_eg1release, par_eg1velscl, par_eg1ampctl,
@@ -296,7 +333,7 @@ struct drawbar_organ: public synth::basic_synth {
v->parameters = parameters;
return v;
}
- virtual void first_note_on(int note, int vel) {
+ virtual void percussion_note_on(int note, int vel) {
percussion.note_on(note, vel);
}
virtual void setup(int sr) {
@@ -314,6 +351,18 @@ struct drawbar_organ: public synth::basic_synth {
}
synth::basic_synth::control_change(controller, value);
}
+ virtual bool check_percussion() {
+ switch(dsp::fastf2i_drm(parameters->percussion_trigger))
+ {
+ case organ_voice_base::perctrig_first:
+ return active_voices.empty();
+ case organ_voice_base::perctrig_each:
+ default:
+ return true;
+ case organ_voice_base::perctrig_eachplus:
+ return !percussion.get_noticable();
+ }
+ }
};
};
diff --git a/src/calf/osc.h b/src/calf/osc.h
index 1948282..e3d9915 100644
--- a/src/calf/osc.h
+++ b/src/calf/osc.h
@@ -81,15 +81,30 @@ struct bandlimiter
/// very basic bandlimiting (brickwall filter)
/// might need to be improved much in future!
- void make_waveform(float output[SIZE], int cutoff)
+ void make_waveform(float output[SIZE], int cutoff, bool foldover = false)
{
std::complex<float> new_spec[SIZE], iffted[SIZE];
for (int i = 0; i < cutoff; i++)
new_spec[i] = spectrum[i],
new_spec[SIZE - 1 - i] = spectrum[SIZE - 1 - i];
- for (int i = cutoff; i < SIZE / 2; i++)
- new_spec[i] = 0.f,
- new_spec[SIZE - 1 - i] = 0.f;
+ if (foldover)
+ {
+ std::complex<float> half(0.5);
+ cutoff /= 2;
+ for (int i = SIZE / 2; i >= cutoff; i--)
+ {
+ new_spec[i / 2] += new_spec[i] * half;
+ new_spec[SIZE - 1 - i / 2] += new_spec[SIZE - 1 - i] * half;
+ new_spec[i] = 0.f,
+ new_spec[SIZE - 1 - i] = 0.f;
+ }
+ }
+ else
+ {
+ for (int i = cutoff; i < SIZE / 2; i++)
+ new_spec[i] = 0.f,
+ new_spec[SIZE - 1 - i] = 0.f;
+ }
fft.calculate(new_spec, iffted, true);
for (int i = 0; i < SIZE; i++)
output[i] = iffted[i].real();
@@ -109,7 +124,7 @@ struct waveform_family: public map<uint32_t, float *>
using map<uint32_t, float *>::lower_bound;
float original[SIZE];
- void make(bandlimiter<SIZE_BITS> &bl, float input[SIZE])
+ void make(bandlimiter<SIZE_BITS> &bl, float input[SIZE], bool foldover = false)
{
memcpy(original, input, sizeof(original));
bl.compute_spectrum(input);
@@ -118,7 +133,7 @@ struct waveform_family: public map<uint32_t, float *>
uint32_t multiple = 1, base = 1 << (32 - SIZE_BITS);
while(multiple < SIZE / 2) {
float *wf = new float[SIZE+1];
- bl.make_waveform(wf, (int)((1 << SIZE_BITS) / (1.5 * multiple)));
+ bl.make_waveform(wf, (int)((1 << SIZE_BITS) / (1.5 * multiple)), foldover);
wf[SIZE] = wf[0];
(*this)[base * multiple] = wf;
multiple = multiple << 1;
diff --git a/src/calf/synth.h b/src/calf/synth.h
index 4d74eab..2fbbcf5 100644
--- a/src/calf/synth.h
+++ b/src/calf/synth.h
@@ -199,10 +199,11 @@ public:
virtual synth::voice *alloc_voice()=0;
virtual void render_to(float (*output)[2], int nsamples);
virtual void note_on(int note, int vel);
- virtual void first_note_on(int note, int vel) {}
+ virtual void percussion_note_on(int note, int vel) {}
virtual void control_change(int ctl, int val);
virtual void note_off(int note, int vel);
virtual void on_pedal_release();
+ virtual bool check_percussion() { return active_voices.empty(); }
virtual ~basic_synth();
};
diff --git a/src/organ.cpp b/src/organ.cpp
index f9601da..16daba7 100644
--- a/src/organ.cpp
+++ b/src/organ.cpp
@@ -69,8 +69,12 @@ const char *organ_audio_module::get_gui_xml()
"<value param=\"perc_level\"/>"
"</vbox>"
"<vbox>"
- "<label param=\"perc_harm\"/>"
- "<combo param=\"perc_harm\"/>"
+ "<label param=\"perc_timbre\"/>"
+ "<combo param=\"perc_timbre\"/>"
+ "</vbox>"
+ "<vbox>"
+ "<label param=\"perc_trigger\"/>"
+ "<combo param=\"perc_trigger\"/>"
"</vbox>"
"<vbox>"
"<label param=\"master\"/>"
@@ -286,7 +290,11 @@ const char *organ_audio_module::get_gui_xml()
const char *organ_audio_module::port_names[] = {"Out L", "Out R"};
-const char *organ_percussion_harmonic_names[] = { "2nd", "3rd" };
+const char *organ_percussion_timbre_names[] = {
+ "16' Sine", "8' Sine", "5 1/3' Sine",
+ "4' Bell", "2' Bell",
+ "16' Sqr", "8' Sqr", "4' Sqr" };
+const char *organ_percussion_trigger_names[] = { "First note", "Each note", "Each, no retrig" };
const char *organ_wave_names[] = {
"Sin",
@@ -379,7 +387,8 @@ parameter_properties organ_audio_module::param_props[] = {
{ 96, 0, 127, 128, PF_INT | PF_CTL_KNOB | PF_UNIT_NOTE, NULL, "foldnote", "Foldover" },
{ 200, 10, 3000, 100, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL, "perc_decay", "Perc. decay" },
{ 0.25, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "perc_level", "Perc. level" },
- { 3, 2, 3, 1, PF_ENUM | PF_CTL_COMBO, organ_percussion_harmonic_names, "perc_harm", "Perc. harmonic" },
+ { 2, 0, 7, 1, PF_ENUM | PF_CTL_COMBO, organ_percussion_timbre_names, "perc_timbre", "Perc. timbre" },
+ { 0, 0, organ_voice_base::perctrig_count - 1, 0, PF_ENUM | PF_CTL_COMBO, organ_percussion_trigger_names, "perc_trigger", "Perc. trigger" },
{ 0.1, 0, 1, 100, PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB, NULL, "master", "Volume" },
@@ -525,11 +534,11 @@ organ_voice_base::organ_voice_base(organ_parameters *_parameters)
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.3 * sin(11*ph) + 0.3 * cos(17*ph) - 0.3 * cos(19*ph);
- tmp[i] = sin(5*ph + fm) + cos(7*ph - fm);
+ 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);
- waves[wave_bell].make(bl, tmp);
+ waves[wave_bell].make(bl, tmp, true);
for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
{
float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
@@ -537,7 +546,7 @@ organ_voice_base::organ_voice_base(organ_parameters *_parameters)
tmp[i] = sin(3*ph + fm) + cos(7*ph - fm);
}
normalize_waveform(tmp, ORGAN_WAVE_SIZE);
- waves[wave_bell2].make(bl, tmp);
+ waves[wave_bell2].make(bl, tmp, true);
for (int i = 0; i < ORGAN_WAVE_SIZE; i++)
{
float ph = i * 2 * M_PI / ORGAN_WAVE_SIZE;
diff --git a/src/synth.cpp b/src/synth.cpp
index 682be9b..f659fe8 100644
--- a/src/synth.cpp
+++ b/src/synth.cpp
@@ -60,7 +60,7 @@ void basic_synth::note_on(int note, int vel)
note_off(note, 0);
return;
}
- bool perc = active_voices.empty();
+ bool perc = check_percussion();
synth::voice *v = alloc_voice();
v->setup(sample_rate);
v->released = false;
@@ -69,7 +69,7 @@ void basic_synth::note_on(int note, int vel)
v->note_on(note, vel);
active_voices.push_back(v);
if (perc) {
- first_note_on(note, vel);
+ percussion_note_on(note, vel);
}
}
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list