From 3056ae399709b4fa5ba96b57d2a01bee0c2c54cb Mon Sep 17 00:00:00 2001 From: James Ball Date: Tue, 28 Mar 2023 13:12:41 +0100 Subject: [PATCH] Add functional sliders for bit crush and bulge --- Source/EffectsComponent.cpp | 11 +++--- Source/audio/BitCrushEffect.cpp | 26 +++++++++++---- Source/audio/BitCrushEffect.h | 5 +-- Source/audio/BulgeEffect.cpp | 12 +++++++ Source/audio/BulgeEffect.h | 5 +-- Source/audio/Effect.h | 4 +++ Source/components/MyListComponent.cpp | 48 +++++++++++---------------- Source/components/MyListComponent.h | 48 ++++++++++++++------------- 8 files changed, 89 insertions(+), 70 deletions(-) diff --git a/Source/EffectsComponent.cpp b/Source/EffectsComponent.cpp index 18affcb..422104a 100644 --- a/Source/EffectsComponent.cpp +++ b/Source/EffectsComponent.cpp @@ -23,22 +23,19 @@ EffectsComponent::EffectsComponent(OscirenderAudioProcessor& p) : audioProcessor auto effect = effects[i]; effect->setValue(0.5); audioProcessor.enableEffect(effect); + itemData.data.push_back(effect); } - itemData.data.push_back(juce::String("Item 1")); - itemData.data.push_back(juce::String("Item 2")); - itemData.data.push_back(juce::String("Item 3")); - - addBtn.setButtonText("Add Item..."); + /*addBtn.setButtonText("Add Item..."); addBtn.onClick = [this]() { itemData.data.push_back(juce::String("Item " + juce::String(1 + itemData.getNumItems()))); listBox.updateContent(); }; - addAndMakeVisible(addBtn); + addAndMakeVisible(addBtn);*/ listBox.setModel(&listBoxModel); - listBox.setRowHeight(40); + listBox.setRowHeight(30); addAndMakeVisible(listBox); } diff --git a/Source/audio/BitCrushEffect.cpp b/Source/audio/BitCrushEffect.cpp index 86cb1bd..3669430 100644 --- a/Source/audio/BitCrushEffect.cpp +++ b/Source/audio/BitCrushEffect.cpp @@ -4,9 +4,20 @@ BitCrushEffect::BitCrushEffect() {} BitCrushEffect::~BitCrushEffect() {} +// algorithm from https://www.kvraudio.com/forum/viewtopic.php?t=163880 Vector2 BitCrushEffect::apply(int index, Vector2 input) { - double crush = 3.0 * (1.0 - value); - return Vector2(bitCrush(input.x, crush), bitCrush(input.y, crush)); + // change rage of value from 0-1 to 0.0-0.78 + double rangedValue = value * 0.78; + double powValue = pow(2.0f, 1.0 - rangedValue) - 1.0; + double crush = powValue * 12; + double x = powf(2.0f, crush); + double quant = 0.5 * x; + double dequant = 1.0f / quant; + return Vector2(dequant * (int)(input.x * quant), dequant * (int)(input.y * quant)); +} + +double BitCrushEffect::getValue() { + return value; } void BitCrushEffect::setValue(double value) { @@ -25,9 +36,10 @@ void BitCrushEffect::setPrecedence(int precedence) { this->precedence = precedence; } -double BitCrushEffect::bitCrush(double value, double places) { - long factor = (long) pow(10, places); - value = value * factor; - long tmp = round(value); - return (double) tmp / factor; +juce::String BitCrushEffect::getName() { + return juce::String("Bit Crush"); +} + +juce::String BitCrushEffect::getId() { + return juce::String("bitCrush"); } diff --git a/Source/audio/BitCrushEffect.h b/Source/audio/BitCrushEffect.h index d98be4b..5b5f4a7 100644 --- a/Source/audio/BitCrushEffect.h +++ b/Source/audio/BitCrushEffect.h @@ -8,15 +8,16 @@ public: ~BitCrushEffect(); Vector2 apply(int index, Vector2 input) override; + double getValue() override; void setValue(double value) override; void setFrequency(double frequency) override; int getPrecedence() override; void setPrecedence(int precedence) override; + juce::String getName() override; + juce::String getId() override; private: double value = 0.0; double frequency = 1.0; int precedence = -1; - - double bitCrush(double value, double places); }; \ No newline at end of file diff --git a/Source/audio/BulgeEffect.cpp b/Source/audio/BulgeEffect.cpp index eeca143..9ec8f3b 100644 --- a/Source/audio/BulgeEffect.cpp +++ b/Source/audio/BulgeEffect.cpp @@ -14,6 +14,10 @@ Vector2 BulgeEffect::apply(int index, Vector2 input) { return Vector2(rn * cos(theta), rn * sin(theta)); } +double BulgeEffect::getValue() { + return value; +} + void BulgeEffect::setValue(double value) { this->value = value; } @@ -29,3 +33,11 @@ int BulgeEffect::getPrecedence() { void BulgeEffect::setPrecedence(int precedence) { this->precedence = precedence; } + +juce::String BulgeEffect::getName() { + return juce::String("Bulge"); +} + +juce::String BulgeEffect::getId() { + return juce::String("bulge"); +} diff --git a/Source/audio/BulgeEffect.h b/Source/audio/BulgeEffect.h index 34b0b75..4018405 100644 --- a/Source/audio/BulgeEffect.h +++ b/Source/audio/BulgeEffect.h @@ -7,13 +7,14 @@ public: BulgeEffect(); ~BulgeEffect(); - - Vector2 apply(int index, Vector2 input) override; + double getValue() override; void setValue(double value) override; void setFrequency(double frequency) override; int getPrecedence() override; void setPrecedence(int precedence) override; + juce::String getName() override; + juce::String getId() override; private: double value = 0.0; diff --git a/Source/audio/Effect.h b/Source/audio/Effect.h index 69fe128..732c11f 100644 --- a/Source/audio/Effect.h +++ b/Source/audio/Effect.h @@ -1,13 +1,17 @@ #pragma once #include "../shape/Vector2.h" +#include class Effect { public: Effect(); virtual Vector2 apply(int index, Vector2 input) = 0; + virtual double getValue() = 0; virtual void setValue(double value) = 0; virtual void setFrequency(double frequency) = 0; virtual int getPrecedence() = 0; virtual void setPrecedence(int precedence) = 0; + virtual juce::String getName() = 0; + virtual juce::String getId() = 0; }; \ No newline at end of file diff --git a/Source/components/MyListComponent.cpp b/Source/components/MyListComponent.cpp index 06fa791..93048fb 100644 --- a/Source/components/MyListComponent.cpp +++ b/Source/components/MyListComponent.cpp @@ -1,45 +1,35 @@ #include "MyListComponent.h" -MyListComponent::MyListComponent(DraggableListBox& lb, MyListBoxItemData& data, int rn) - : DraggableListBoxItem(lb, data, rn) -{ - actionBtn.setButtonText("Action"); - actionBtn.onClick = [this]() - { - ((MyListBoxItemData&)modelData).doItemAction(rowNum); - }; - addAndMakeVisible(actionBtn); +MyListComponent::MyListComponent(DraggableListBox& lb, MyListBoxItemData& data, int rn) : DraggableListBoxItem(lb, data, rn) { + addAndMakeVisible(slider); + addAndMakeVisible(label); - deleteBtn.setButtonText("Delete"); - deleteBtn.onClick = [this]() - { - modelData.deleteItem(rowNum); - listBox.updateContent(); - }; - addAndMakeVisible(deleteBtn); + label.setText(data.getText(rn), juce::dontSendNotification); + label.attachToComponent(&slider, true); + + slider.setSliderStyle(juce::Slider::LinearHorizontal); + slider.setTextBoxStyle(juce::Slider::TextBoxRight, false, 90, slider.getTextBoxHeight()); + slider.setRange(0.0, 1.0, 0.01); + slider.setValue(data.getValue(rn), juce::dontSendNotification); + slider.onValueChange = [this] { + ((MyListBoxItemData&)modelData).setValue(rowNum, slider.getValue()); + }; } -MyListComponent::~MyListComponent() -{ - -} +MyListComponent::~MyListComponent() {} -void MyListComponent::paint (juce::Graphics& g) -{ +void MyListComponent::paint (juce::Graphics& g) { modelData.paintContents(rowNum, g, dataArea); DraggableListBoxItem::paint(g); } -void MyListComponent::resized() -{ - dataArea = getLocalBounds(); - actionBtn.setBounds(dataArea.removeFromLeft(70).withSizeKeepingCentre(56, 24)); - deleteBtn.setBounds(dataArea.removeFromRight(70).withSizeKeepingCentre(56, 24)); +void MyListComponent::resized() { + auto sliderLeft = 100; + slider.setBounds(sliderLeft, 0, getWidth() - 110, getHeight()); } -juce::Component* MyListBoxModel::refreshComponentForRow(int rowNumber, bool isRowSelected, juce::Component *existingComponentToUpdate) -{ +juce::Component* MyListBoxModel::refreshComponentForRow(int rowNumber, bool isRowSelected, juce::Component *existingComponentToUpdate) { std::unique_ptr item(dynamic_cast(existingComponentToUpdate)); if (juce::isPositiveAndBelow(rowNumber, modelData.getNumItems())) { diff --git a/Source/components/MyListComponent.h b/Source/components/MyListComponent.h index 09d3d67..bb50389 100644 --- a/Source/components/MyListComponent.h +++ b/Source/components/MyListComponent.h @@ -1,39 +1,33 @@ #pragma once #include "DraggableListBox.h" #include +#include "../audio/Effect.h" // Application-specific data container struct MyListBoxItemData : public DraggableListBoxItemData { - std::vector data; + std::vector> data; - int getNumItems() override - { + int getNumItems() override { return data.size(); } - void deleteItem(int indexOfItemToDelete) override - { + void deleteItem(int indexOfItemToDelete) override { data.erase(data.begin() + indexOfItemToDelete); } - void addItemAtEnd() override - { - data.push_back(juce::String("Yahoo")); + void addItemAtEnd() override { + // data.push_back(juce::String("Yahoo")); } - void paintContents(int rowNum, juce::Graphics& g, juce::Rectangle bounds) override - { + void paintContents(int rowNum, juce::Graphics& g, juce::Rectangle bounds) override { g.fillAll(juce::Colours::lightgrey); g.setColour(juce::Colours::black); g.drawRect(bounds); - if (rowNum < data.size()) { - g.drawText(data[rowNum], bounds, juce::Justification::centred); - } } void moveBefore(int indexOfItemToMove, int indexOfItemToPlaceBefore) override { - juce::String temp = data[indexOfItemToMove]; + auto temp = data[indexOfItemToMove]; if (indexOfItemToMove < indexOfItemToPlaceBefore) { move(data, indexOfItemToMove, indexOfItemToPlaceBefore - 1); @@ -43,7 +37,7 @@ struct MyListBoxItemData : public DraggableListBoxItemData } void moveAfter(int indexOfItemToMove, int indexOfItemToPlaceAfter) override { - juce::String temp = data[indexOfItemToMove]; + auto temp = data[indexOfItemToMove]; if (indexOfItemToMove <= indexOfItemToPlaceAfter) { move(data, indexOfItemToMove, indexOfItemToPlaceAfter); @@ -52,20 +46,25 @@ struct MyListBoxItemData : public DraggableListBoxItemData } } - template void move(std::vector& v, size_t oldIndex, size_t newIndex) - { + template void move(std::vector& v, size_t oldIndex, size_t newIndex) { if (oldIndex > newIndex) { std::rotate(v.rend() - oldIndex - 1, v.rend() - oldIndex, v.rend() - newIndex); } else { std::rotate(v.begin() + oldIndex, v.begin() + oldIndex + 1, v.begin() + newIndex + 1); } } - - // This is an example of an operation on a single list item. - void doItemAction(int itemIndex) - { - DBG(data[itemIndex]); + + void setValue(int itemIndex, double value) { + data[itemIndex]->setValue(value); } + + juce::String getText(int itemIndex) { + return data[itemIndex]->getName(); + } + + double getValue(int itemIndex) { + return data[itemIndex]->getValue(); + } }; // Custom list-item Component (which includes item-delete button) @@ -80,7 +79,10 @@ public: protected: juce::Rectangle dataArea; - juce::TextButton actionBtn, deleteBtn; + + juce::Slider slider; + juce::Label label; + juce::String id; private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MyListComponent)