Skip to content

Commit

Permalink
And a Normal distribution to each Random
Browse files Browse the repository at this point in the history
The Random Bi and Uni polar have a normally distributed output
as well as a uniform one, implemented as modulator indices.
This is useful, but also serves as a 'second implementation'
test of my modulator index code and as such has a couple of
tiny tweaks and fixes from adding a second, addresseing surge-synthesizer#4868
  • Loading branch information
baconpaul committed Aug 19, 2021
1 parent e758bec commit da0cbd3
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 61 deletions.
73 changes: 65 additions & 8 deletions src/common/ModulationSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#pragma once

#include <random>
#include "basic_dsp.h"

enum modsrctype
{
Expand Down Expand Up @@ -268,7 +269,11 @@ struct ModulationRouting
class ModulationSource
{
public:
ModulationSource() {}
ModulationSource()
{
for (int i = 0; i < vecsize; ++i)
voutput[i] = 0.f;
}
virtual ~ModulationSource() {}
virtual const char *get_title() { return 0; }
virtual int get_type() { return mst_undefined; }
Expand All @@ -277,17 +282,42 @@ class ModulationSource
virtual void release(){};
virtual void reset(){};
// override these if you support indices
virtual int get_active_outputs() { return 1; }
virtual float get_output(int which) { return output; }
virtual float get_output01(int which) { return output; }
virtual void set_output(int which, float f) { output = f; }
virtual void set_active_outputs(int ao) { active_outputs = ao; }
virtual int get_active_outputs() { return active_outputs; }
virtual float get_output(int which)
{
if (which == 0)
return output;
else if (which < vecsize)
return voutput[which];
else
return 0.f;
}
virtual float get_output01(int which)
{
if (which == 0)
return output;
else if (which < vecsize)
return voutput[which];
else
return 0.f;
}
virtual void set_output(int which, float f)
{
if (which == 0)
output = f;
else if (which < vecsize)
voutput[which] = f;
}

virtual bool per_voice() { return false; }
virtual bool is_bipolar() { return false; }
virtual void set_bipolar(bool b) {}

protected:
float output;
int active_outputs{0};
static constexpr int vecsize = 16;
float output, voutput[vecsize];
};

class ControllerModulationSource : public ModulationSource
Expand Down Expand Up @@ -446,16 +476,43 @@ class RandomModulationSource : public ModulationSource
std::random_device rd;
gen = std::minstd_rand(rd());
if (bp)
{
dis = std::uniform_real_distribution<float>(-1.0, 1.0);
norm = std::normal_distribution<float>(0, 0.33); // stddev
}
else
{
dis = std::uniform_real_distribution<float>(0.0, 1.0);
norm = std::normal_distribution<float>(0, 0.33); // stddev
}
}

virtual void attack() override { output = dis(gen); }
int get_active_outputs() override
{
return 2; // bipolar can't support lognormal obvs
}

bool bipolar;
float get_output(int which) override { return output[which]; }

virtual void attack() override
{
if (bipolar)
{
output[0] = dis(gen);
output[1] = limitpm1(norm(gen));
}
else
{
output[0] = dis(gen);
output[1] = limit01(fabs(norm(gen)));
}
}

float output[2];
bool bipolar{false};
std::minstd_rand gen;
std::uniform_real_distribution<float> dis;
std::normal_distribution<float> norm;
};

class AlternateModulationSource : public ModulationSource
Expand Down
11 changes: 10 additions & 1 deletion src/common/SurgeSynthesizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2770,19 +2770,28 @@ bool SurgeSynthesizer::supportsIndexedModulator(int scene, modsources modsource)
auto lf = &(storage.getPatch().scene[scene].lfo[modsource - ms_lfo1]);
return lf->shape.val.i == lt_formula;
}

if (modsource == ms_random_bipolar || modsource == ms_random_unipolar)
{
return true;
}
return false;
}

int SurgeSynthesizer::getMaxModulationIndex(int scene, modsources modsource) const
{
if (modsource >= ms_lfo1 && modsource <= ms_lfo6)
if (modsource >= ms_lfo1 && modsource <= ms_slfo6)
{
auto lf = &(storage.getPatch().scene[scene].lfo[modsource - ms_lfo1]);
if (lf->shape.val.i == lt_formula)
{
return Surge::Formula::max_formula_outputs;
}
}
if (modsource == ms_random_bipolar)
return 2;
if (modsource == ms_random_unipolar)
return 2;
return 1;
}

