[SCM] calf/master: + True ADSR envelope (ok, kfoltman's own cheated ADSR, but that shouldn't matter) - still needs clicks fixed, but pretty functional already + Basic constant-time portamento (not really great!)
js at users.alioth.debian.org
js at users.alioth.debian.org
Tue May 7 15:36:45 UTC 2013
The following commit has been merged in the master branch:
commit 0e9e9937c44e1afb64272970ad4b5ff47209ff01
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date: Sat Dec 15 00:09:13 2007 +0000
+ True ADSR envelope (ok, kfoltman's own cheated ADSR, but that shouldn't matter) - still needs clicks fixed, but pretty functional already
+ Basic constant-time portamento (not really great!)
git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@21 78b06b96-2940-0410-b7fc-879d825d01d8
diff --git a/src/calf/modules_dev.h b/src/calf/modules_dev.h
index b9c2d89..0928d8f 100644
--- a/src/calf/modules_dev.h
+++ b/src/calf/modules_dev.h
@@ -41,7 +41,7 @@ class monosynth_audio_module: public null_audio_module
public:
enum { wave_saw, wave_sqr, wave_pulse, wave_sine, wave_triangle, wave_count };
enum { flt_lp12, flt_lp24, flt_2lp12, flt_hp12, flt_lpbr, flt_hpbr, flt_bp6, flt_2bp6 };
- enum { par_wave1, par_wave2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_envmod, par_envtores, par_decay, par_keyfollow, par_legato, par_vel2amp, par_vel2filter, param_count };
+ enum { par_wave1, par_wave2, par_detune, par_osc2xpose, par_oscmode, par_oscmix, par_filtertype, par_cutoff, par_resonance, par_cutoffsep, par_envmod, par_envtores, par_attack, par_decay, par_sustain, par_release, par_keyfollow, par_legato, par_portamento, par_vel2amp, par_vel2filter, param_count };
enum { in_count = 0, out_count = 2, support_midi = true, rt_capable = true };
enum { step_size = 64 };
static const char *param_names[];
@@ -59,12 +59,12 @@ public:
biquad<float> filter;
biquad<float> filter2;
int wave1, wave2, filter_type;
- float freq, cutoff, decay_factor, fgain, separation;
+ float freq, start_freq, target_freq, cutoff, decay_factor, fgain, separation;
float detune, xpose, xfade, pitchbend, ampctl, fltctl, queue_vel;
- int voice_age;
- float odcr;
+ float odcr, porta_time;
int queue_note_on;
bool legato;
+ adsr envelope;
static parameter_properties param_props[];
void set_sample_rate(uint32_t sr) {
@@ -74,14 +74,16 @@ public:
}
void delayed_note_on()
{
- freq = 440 * pow(2.0, (queue_note_on - 69) / 12.0);
+ porta_time = 0.f;
+ start_freq = freq;
+ target_freq = freq = 440 * pow(2.0, (queue_note_on - 69) / 12.0);
ampctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2amp];
fltctl = 1.0 + (queue_vel - 1.0) * *params[par_vel2filter];
set_frequency();
osc1.waveform = waves[wave1].get_level(osc1.phasedelta);
osc2.waveform = waves[wave2].get_level(osc2.phasedelta);
- if (!running)
+ if (!running || envelope.released())
{
osc1.reset();
osc2.reset();
@@ -110,13 +112,13 @@ public:
default:
break;
}
- voice_age = 0;
+ envelope.note_on();
running = true;
}
gate = true;
stopping = false;
if (!legato)
- voice_age = 0;
+ envelope.note_on();
queue_note_on = -1;
}
void note_on(int note, int vel)
@@ -127,8 +129,10 @@ public:
}
void note_off(int note, int vel)
{
- if (note == last_key)
+ if (note == last_key) {
gate = false;
+ envelope.note_off();
+ }
}
void pitch_bend(int value)
{
@@ -140,6 +144,8 @@ public:
osc2.set_freq(freq * (detune) * pitchbend * xpose, srate);
}
void params_changed() {
+ float sf = 0.001f;
+ envelope.set(*params[par_attack] * sf, *params[par_decay] * sf, *params[par_sustain], *params[par_release] * sf, srate / step_size);
filter_type = fastf2i_drm(*params[par_filtertype]);
decay_factor = odcr * 1000.0 / *params[par_decay];
separation = pow(2.0, *params[par_cutoffsep] / 1200.0);
@@ -253,8 +259,22 @@ public:
dsp::zero(buffer2, step_size);
return;
}
+ float porta_total_time = *params[par_portamento] * 0.001f;
+
+ if (porta_total_time >= 0.00101f && porta_time >= 0) {
+ // XXXKF this is criminal, optimize!
+ float point = porta_time / porta_total_time;
+ if (point >= 1.0f) {
+ freq = target_freq;
+ porta_time = -1;
+ } else {
+ freq = start_freq * pow(target_freq / start_freq, point);
+ porta_time += odcr;
+ }
+ }
set_frequency();
- float env = max(0.f, 1.f - voice_age * decay_factor);
+ envelope.advance();
+ float env = envelope.value;
cutoff = *params[par_cutoff] * pow(2.0f, env * fltctl * *params[par_envmod] * (1.f / 1200.f));
if (*params[par_keyfollow] >= 0.5f)
cutoff *= freq / 264.0f;
@@ -320,7 +340,7 @@ public:
calculate_buffer_stereo();
break;
}
- if (!gate)
+ if (envelope.state == adsr::STOP)
{
for (int i = 0; i < step_size; i++)
buffer[i] *= (step_size - i) * (1.0f / step_size);
@@ -329,8 +349,6 @@ public:
buffer2[i] *= (step_size - i) * (1.0f / step_size);
stopping = true;
}
-
- voice_age++;
}
uint32_t process(uint32_t offset, uint32_t nsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
if (!running && queue_note_on == -1)
diff --git a/src/calf/synth.h b/src/calf/synth.h
index 7efc54a..3c02c90 100644
--- a/src/calf/synth.h
+++ b/src/calf/synth.h
@@ -156,6 +156,99 @@ public:
virtual ~basic_synth();
};
+// temporarily here, will be moved to separate file later
+// this is a weird envelope and perhaps won't turn out to
+// be a good idea in the long run, still, worth trying
+class adsr
+{
+public:
+ enum env_state { STOP, ATTACK, DECAY, SUSTAIN, RELEASE, LOCKDECAY };
+
+ env_state state;
+ // note: these are *rates*, not times
+ float attack, decay, sustain, release;
+ float value;
+
+ adsr()
+ {
+ attack = decay = sustain = release = 0.f;
+ reset();
+ }
+ inline void reset()
+ {
+ value = 0.f;
+ state = STOP;
+ }
+ inline void set(float a, float d, float s, float r, float er)
+ {
+ attack = 1.0 / (a * er);
+ decay = (1 - s) / (d * er);
+ sustain = s;
+ release = s / (r * er);
+ }
+ inline bool released()
+ {
+ return state == LOCKDECAY || state == RELEASE || state == STOP;
+ }
+ inline void note_on()
+ {
+ state = ATTACK;
+ }
+ inline void note_off()
+ {
+ if (state == STOP)
+ return;
+ if (value > sustain && decay > release)
+ state = LOCKDECAY;
+ else
+ state = RELEASE;
+ }
+ inline void advance()
+ {
+ switch(state)
+ {
+ case ATTACK:
+ value += attack;
+ if (value >= 1.0) {
+ value = 1.0;
+ state = DECAY;
+ }
+ break;
+ case DECAY:
+ value -= decay;
+ if (value < sustain)
+ {
+ value = sustain;
+ state = SUSTAIN;
+ }
+ break;
+ case LOCKDECAY:
+ value -= decay;
+ if (value < sustain)
+ {
+ if (value < 0.f)
+ value = 0.f;
+ state = RELEASE;
+ }
+ break;
+ case SUSTAIN:
+ value = sustain;
+ break;
+ case RELEASE:
+ value -= release;
+ if (value < 0.f) {
+ value = 0.f;
+ state = STOP;
+ }
+ break;
+ case STOP:
+ value = 0.f;
+ break;
+ }
+ }
+};
+
+
}
#endif
diff --git a/src/modules.cpp b/src/modules.cpp
index a173753..f4ae503 100644
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@ -140,7 +140,13 @@ synth::ladspa_wrapper<organ_audio_module> organ(organ_info);
////////////////////////////////////////////////////////////////////////////
#ifdef ENABLE_EXPERIMENTAL
-const char *monosynth_audio_module::param_names[] = {"Out L", "Out R", "Osc1 Wave", "Osc2 Wave", "Osc 1/2 Detune", "Osc 2 Transpose", "Phase Mode", "Osc Mix", "Filter", "Cutoff", "Resonance", "Separation", "Env->Cutoff", "Env->Res", "Decay", "Key Follow", "Legato", "Vel->Amp", "Vel->Filter"};
+const char *monosynth_audio_module::param_names[] = {
+ "Out L", "Out R",
+ "Osc1 Wave", "Osc2 Wave", "Osc 1/2 Detune", "Osc 2 Transpose", "Phase Mode", "Osc Mix",
+ "Filter", "Cutoff", "Resonance", "Separation", "Env->Cutoff", "Env->Res",
+ "Attack", "Decay", "Sustain", "Release",
+ "Key Follow", "Legato", "Portamento",
+ "Vel->Amp", "Vel->Filter"};
const char *monosynth_waveform_names[] = { "Sawtooth", "Square", "Pulse", "Sine", "Triangle" };
const char *monosynth_mode_names[] = { "0 : 0", "0 : 180", "0 : 90", "90 : 90", "90 : 270", "Random" };
@@ -169,9 +175,16 @@ parameter_properties monosynth_audio_module::param_props[] = {
{ 0, -2400, 2400, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL },
{ 8000, -10800,10800, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_CENTS, NULL },
{ 0.5, 0, 1, 1.01, PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB, NULL },
+
+ { 10, 1,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+ { 350, 10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+ { 0.5, 0, 1, 1.01, PF_FLOAT | PF_SCALE_PERC, NULL },
{ 350, 10,20000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+
{ 0, 0, 1, 1.01, PF_BOOL | PF_CTL_TOGGLE, NULL },
{ 0, 0, 1, 1.01, PF_BOOL | PF_CTL_TOGGLE, NULL },
+ { 1, 1, 2000, 1.01, PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_MSEC, NULL },
+
{ 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL },
{ 0, 0, 1, 0.1, PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB, NULL },
};
--
calf audio plugins packaging
More information about the pkg-multimedia-commits
mailing list