Skip to content

Commit

Permalink
RingModulator gets AudioIn Source (#7325)
Browse files Browse the repository at this point in the history
RingModulator effect can use audio in to ring modulate
against. This is needed for surge-synthesizer/surge-rack#454
but we can expose it in surge vst proper also, so do so here.
  • Loading branch information
baconpaul committed Nov 21, 2023
1 parent b1a6cb0 commit ccb3f50
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 28 deletions.
12 changes: 12 additions & 0 deletions src/common/Parameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ bool Parameter::is_discrete_selection() const
{
case ct_sinefmlegacy:
case ct_sineoscmode:
case ct_ringmod_sineoscmode:
case ct_wt2window:
case ct_airwindows_fx:
case ct_flangermode:
Expand Down Expand Up @@ -1057,6 +1058,12 @@ void Parameter::set_type(int ctrltype)
valtype = vt_int;
val_default.i = 0;
break;
case ct_ringmod_sineoscmode:
val_min.i = 0;
val_max.i = 28; // above sineosc + 1 for audio in
valtype = vt_int;
val_default.i = 0;
break;
case ct_sinefmlegacy:
val_min.i = 0;
val_max.i = 1;
Expand Down Expand Up @@ -3793,6 +3800,7 @@ std::string Parameter::get_display(bool external, float ef) const
break;
}
break;
case ct_ringmod_sineoscmode:
case ct_sineoscmode:
switch (i)
{
Expand All @@ -3806,6 +3814,9 @@ std::string Parameter::get_display(bool external, float ef) const
case 7:
txt = fmt::format("Wave {:d} (TX {:d})", i + 1, i + 1);
break;
case 28: // only hit in ringmod_sineoscmode
txt = "Audio In";
break;
default:
txt = fmt::format("Wave {:d}", i + 1);
}
Expand Down Expand Up @@ -4185,6 +4196,7 @@ bool Parameter::can_be_nondestructively_modulated() const
case ct_osccount:
case ct_pitch_octave:
case ct_wt2window:
case ct_ringmod_sineoscmode:
case ct_sineoscmode:
case ct_sinefmlegacy:
case ct_fmratio_int:
Expand Down
1 change: 1 addition & 0 deletions src/common/Parameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ enum ctrltypes
ct_stereowidth,
ct_character,
ct_sineoscmode,
ct_ringmod_sineoscmode,
ct_sinefmlegacy,
ct_countedset_percent, // what % through a counted set are we
ct_countedset_percent_extendable, // what % through a counted set are we
Expand Down
104 changes: 76 additions & 28 deletions src/common/dsp/effects/RingModulatorEffect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ void RingModulatorEffect::process(float *dataL, float *dataR)
float dphase[MAX_UNISON];
auto uni = std::max(1, *pd_int[rm_unison_voices]);

auto isAudioIn = (*pd_int[rm_carrier_shape] == fxdata->p[rm_carrier_shape].val_max.i);

if (isAudioIn)
uni = 1;

// Has unison reset? If so modify settings
if (uni != last_unison)
{
Expand Down Expand Up @@ -114,24 +119,27 @@ void RingModulatorEffect::process(float *dataL, float *dataR)
dataOS[1] = dataR;
#endif

for (int u = 0; u < uni; ++u)
if (!isAudioIn)
{
// need to calc this every time since carrier freq could change
if (fxdata->p[rm_unison_detune].absolute)
{
dphase[u] =
(storage->note_to_pitch(*pd_float[rm_carrier_freq] +
fxdata->p[rm_unison_detune].get_extended(
*pd_float[rm_unison_detune] * detune_offset[u]))) *
sri;
}
else
for (int u = 0; u < uni; ++u)
{
dphase[u] =
storage->note_to_pitch(*pd_float[rm_carrier_freq] +
fxdata->p[rm_unison_detune].get_extended(
*pd_float[rm_unison_detune] * detune_offset[u])) *
Tunings::MIDI_0_FREQ * sri;
// need to calc this every time since carrier freq could change
if (fxdata->p[rm_unison_detune].absolute)
{
dphase[u] =
(storage->note_to_pitch(*pd_float[rm_carrier_freq] +
fxdata->p[rm_unison_detune].get_extended(
*pd_float[rm_unison_detune] * detune_offset[u]))) *
sri;
}
else
{
dphase[u] =
storage->note_to_pitch(*pd_float[rm_carrier_freq] +
fxdata->p[rm_unison_detune].get_extended(
*pd_float[rm_unison_detune] * detune_offset[u])) *
Tunings::MIDI_0_FREQ * sri;
}
}
}

Expand All @@ -140,25 +148,36 @@ void RingModulatorEffect::process(float *dataL, float *dataR)
float resL = 0, resR = 0;
for (int u = 0; u < uni; ++u)
{
// TODO efficiency of course
auto vc = SineOscillator::valueFromSinAndCos(
sst::basic_blocks::dsp::fastsin(2.0 * M_PI * (phase[u] - 0.5)),
sst::basic_blocks::dsp::fastcos(2.0 * M_PI * (phase[u] - 0.5)),
*pd_int[rm_carrier_shape]);
phase[u] += dphase[u];

if (phase[u] > 1)
float vc[2]{0.f, 0.f};

if (isAudioIn)
{
phase[u] -= (int)phase[u];
vc[0] = storage->audio_in[0][i] * 2.0;
vc[1] = storage->audio_in[1][i] * 2.0;
}
else
{
// TODO efficiency of course
vc[0] = SineOscillator::valueFromSinAndCos(
sst::basic_blocks::dsp::fastsin(2.0 * M_PI * (phase[u] - 0.5)),
sst::basic_blocks::dsp::fastcos(2.0 * M_PI * (phase[u] - 0.5)),
*pd_int[rm_carrier_shape]);
vc[1] = vc[0];
phase[u] += dphase[u];

if (phase[u] > 1)
{
phase[u] -= (int)phase[u];
}
}

for (int c = 0; c < 2; ++c)
{
auto vin = (c == 0 ? dataOS[0][i] : dataOS[1][i]);
auto wd = 1.0;

auto A = 0.5 * vin + vc;
auto B = vc - 0.5 * vin;
auto A = 0.5 * vin + vc[c];
auto B = vc[c] - 0.5 * vin;

float dPA = diode_sim(A);
float dMA = diode_sim(-A);
Expand Down Expand Up @@ -240,16 +259,45 @@ int RingModulatorEffect::group_label_ypos(int id)

void RingModulatorEffect::init_ctrltypes()
{
static struct RQD : public ParameterDynamicDeactivationFunction
{
bool getValue(const Parameter *p) const override
{
auto fx = &(p->storage->getPatch().fx[p->ctrlgroup_entry]);
auto idx = p - fx->p;
auto isAudioIn = (fx->p[rm_carrier_shape].val.i == fx->p[rm_carrier_shape].val_max.i);

switch (idx)
{
case rm_carrier_freq:
case rm_unison_detune:
case rm_unison_voices:
return isAudioIn;
default:
break;
}

return false;
}
Parameter *getPrimaryDeactivationDriver(const Parameter *p) const override
{
return nullptr;
}
} rmGroupDeact;

Effect::init_ctrltypes();

fxdata->p[rm_carrier_shape].set_name("Shape");
fxdata->p[rm_carrier_shape].set_type(ct_sineoscmode);
fxdata->p[rm_carrier_shape].set_type(ct_ringmod_sineoscmode);
fxdata->p[rm_carrier_freq].set_name("Frequency");
fxdata->p[rm_carrier_freq].set_type(ct_freq_ringmod);
fxdata->p[rm_carrier_freq].dynamicDeactivation = &rmGroupDeact;
fxdata->p[rm_unison_detune].set_name("Unison Detune");
fxdata->p[rm_unison_detune].set_type(ct_oscspread);
fxdata->p[rm_unison_detune].dynamicDeactivation = &rmGroupDeact;
fxdata->p[rm_unison_voices].set_name("Unison Voices");
fxdata->p[rm_unison_voices].set_type(ct_osccount);
fxdata->p[rm_unison_voices].dynamicDeactivation = &rmGroupDeact;

fxdata->p[rm_diode_fwdbias].set_name("Forward Bias");
fxdata->p[rm_diode_fwdbias].set_type(ct_percent);
Expand Down

0 comments on commit ccb3f50

Please sign in to comment.