From b26845ca1f8b63e2eff23c501c3d936df5669c23 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 21 Jan 2010 17:40:30 +0000 Subject: [PATCH] Oscillator pan control --- engine.c | 22 ++++++++++++++++++++++ program.txt | 33 +++++++++++++++++++++++++++++++++ voice.c | 27 +++++++++++++++++++++++---- voice.h | 8 +++----- 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/engine.c b/engine.c index 4cb8457..b6288d9 100644 --- a/engine.c +++ b/engine.c @@ -66,6 +66,28 @@ void engine_load_program() _engine.params[osc].freq_mult.value = freq; _engine.params[osc].phase.value = phase; } + } else if (!strncmp(buf, "pan", 3)) { + int pan; + char ssource[1024]; + float parm1; + float parm2; + int r = sscanf(buf, "pan %d %s %f %f", &pan, ssource, &parm1, &parm2); + if (r >= 4 && pan >= 0 && pan <= VOICE_OSCILLATORS) { + int source = 0; + if (!strcmp(ssource, "FIXED")) { + _engine.params[pan].pan_type = PAN_FIXED; + _engine.params[pan].pan_level = parm1; + _engine.params[pan].pan_level_r = parm2; + } else if (!strcmp(ssource, "OSC")) { + _engine.params[pan].pan_type = PAN_OSC; + _engine.params[pan].pan_source = parm1; + _engine.params[pan].pan_level = parm2; + } else if (!strcmp(ssource, "LFO")) { + _engine.params[pan].pan_type = PAN_LFO; + _engine.params[pan].pan_source = parm1; + _engine.params[pan].pan_level = parm2; + } + } } else if (!strncmp(buf, "env", 3)) { int env; float attack; diff --git a/program.txt b/program.txt index 60425f2..ffc3976 100644 --- a/program.txt +++ b/program.txt @@ -8,9 +8,42 @@ osc 0 SINE 0.5 1.0 0.0 osc 1 TRIANGLE 0.5 1.01 0.25 osc 2 SQUARE 0.5 2.0 0.0 osc 3 MOOGSAW 0.5 0.99 0.0 +# Pan, Source, Parm1, Parm2 +# if source is FIXED, Parm1 = L level, Parm2 = R level +# else Parm1 = LFO/OSC source, Parm2 = depth +pan 0 FIXED 1.0 1.0 +pan 1 LFO 1 0.5 +pan 2 OSC 0 0.25 +pan 3 LFO 2 0.5 # Env, Attack, Hold, Decay, Sustain, Release env 0 0.0125 0.025 5.0 0.0 0.25 env 1 0.0125 0.025 5.0 0.0 0.25 env 2 0.0125 0.025 5.0 0.0 0.25 env 3 0.0125 0.025 5.0 0.0 0.25 cutoff_env 0 0.0 0.0 0.5 0.0 0.25 + +voice 1 +# LFO, Freq +lfo 0 2.0 +lfo 1 3.0 +lfo 2 1.0 +# Osc, Shape, Level, Freq, Phase +osc 0 MOOGSAW 0.75 1.0 0.0 +osc 1 EXP 0.5 1.0 0.1 +osc 2 SQUARE 0.25 0.5 0.25 +osc 3 SQUARE 0.25 0.5 0.75 +# Pan, Source, Parm1, Parm2 +wwwwwwwwwweerr +# if source is FIXED, Parm1 = L level, Parm2 = R level +# else Parm1 = LFO/OSC source, Parm2 = depth +pan 0 FIXED 1.0 1.0 +pan 1 FIXED 1.0 1.0 +pan 2 LFO 0 1.0 +pan 3 LFO 1 1.0 +# Env, Attack, Hold, Decay, Sustain, Release +env 0 0.5 0.0 0.25 0.5 2.0 +env 1 1.0 0.0 0.5 0.25 2.0 +env 2 0.1 0.1 1.0 0.0 0.5 +env 3 0.1 0.1 1.0 0.0 0.5 +cutoff_env 0 0.0 0.0 1.5 0.0 0.25 + diff --git a/voice.c b/voice.c index 4b2dd6c..179f333 100644 --- a/voice.c +++ b/voice.c @@ -69,11 +69,30 @@ void voice_run(struct voice_t *voice, uint32_t samples, float *left, float *righ } for (i = 0; i < VOICE_OSCILLATORS; i++) { - float s = osc_getsample(&voice->osc[i]); - + float ss; + float pl = osc_getsample(&voice->osc[i]); + float pr = pl; // Mix - l += a[i] * s; - r += a[i] * s; + + switch (_engine.params[i].pan_type) { + case PAN_FIXED: + pl *= _engine.params[i].pan_level; + pr *= _engine.params[i].pan_level_r; + break; + case PAN_OSC: + ss = osc_getsample(&voice->osc[_engine.params[i].pan_source]) * _engine.params[i].pan_level * 0.5; + pl *= 0.5 + ss; + pr *= 0.5 - ss; + break; + case PAN_LFO: + ss = osc_getsample(&_engine.lfo[_engine.params[i].pan_source]) * _engine.params[i].pan_level * 0.5; + pl *= 0.5 + ss; + pr *= 0.5 - ss; + break; + } + + l += a[i] * pl; + r += a[i] * pr; } // Amplitude mod diff --git a/voice.h b/voice.h index e430e57..44eff7a 100644 --- a/voice.h +++ b/voice.h @@ -11,11 +11,9 @@ enum { struct voice_param_t { uint8_t pan_type; - union { - float pan; - uint8_t pan_osc; - uint8_t pan_lfo; - } u; + uint8_t pan_source; + double pan_level; + double pan_level_r; struct control_t shape; struct control_t level;