osci-render/Source/components/EffectsListComponent.h

188 wiersze
6.3 KiB
C++

#pragma once
#include "DraggableListBox.h"
#include <JuceHeader.h>
#include "../PluginProcessor.h"
#include "../audio/Effect.h"
#include "EffectComponent.h"
#include "ComponentList.h"
#include "SwitchButton.h"
#include <random>
// Application-specific data container
class OscirenderAudioProcessorEditor;
struct AudioEffectListBoxItemData : public DraggableListBoxItemData
{
std::vector<std::shared_ptr<Effect>> data;
OscirenderAudioProcessor& audioProcessor;
OscirenderAudioProcessorEditor& editor;
AudioEffectListBoxItemData(OscirenderAudioProcessor& p, OscirenderAudioProcessorEditor& editor) : audioProcessor(p), editor(editor) {
resetData();
}
void randomise() {
juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock);
for (int i = 0; i < data.size(); i++) {
auto effect = data[i];
auto id = effect->getId().toLowerCase();
if (id.contains("scale") || id.contains("translate") || id.contains("trace")) {
continue;
}
for (auto& parameter : effect->parameters) {
parameter->setValueNotifyingHost(juce::Random::getSystemRandom().nextFloat());
if (parameter->lfo != nullptr) {
parameter->lfo->setUnnormalisedValueNotifyingHost((int) LfoType::Static);
parameter->lfoRate->setUnnormalisedValueNotifyingHost(1);
if (juce::Random::getSystemRandom().nextFloat() > 0.8) {
parameter->lfo->setUnnormalisedValueNotifyingHost((int)(juce::Random::getSystemRandom().nextFloat() * (int)LfoType::Noise));
parameter->lfoRate->setValueNotifyingHost(juce::Random::getSystemRandom().nextFloat() * 0.1);
}
}
}
effect->enabled->setValueNotifyingHost(juce::Random::getSystemRandom().nextFloat() > 0.7);
}
// shuffle precedence
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(data.begin(), data.end(), g);
for (int i = 0; i < data.size(); i++) {
data[i]->setPrecedence(i);
}
audioProcessor.updateEffectPrecedence();
}
void resetData() {
juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock);
data.clear();
for (int i = 0; i < audioProcessor.toggleableEffects.size(); i++) {
auto effect = audioProcessor.toggleableEffects[i];
effect->setValue(effect->getValue());
data.push_back(effect);
}
}
int getNumItems() override {
return data.size();
}
// CURRENTLY NOT USED
void deleteItem(int indexOfItemToDelete) override {
// data.erase(data.begin() + indexOfItemToDelete);
}
// CURRENTLY NOT USED
void addItemAtEnd() override {
// data.push_back(juce::String("Yahoo"));
}
void moveBefore(int indexOfItemToMove, int indexOfItemToPlaceBefore) override {
juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock);
auto effect = data[indexOfItemToMove];
if (indexOfItemToMove < indexOfItemToPlaceBefore) {
move(data, indexOfItemToMove, indexOfItemToPlaceBefore - 1);
} else {
move(data, indexOfItemToMove, indexOfItemToPlaceBefore);
}
for (int i = 0; i < data.size(); i++) {
data[i]->setPrecedence(i);
}
audioProcessor.updateEffectPrecedence();
}
void moveAfter(int indexOfItemToMove, int indexOfItemToPlaceAfter) override {
juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock);
auto temp = data[indexOfItemToMove];
if (indexOfItemToMove <= indexOfItemToPlaceAfter) {
move(data, indexOfItemToMove, indexOfItemToPlaceAfter);
} else {
move(data, indexOfItemToMove, indexOfItemToPlaceAfter + 1);
}
for (int i = 0; i < data.size(); i++) {
data[i]->setPrecedence(i);
}
audioProcessor.updateEffectPrecedence();
}
template <typename t> void move(std::vector<t>& 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);
}
}
void setSelected(int itemIndex, bool selected) {
if (selected) {
data[itemIndex]->enabled->setValueNotifyingHost(true);
} else {
data[itemIndex]->enabled->setValueNotifyingHost(false);
}
}
std::shared_ptr<Effect> getEffect(int itemIndex) {
return data[itemIndex];
}
};
// Custom list-item Component (which includes item-delete button)
class EffectsListComponent : public DraggableListBoxItem
{
public:
EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, Effect& effect);
~EffectsListComponent();
void paint(juce::Graphics& g) override;
void paintOverChildren(juce::Graphics& g) override;
void resized() override;
static const int LEFT_BAR_WIDTH = 50;
static const int ROW_HEIGHT = 30;
static const int PADDING = 4;
protected:
Effect& effect;
ComponentListModel listModel;
juce::ListBox list;
jux::SwitchButton selected = { effect.enabled };
private:
OscirenderAudioProcessor& audioProcessor;
OscirenderAudioProcessorEditor& editor;
std::shared_ptr<juce::Component> createComponent(EffectParameter* parameter);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectsListComponent)
};
// Customized DraggableListBoxModel overrides refreshComponentForRow() to ensure that every
// list-item Component is a EffectsListComponent.
class EffectsListBoxModel : public DraggableListBoxModel
{
public:
EffectsListBoxModel(DraggableListBox& lb, DraggableListBoxItemData& md)
: DraggableListBoxModel(lb, md) {
OscirenderAudioProcessor& audioProcessor = ((AudioEffectListBoxItemData&)md).audioProcessor;
juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock);
audioProcessor.updateEffectPrecedence();
}
int getRowHeight(int row) override;
bool hasVariableHeightRows() const override;
juce::Component* refreshComponentForRow(int, bool, juce::Component*) override;
};