Expand Down
10 changes: 8 additions & 2 deletions src/common/dsp/SurgeVoice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,16 @@ SurgeVoice::SurgeVoice(SurgeStorage *storage, SurgeSceneStorage *oscene, pdata *
/*
** We want to snap the rnd and alt
*/
rndUni.set_output(0, oscene->modsources[ms_random_unipolar]->get_output(0));
int ao = oscene->modsources[ms_random_unipolar]->get_active_outputs();
rndUni.set_active_outputs(ao);
for (int w = 0; w < ao; ++w)
rndUni.set_output(w, oscene->modsources[ms_random_unipolar]->get_output(w));
modsources[ms_random_unipolar] = &rndUni;

rndBi.set_output(0, oscene->modsources[ms_random_bipolar]->get_output(0));
ao = oscene->modsources[ms_random_bipolar]->get_active_outputs();
rndBi.set_active_outputs(ao);
for (int w = 0; w < ao; ++w)
rndBi.set_output(w, oscene->modsources[ms_random_bipolar]->get_output(w));
modsources[ms_random_bipolar] = &rndBi;

altUni.set_output(0, oscene->modsources[ms_alternate_unipolar]->get_output(0));
Expand Down
14 changes: 14 additions & 0 deletions src/gui/SurgeGUIEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4946,6 +4946,20 @@ std::string SurgeGUIEditor::modulatorIndexExtension(int scene, int ms, int index
{
if (synth->supportsIndexedModulator(scene, (modsources)ms))
{
if (ms == ms_random_bipolar)
{
if (index == 0)
return " (Uniform)";
if (index == 1)
return " (Normal)";
}
if (ms == ms_random_unipolar)
{
if (index == 0)
return " (Uniform)";
if (index == 1)
return " (Half Normal)";
}
return std::string(" Out ") + std::to_string(index + 1);
}
return "";
Expand Down
73 changes: 23 additions & 50 deletions src/gui/SurgeGUIEditorValueCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1776,74 +1776,47 @@ int32_t SurgeGUIEditor::controlModifierClicked(Surge::GUI::IComponentTagValue *c
char tmptxt[512];
sprintf(tmptxt, "%s", modulatorName(ms, false).c_str());

auto *popMenu = &addMIDISub;

// TODO FIXME: Try not to be gross!
if (ms >= ms_ctrl1 && ms <= ms_ctrl1 + n_customcontrollers - 1)
{
addMacroSub.addItem(tmptxt, [this, p, bvf, ms]() {
this->promptForUserValueEntry(p, bvf, ms, 0);
});
popMenu = &addMacroSub;
}
else if (ms >= ms_lfo1 && ms <= ms_lfo1 + n_lfos_voice - 1)
{
if (isIndexed)
{
int maxidx = synth->getMaxModulationIndex(current_scene, ms);
auto subm = juce::PopupMenu();
for (int i = 0; i < maxidx; ++i)
{
auto subn = modulatorName(ms, false) +
modulatorIndexExtension(current_scene, ms, i);
subm.addItem(subn, [this, p, bvf, ms, i]() {
this->promptForUserValueEntry(p, bvf, ms, i);
});
}
addVLFOSub.addSubMenu(tmptxt, subm);
}
else
{
addVLFOSub.addItem(tmptxt, [this, p, bvf, ms]() {
this->promptForUserValueEntry(p, bvf, ms, 0);
});
}
popMenu = &addVLFOSub;
}
else if (ms >= ms_slfo1 && ms <= ms_slfo1 + n_lfos_scene - 1)
{
if (isIndexed)
{
int maxidx = synth->getMaxModulationIndex(current_scene, ms);
auto subm = juce::PopupMenu();
for (int i = 0; i < maxidx; ++i)
{
auto subn = modulatorName(ms, false) +
modulatorIndexExtension(current_scene, ms, i);
subm.addItem(subn, [this, p, bvf, ms, i]() {
this->promptForUserValueEntry(p, bvf, ms, i);
});
}
addSLFOSub.addSubMenu(tmptxt, subm);
}
else
{
addSLFOSub.addItem(tmptxt, [this, p, bvf, ms]() {
this->promptForUserValueEntry(p, bvf, ms, 0);
});
}
popMenu = &addSLFOSub;
}
else if (ms >= ms_ampeg && ms <= ms_filtereg)
{
addEGSub.addItem(tmptxt, [this, p, bvf, ms]() {
this->promptForUserValueEntry(p, bvf, ms, 0);
});
popMenu = &addEGSub;
}
else if (ms >= ms_random_bipolar && ms <= ms_alternate_unipolar)
{
addMiscSub.addItem(tmptxt, [this, p, bvf, ms]() {
this->promptForUserValueEntry(p, bvf, ms, 0);
});
popMenu = &addMiscSub;
}

if (isIndexed)
{
int maxidx = synth->getMaxModulationIndex(current_scene, ms);
auto subm = juce::PopupMenu();
for (int i = 0; i < maxidx; ++i)
{
auto subn = modulatorName(ms, false) +
modulatorIndexExtension(current_scene, ms, i);
subm.addItem(subn, [this, p, bvf, ms, i]() {
this->promptForUserValueEntry(p, bvf, ms, i);
});
}
popMenu->addSubMenu(tmptxt, subm);
}
else
{
addMIDISub.addItem(tmptxt, [this, p, bvf, ms]() {
popMenu->addItem(tmptxt, [this, p, bvf, ms]() {
this->promptForUserValueEntry(p, bvf, ms, 0);
});
}
Expand Down

0 comments on commit da0cbd3

Please sign in to comment.