Skip to content

Commit

Permalink
2.0.11 Update
Browse files Browse the repository at this point in the history
Added 'smart' knobs to Arrange and Morta. These allow the module to detect when a knob is being turned, and then disable parameter mapping in that case.
  • Loading branch information
codygeary committed Nov 9, 2024
1 parent 4a0279d commit e85e1d1
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 10 deletions.
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"slug": "CVfunk",
"name": "CV funk Modules",
"version": "2.0.10",
"version": "2.0.11",
"license": "MIT",
"brand": "CV funk",
"author": "Cody Geary",
Expand Down
63 changes: 58 additions & 5 deletions src/Arrange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ struct Arrange : Module {
NUM_LIGHTS
};

std::atomic<bool> isEditing[7]; //For the smart knobs

DigitalDisplay* digitalDisplay = nullptr;
DigitalDisplay* chanDisplays[7] = {nullptr};

Expand Down Expand Up @@ -259,6 +261,10 @@ struct Arrange : Module {
configOutput(CHAN_5_OUTPUT, "Channel 5");
configOutput(CHAN_6_OUTPUT, "Channel 6");
configOutput(CHAN_7_OUTPUT, "Channel 7");

for (int i = 0; i < 7; i++) {
isEditing[i] = false; // Initialize editing state to false
}
}

