Skip to content

Commit

Permalink
Update GenericDrum
Browse files Browse the repository at this point in the history
  • Loading branch information
ryukau committed Oct 1, 2023
1 parent b5ede97 commit 96f2f37
Show file tree
Hide file tree
Showing 9 changed files with 416 additions and 203 deletions.
342 changes: 220 additions & 122 deletions GenericDrum/source/dsp/dspcore.cpp

Large diffs are not rendered by default.

59 changes: 36 additions & 23 deletions GenericDrum/source/dsp/dspcore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,20 @@ class DSPCore {
}

private:
void updateUpRate();
void resetCollision();
double calcNotePitch(double note);
double processSample();
std::array<double, 2> processFrame();
double processDrum(
size_t index, double noise, double wireGain, double crossGain, double timeModAmt);

std::vector<NoteInfo> midiNotes;
std::vector<NoteInfo> noteStack;

bool isWireCollided = false;
bool isSecondaryCollided = false;

DecibelScale<double> velocityMap{-60, 0, true};
DecibelScale<double> velocityToCouplingDecayMap{-40, 0, false};
double velocity = 0;
Expand All @@ -118,39 +129,41 @@ class DSPCore {
ExpSmoother<double> delayTimeModAmount;
ExpSmoother<double> secondaryFdnMix;
ExpSmoother<double> membraneWireMix;
ExpSmoother<double> stereoBalance;
ExpSmoother<double> stereoMerge;
ExpSmoother<double> outputGain;

static constexpr size_t nDrum = 2;
static constexpr size_t nAllpass = 4;

std::minstd_rand noiseRng{0};
std::minstd_rand paramRng{0};
double noiseGain = 0;
double noiseDecay = 0;
ComplexLowpass<double> noiseLowpass;
SerialAllpass<double, 4> noiseAllpass;

SerialAllpass<double, 4> wireAllpass;
EnergyStoreDecay<double> wireEnergyDecay;
EnergyStoreNoise<double, std::minstd_rand> wireEnergyNoise;
double wirePosition = 0;
double wireVelocity = 0;
std::array<ComplexLowpass<double>, nDrum> noiseLowpass;
std::array<SerialAllpass<double, nAllpass>, nDrum> noiseAllpass;

std::array<SerialAllpass<double, nAllpass>, 2> wireAllpass;
std::array<EnergyStoreDecay<double>, 2> wireEnergyDecay;
std::array<EnergyStoreNoise<double, std::minstd_rand>, 2> wireEnergyNoise;
std::array<double, nDrum> wirePosition{};
std::array<double, nDrum> wireVelocity{};
double wireGain = 0;
double wireDecay = 0;

DoubleEmaADEnvelope<double> envelope;
TransitionReleaseSmoother<double> releaseSmoother;
FeedbackMatrix<double, maxFdnSize> feedbackMatrix;
double membrane1Position = 0;
double membrane1Velocity = 0;
double membrane2Position = 0;
double membrane2Velocity = 0;
EnergyStoreDecay<double> membrane1EnergyDecay;
EnergyStoreDecay<double> membrane2EnergyDecay;
EasyFDN<double, maxFdnSize> membrane1;
EasyFDN<double, maxFdnSize> membrane2;

HalfBandIIR<double, HalfBandCoefficient<double>> halfbandIir;
SVFHighpass<double> safetyHighpass;

void updateUpRate();
double calcNotePitch(double note);
double processSample();
std::array<double, nDrum> membrane1Position{};
std::array<double, nDrum> membrane1Velocity{};
std::array<double, nDrum> membrane2Position{};
std::array<double, nDrum> membrane2Velocity{};
std::array<EnergyStoreDecay<double>, 2> membrane1EnergyDecay;
std::array<EnergyStoreDecay<double>, 2> membrane2EnergyDecay;
std::array<EasyFDN<double, maxFdnSize>, 2> membrane1;
std::array<EasyFDN<double, maxFdnSize>, 2> membrane2;

std::array<std::array<double, 2>, 2> halfbandInput{};
std::array<HalfBandIIR<double, HalfBandCoefficient<double>>, 2> halfbandIir;
std::array<SVFHighpass<double>, 2> safetyHighpass;
};
5 changes: 2 additions & 3 deletions GenericDrum/source/dsp/filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,13 +502,10 @@ template<typename Sample, size_t length> class EasyFDN {
auto &front = buf[bufIndex];
auto &back = buf[bufIndex ^ 1];
front.fill({});
// feedbackMatrix.process();
for (size_t i = 0; i < length; ++i) {
feedbackMatrix.matrix[i].process();
for (size_t j = 0; j < length; ++j) front[i] += feedbackMatrix.at(i, j) * back[j];
}

// input /= Sample(length);
const auto feedbackGain = safetyGain * crossGain;
for (size_t i = 0; i < length; ++i) front[i] = input + feedbackGain * front[i];

Expand All @@ -521,6 +518,8 @@ template<typename Sample, size_t length> class EasyFDN {
const auto sum = std::accumulate(front.begin(), front.end(), Sample(0));
if (Sample(length) < sum) {
safetyGain *= sum <= Sample(100) ? crossDecayGentle : crossDecaySteep;
} else {
safetyGain = std::min(safetyGain + Sample(0.001), Sample(1));
}
return sum;
}
Expand Down
139 changes: 105 additions & 34 deletions GenericDrum/source/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ constexpr int_least32_t defaultWidth = int_least32_t(4 * uiMargin + 3 * groupLab
constexpr int_least32_t defaultHeight
= int_least32_t(2 * uiMargin + 20 * labelY - 2 * margin);

enum tabIndex { tabBatter, tabSnare };
constexpr const char *wireDidntCollidedText = "Wire didn't collide.";
constexpr const char *membraneDidntCollidedText = "Membrane didn't collide.";

namespace Steinberg {
namespace Vst {
Expand All @@ -63,6 +64,80 @@ Editor::Editor(void *controller) : PlugEditor(controller)
setRect(viewRect);
}

ParamValue Editor::getPlainValue(ParamID id)
{
auto normalized = controller->getParamNormalized(id);
return controller->normalizedParamToPlain(id, normalized);
}

template<typename ControllerPtr, typename LabelPtr>
inline void resetStatusText(
ControllerPtr controller, LabelPtr label, Synth::ParameterID::ID id, const char *text)
{
controller->setParamNormalized(id, 0.0);
controller->performEdit(id, 0.0);
if (label.get()) {
label->setText(text);
label->setDirty();
}
}

void Editor::valueChanged(CControl *pControl)
{
using ID = Synth::ParameterID::ID;

ParamID id = pControl->getTag();

if (id != ID::isWireCollided && id != ID::isSecondaryCollided) {
// controller->setParamNormalized(ID::isWireCollided, 0.0);
// controller->performEdit(ID::isWireCollided, 0.0);
// if (labelWireCollision.get()) {
// labelWireCollision->setText(wireDidntCollidedText);
// labelWireCollision->setDirty();
// }

// controller->setParamNormalized(ID::isSecondaryCollided, 0.0);
// controller->performEdit(ID::isSecondaryCollided, 0.0);
// if (labelMembraneCollision.get()) {
// labelMembraneCollision->setText(membraneDidntCollidedText);
// labelMembraneCollision->setDirty();
// }

resetStatusText(
controller, labelWireCollision, ID::isWireCollided, wireDidntCollidedText);
resetStatusText(
controller, labelMembraneCollision, ID::isSecondaryCollided,
membraneDidntCollidedText);
}

ParamValue value = pControl->getValueNormalized();
controller->setParamNormalized(id, value);
controller->performEdit(id, value);
}

void Editor::updateUI(ParamID id, ParamValue normalized)
{
using ID = Synth::ParameterID::ID;

PlugEditor::updateUI(id, normalized);

if (labelWireCollision.get() && id == ID::isWireCollided) {
if (getPlainValue(ID::isWireCollided)) {
labelWireCollision->setText("Wire collided.");
} else {
labelWireCollision->setText(wireDidntCollidedText);
}
labelWireCollision->setDirty();
} else if (labelMembraneCollision.get() && id == ID::isSecondaryCollided) {
if (getPlainValue(ID::isSecondaryCollided)) {
labelMembraneCollision->setText("Membrane collided.");
} else {
labelMembraneCollision->setText(membraneDidntCollidedText);
}
labelMembraneCollision->setDirty();
}
}

bool Editor::prepareUI()
{
using ID = Synth::ParameterID::ID;
Expand Down Expand Up @@ -102,6 +177,9 @@ bool Editor::prepareUI()
constexpr auto mixTop1 = mixTop0 + 1 * labelY;
constexpr auto mixTop2 = mixTop0 + 2 * labelY;
constexpr auto mixTop3 = mixTop0 + 3 * labelY;
constexpr auto mixTop4 = mixTop0 + 4 * labelY;
constexpr auto mixTop5 = mixTop0 + 5 * labelY;
constexpr auto mixTop6 = mixTop0 + 6 * labelY;
constexpr auto mixLeft0 = left0;
constexpr auto mixLeft1 = mixLeft0 + labelWidth + 2 * margin;
addGroupLabel(mixLeft0, mixTop0, groupLabelWidth, labelHeight, uiTextSize, "Mix");
Expand All @@ -116,35 +194,49 @@ bool Editor::prepareUI()
addTextKnob(
mixLeft1, mixTop2, labelWidth, labelHeight, uiTextSize, ID::safetyHighpassHz,
Scales::safetyHighpassHz, false, 5);
addCheckbox(
mixLeft0, mixTop3, labelWidth, labelHeight, uiTextSize, "Reset Seed at Note-on",
ID::resetSeedAtNoteOn);
addCheckbox(
mixLeft1, mixTop3, labelWidth, labelHeight, uiTextSize, "2x Sampling",
ID::overSampling);
addLabel(mixLeft0, mixTop4, labelWidth, labelHeight, uiTextSize, "Channel");
addOptionMenu(
mixLeft1, mixTop4, labelWidth, labelHeight, uiTextSize, ID::stereoEnable,
{"Mono", "Stereo"});
addLabel(mixLeft0, mixTop5, labelWidth, labelHeight, uiTextSize, "Stereo Balance");
addTextKnob(
mixLeft1, mixTop5, labelWidth, labelHeight, uiTextSize, ID::stereoBalance,
Scales::bipolarScale, false, 5);
addLabel(mixLeft0, mixTop6, labelWidth, labelHeight, uiTextSize, "Stereo Merge");
addTextKnob(
mixLeft1, mixTop6, labelWidth, labelHeight, uiTextSize, ID::stereoMerge,
Scales::defaultScale, false, 5);

// Tuning.
constexpr auto tuningTop0 = top0 + 4 * labelY;
constexpr auto tuningTop0 = top0 + 7 * labelY;
constexpr auto tuningTop1 = tuningTop0 + 1 * labelY;
constexpr auto tuningTop2 = tuningTop0 + 2 * labelY;
constexpr auto tuningTop3 = tuningTop0 + 3 * labelY;
constexpr auto tuningTop4 = tuningTop0 + 4 * labelY;
constexpr auto tuningTop5 = tuningTop0 + 5 * labelY;
constexpr auto tuningTop6 = tuningTop0 + 6 * labelY;
constexpr auto tuningLeft0 = left0;
constexpr auto tuningLeft1 = tuningLeft0 + labelWidth + 2 * margin;
addGroupLabel(
tuningLeft0, tuningTop0, groupLabelWidth, labelHeight, uiTextSize, "Tuning");

addLabel(tuningLeft0, tuningTop1, labelWidth, labelHeight, uiTextSize, "Semitone");
addLabel(tuningLeft0, tuningTop1, labelWidth, labelHeight, uiTextSize, "Note -> Pitch");
addTextKnob(
tuningLeft1, tuningTop1, labelWidth, labelHeight, uiTextSize, ID::notePitchAmount,
Scales::bipolarScale, false, 5);
addLabel(tuningLeft0, tuningTop2, labelWidth, labelHeight, uiTextSize, "Semitone");
addTextKnob(
tuningLeft1, tuningTop1, labelWidth, labelHeight, uiTextSize, ID::tuningSemitone,
tuningLeft1, tuningTop2, labelWidth, labelHeight, uiTextSize, ID::tuningSemitone,
Scales::semitone, false, 0, -semitoneOffset);
addLabel(tuningLeft0, tuningTop2, labelWidth, labelHeight, uiTextSize, "Cent");
addLabel(tuningLeft0, tuningTop3, labelWidth, labelHeight, uiTextSize, "Cent");
addTextKnob(
tuningLeft1, tuningTop2, labelWidth, labelHeight, uiTextSize, ID::tuningCent,
tuningLeft1, tuningTop3, labelWidth, labelHeight, uiTextSize, ID::tuningCent,
Scales::cent, false, 5);
addLabel(tuningLeft0, tuningTop3, labelWidth, labelHeight, uiTextSize, "Equal Temp.");
addTextKnob(
tuningLeft1, tuningTop3, labelWidth, labelHeight, uiTextSize, ID::tuningET,
Scales::equalTemperament, false, 0, 1);
addLabel(
tuningLeft0, tuningTop4, labelWidth, labelHeight, uiTextSize,
"Pitch Bend Range [st.]");
Expand All @@ -156,16 +248,6 @@ bool Editor::prepareUI()
addTextKnob(
tuningLeft1, tuningTop5, labelWidth, labelHeight, uiTextSize, ID::noteSlideTimeSecond,
Scales::noteSlideTimeSecond, false, 5);
constexpr auto slideAtWidth = int(groupLabelWidth / 3);
constexpr auto slideAtLeft1 = tuningLeft0 + 1 * slideAtWidth;
constexpr auto slideAtLeft2 = tuningLeft0 + 2 * slideAtWidth;
addLabel(tuningLeft0, tuningTop6, slideAtWidth, labelHeight, uiTextSize, "Slide at");
addCheckbox(
slideAtLeft1, tuningTop6, slideAtWidth, labelHeight, uiTextSize, "Note-on",
ID::slideAtNoteOn);
addCheckbox(
slideAtLeft2, tuningTop6, slideAtWidth, labelHeight, uiTextSize, "Note-off",
ID::slideAtNoteOff);

// Impact.
constexpr auto impactTop0 = top0 + 0 * labelY;
Expand Down Expand Up @@ -239,7 +321,7 @@ bool Editor::prepareUI()
addTextKnob(
wireLeft1, wireTop6, labelWidth, labelHeight, uiTextSize, ID::wireCollisionTypeMix,
Scales::defaultScale, false, 5);
addLabel(
labelWireCollision = addLabel(
wireLeft0, wireTop7, 2 * labelWidth, labelHeight, uiTextSize,
"Wire collision status.");

Expand Down Expand Up @@ -326,17 +408,6 @@ bool Editor::prepareUI()
mainLeft0, mainTop0, groupLabelWidth, labelHeight, uiTextSize, "Pitch Main");

addLabel(mainLeft0, mainTop1, labelWidth, labelHeight, uiTextSize, "Pitch Type");
std::vector<std::string> pitchTypeItems{
"Harmonic",
"Harmonic+12",
"Harmonic*5",
"Harmonic Cycle(1, 5)",
"Harmonic Odd",
"Semitone (1, 2, 7, 9)",
"Circular Membrane Mode",
"Prime Number",
"Octave",
};
addOptionMenu(
mainLeft1, mainTop1, labelWidth, labelHeight, uiTextSize, ID::pitchType,
{"Harmonic", "Harmonic+12", "Harmonic*5", "Harmonic Cycle(1, 5)", "Harmonic Odd",
Expand Down Expand Up @@ -394,7 +465,7 @@ bool Editor::prepareUI()
addTextKnob(
secondaryLeft1, secondaryTop4, labelWidth, labelHeight, uiTextSize,
ID::secondaryDistance, Scales::collisionDistance, false, 5);
addLabel(
labelMembraneCollision = addLabel(
secondaryLeft0, secondaryTop5, 2 * labelWidth, labelHeight, uiTextSize,
"Membrane collision status.");

Expand Down
7 changes: 7 additions & 0 deletions GenericDrum/source/editor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,17 @@ class Editor : public PlugEditor {
public:
Editor(void *controller);

virtual void valueChanged(CControl *pControl) override;
void updateUI(Vst::ParamID id, ParamValue normalized) override;

DELEGATE_REFCOUNT(VSTGUIEditor);

private:
ParamValue getPlainValue(ParamID id);
bool prepareUI() override;

SharedPointer<Label> labelWireCollision;
SharedPointer<Label> labelMembraneCollision;
};

} // namespace Vst
Expand Down
1 change: 0 additions & 1 deletion GenericDrum/source/parameter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ DecibelScale<double> Scales::safetyHighpassHz(ampToDB(0.1), ampToDB(100.0), fals

UIntScale<double> Scales::semitone(semitoneOffset + 48);
LinearScale<double> Scales::cent(-100.0, 100.0);
UIntScale<double> Scales::equalTemperament(119);
LinearScale<double> Scales::pitchBendRange(0.0, 120.0);
DecibelScale<double> Scales::noteSlideTimeSecond(-100.0, 40.0, true);

Expand Down
Loading

0 comments on commit 96f2f37

Please sign in to comment.