void onRandomize(const RandomizeEvent& e) override {
Expand Down Expand Up @@ -383,7 +389,9 @@ struct Arrange : Module {
for (int i = 0; i < 7; i++) {
// Recall the output values for the current stage and set them to the knobs
float recalledValue = outputValues[currentStage][i]; // Get the stored value for the current stage
paramQuantities[CHAN_1_KNOB + i]->setDisplayValue(recalledValue);
if (!isEditing[i]){ //only change the knob if it's not being turned
paramQuantities[CHAN_1_KNOB + i]->setDisplayValue(recalledValue);
}

// Generate a random value for each gate based on the probability
float randVal = random::uniform(); // Generate a random number between 0 and 1
Expand Down Expand Up @@ -452,13 +460,21 @@ struct Arrange : Module {
float inputVal = knobVal;

if (activeInputChannel[i]==i) {
inputVal = inputs[CHAN_1_INPUT + i].getPolyVoltage(0);
if (!isEditing[i]){
inputVal = inputs[CHAN_1_INPUT + i].getPolyVoltage(0);
} else {
inputVal = knobVal;
}
} else if (activeInputChannel[i] > -1){
// Now we compute which channel we need to grab
int diffBetween = i - activeInputChannel[i];
int currentChannelMax = inputChannels[activeInputChannel[i]] ;
if (currentChannelMax - diffBetween > 0) { //If we are before the last poly channel
inputVal = inputs[CHAN_1_INPUT + activeInputChannel[i]].getPolyVoltage(diffBetween);
if (!isEditing[i]){
inputVal = inputs[CHAN_1_INPUT + activeInputChannel[i]].getPolyVoltage(diffBetween);
} else {
inputVal = knobVal;
}
}
}

Expand All @@ -478,7 +494,9 @@ struct Arrange : Module {
}

if (knobVal != inputVal){ //only update knobs to the set value if they are different
paramQuantities[CHAN_1_KNOB + i]->setDisplayValue(inputVal);
if (!isEditing[i]){ //don't force set any knob currently being turned.
paramQuantities[CHAN_1_KNOB + i]->setDisplayValue(inputVal);
}
}

//Store the output value in the 2D array for the current stage
Expand Down Expand Up @@ -585,6 +603,41 @@ struct ProgressDisplay : TransparentWidget {

};

//Define a SmartKnob that tracks if we are turning it
template <typename BaseKnob>
struct SmartKnob : BaseKnob {
void onDragStart(const event::DragStart& e) override {
if (ParamQuantity* paramQuantity = this->getParamQuantity()) {
if (Arrange* module = dynamic_cast<Arrange*>(paramQuantity->module)) {
int index = paramQuantity->paramId - Arrange::CHAN_1_KNOB; //instance of 1st smart knob in the group
if (index >= 0 && index < 7) { //for 7 smart knobs
module->isEditing[index].store(true);
}
}
}
BaseKnob::onDragStart(e);
}

void onDragEnd(const event::DragEnd& e) override {
if (ParamQuantity* paramQuantity = this->getParamQuantity()) {
if (Arrange* module = dynamic_cast<Arrange*>(paramQuantity->module)) {
int index = paramQuantity->paramId - Arrange::CHAN_1_KNOB;
if (index >= 0 && index < 7) { //for 7 smart knobs
module->isEditing[index].store(false);
}
}
}
BaseKnob::onDragEnd(e);
}
};

// Type aliases to apply 'Smart' to all the knob types we use
using SmartRoundBlackKnob = SmartKnob<RoundBlackKnob>;
using SmartTrimpot = SmartKnob<Trimpot>;
using SmartRoundLargeBlackKnob = SmartKnob<RoundLargeBlackKnob>;
using SmartRoundHugeBlackKnob = SmartKnob<RoundHugeBlackKnob>;


struct ArrangeWidget : ModuleWidget {
ArrangeWidget(Arrange* module) {
setModule(module);
Expand Down Expand Up @@ -650,7 +703,7 @@ struct ArrangeWidget : ModuleWidget {
addParam(createParamCentered<TL1105> (Vec(20 + 30, yPos), module, Arrange::CHAN_1_BUTTON + i));
addChild(createLightCentered<LargeLight<BlueLight>>(Vec(20 + 30, yPos), module, Arrange::CHAN_1_LIGHT + i));
addChild(createLightCentered<LargeLight<YellowLight>>(Vec(20 + 30, yPos), module, Arrange::CHAN_1_LIGHT_B + i));
addParam(createParamCentered<RoundBlackKnob> (Vec(50 + 35, yPos), module, Arrange::CHAN_1_KNOB + i));
addParam(createParamCentered<SmartRoundBlackKnob> (Vec(50 + 35, yPos), module, Arrange::CHAN_1_KNOB + i));

if (module) {
// Ratio Displays Initialization
Expand Down
56 changes: 52 additions & 4 deletions src/Morta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ struct Morta : Module {
NUM_LIGHTS
};

std::atomic<bool> isEditing[1]; //For the master smart knob

float inputValue = 0.f;
float displayValue = 0.0f;
DigitalDisplay* voltDisplay = nullptr;
Expand All @@ -58,6 +60,8 @@ struct Morta : Module {
for (int i = 0; i < 16; i++) {
configOutput(OUTPUT_1_1 + i, "Output " + std::to_string(i / 4 + 1) + "," + std::to_string(i % 4 + 1));
}

isEditing[0] = false; // Initialize editing state to false
}

void process(const ProcessArgs &args) override {
Expand All @@ -81,9 +85,14 @@ struct Morta : Module {
for (int c = 0; c < numChannels; c++) {

// Override master knob value with input if input is connected
float topChannelVoltage = inputs[MAIN_INPUT].getVoltage(0);
if (inputs[MAIN_INPUT].isConnected()) {
params[MASTER_KNOB].setValue(inputs[MAIN_INPUT].getVoltage(0));
displayValue = inputs[MAIN_INPUT].getVoltage(0);
if (!isEditing[0]){
params[MASTER_KNOB].setValue(topChannelVoltage);
displayValue = inputs[MAIN_INPUT].getVoltage(0);
} else {
displayValue = params[MASTER_KNOB].getValue();
}
} else {
displayValue = params[MASTER_KNOB].getValue();
}
Expand All @@ -97,7 +106,11 @@ struct Morta : Module {
float inputValue = 0.0f;

if (inputs[MAIN_INPUT].isConnected()) {
inputValue = inputs[MAIN_INPUT].getVoltage(c);
if (!isEditing[0]){
inputValue = inputs[MAIN_INPUT].getVoltage(c);
} else {
inputValue = params[MASTER_KNOB].getValue();
}
} else {
inputValue = params[MASTER_KNOB].getValue();
}
Expand All @@ -124,6 +137,41 @@ struct Morta : Module {

};

//Define a SmartKnob that tracks if we are turning it
template <typename BaseKnob>
struct SmartKnob : BaseKnob {
void onDragStart(const event::DragStart& e) override {
if (ParamQuantity* paramQuantity = this->getParamQuantity()) {
if (Morta* module = dynamic_cast<Morta*>(paramQuantity->module)) {
int index = paramQuantity->paramId - Morta::MASTER_KNOB; //instance of 1st smart knob in the group
if (index >= 0 && index < 1) { //for 1 smart knobs
module->isEditing[index].store(true);
}
}
}
BaseKnob::onDragStart(e);
}

void onDragEnd(const event::DragEnd& e) override {
if (ParamQuantity* paramQuantity = this->getParamQuantity()) {
if (Morta* module = dynamic_cast<Morta*>(paramQuantity->module)) {
int index = paramQuantity->paramId - Morta::MASTER_KNOB;
if (index >= 0 && index < 1) { //for 1 smart knobs
module->isEditing[index].store(false);
}
}
}
BaseKnob::onDragEnd(e);
}
};

// Type aliases to apply 'Smart' to all the knob types we use
using SmartRoundBlackKnob = SmartKnob<RoundBlackKnob>;
using SmartTrimpot = SmartKnob<Trimpot>;
using SmartRoundLargeBlackKnob = SmartKnob<RoundLargeBlackKnob>;
using SmartRoundHugeBlackKnob = SmartKnob<RoundHugeBlackKnob>;


struct MortaWidget : ModuleWidget {
MortaWidget(Morta* module) {
setModule(module);
Expand All @@ -142,7 +190,7 @@ struct MortaWidget : ModuleWidget {
addInput(createInputCentered<ThemedPJ301MPort>(Vec(box.size.x / 2 - 50, 70), module, Morta::MAIN_INPUT));

// Central giant knob
addParam(createParamCentered<RoundHugeBlackKnob>(Vec(box.size.x / 2, 70), module, Morta::MASTER_KNOB));
addParam(createParamCentered<SmartRoundHugeBlackKnob>(Vec(box.size.x / 2, 70), module, Morta::MASTER_KNOB));

// CV input, trimpot, and knob for the range control at the bottom
addInput(createInputCentered<ThemedPJ301MPort>(Vec(box.size.x / 2 + 30, 155), module, Morta::RANGE_CV_INPUT));
Expand Down

0 comments on commit e85e1d1

Please sign in to comment.