kopia lustrzana https://github.com/jameshball/osci-render
Fix bugs, improve performance, and change how multiplex and kaleidoscope react to frequency
rodzic
5da472ccd6
commit
c052decbe9
|
|
@ -130,18 +130,13 @@ void EffectsComponent::resized() {
|
|||
area.removeFromTop(6);
|
||||
if (showingGrid) {
|
||||
grid.setBounds(area);
|
||||
grid.setVisible(true);
|
||||
addEffectButton.setVisible(false);
|
||||
listBox.setVisible(false);
|
||||
} else {
|
||||
// Reserve space at bottom for the add button
|
||||
auto addBtnHeight = 44;
|
||||
auto listArea = area;
|
||||
auto buttonArea = listArea.removeFromBottom(addBtnHeight);
|
||||
listBox.setBounds(listArea);
|
||||
listBox.setVisible(true);
|
||||
grid.setVisible(false);
|
||||
listBox.updateContent();
|
||||
addEffectButton.setVisible(true);
|
||||
addEffectButton.setBounds(buttonArea.reduced(0, 4));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,21 +38,24 @@ OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(Buse
|
|||
|
||||
toggleableEffects.push_back(BitCrushEffect().build());
|
||||
toggleableEffects.push_back(BulgeEffect().build());
|
||||
toggleableEffects.push_back(MultiplexEffect().build());
|
||||
toggleableEffects.push_back(KaleidoscopeEffect().build());
|
||||
toggleableEffects.push_back(BounceEffect().build());
|
||||
toggleableEffects.push_back(VectorCancellingEffect().build());
|
||||
toggleableEffects.push_back(RippleEffectApp().build());
|
||||
toggleableEffects.push_back(RotateEffectApp().build());
|
||||
toggleableEffects.push_back(TranslateEffectApp().build());
|
||||
toggleableEffects.push_back(SwirlEffectApp().build());
|
||||
toggleableEffects.push_back(SmoothEffect().build());
|
||||
toggleableEffects.push_back(TwistEffect().build());
|
||||
toggleableEffects.push_back(DelayEffect().build());
|
||||
toggleableEffects.push_back(DashedLineEffect(*this).build());
|
||||
toggleableEffects.push_back(TraceEffect(*this).build());
|
||||
toggleableEffects.push_back(WobbleEffect(*this).build());
|
||||
|
||||
#if OSCI_PREMIUM
|
||||
toggleableEffects.push_back(MultiplexEffect(*this).build());
|
||||
toggleableEffects.push_back(KaleidoscopeEffect(*this).build());
|
||||
toggleableEffects.push_back(BounceEffect().build());
|
||||
toggleableEffects.push_back(TwistEffect().build());
|
||||
#endif
|
||||
|
||||
auto scaleEffect = ScaleEffectApp().build();
|
||||
booleanParameters.push_back(scaleEffect->linked);
|
||||
toggleableEffects.push_back(scaleEffect);
|
||||
|
|
|
|||
|
|
@ -8,11 +8,12 @@
|
|||
|
||||
class KaleidoscopeEffect : public osci::EffectApplication {
|
||||
public:
|
||||
osci::Point apply(int /*index*/, osci::Point input, const std::vector<std::atomic<double>>& values, double /*sampleRate*/) override {
|
||||
explicit KaleidoscopeEffect(OscirenderAudioProcessor &p) : audioProcessor(p) {}
|
||||
|
||||
osci::Point apply(int /*index*/, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
||||
// values[0] = segments (can be fractional)
|
||||
// values[1] = phase (0-1) selecting which segment is currently being drawn
|
||||
double segments = juce::jmax(values[0].load(), 1.0); // ensure at least 1 segment
|
||||
double phase = values.size() > 1 ? values[1].load() : 0.0;
|
||||
|
||||
// Polar conversion
|
||||
double r = std::sqrt(input.x * input.x + input.y * input.y);
|
||||
|
|
@ -22,6 +23,8 @@ public:
|
|||
int fullSegments = (int)std::floor(segments);
|
||||
double fractionalPart = segments - fullSegments; // in [0,1)
|
||||
|
||||
phase = nextPhase(audioProcessor.frequency / (fullSegments + 1), sampleRate) / (2.0 * std::numbers::pi);
|
||||
|
||||
// Use 'segments' for timing so partial segment gets proportionally shorter time.
|
||||
double currentSegmentFloat = phase * segments; // [0, segments)
|
||||
int currentSegmentIndex = (int)std::floor(currentSegmentFloat);
|
||||
|
|
@ -53,7 +56,7 @@ public:
|
|||
|
||||
std::shared_ptr<osci::Effect> build() const override {
|
||||
auto eff = std::make_shared<osci::Effect>(
|
||||
std::make_shared<KaleidoscopeEffect>(),
|
||||
std::make_shared<KaleidoscopeEffect>(audioProcessor),
|
||||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter(
|
||||
"Kaleidoscope Segments",
|
||||
|
|
@ -67,22 +70,14 @@ public:
|
|||
osci::LfoType::Sine,
|
||||
0.25f // LFO frequency (Hz) – slow, visible rotation
|
||||
),
|
||||
new osci::EffectParameter(
|
||||
"Kaleidoscope Phase",
|
||||
"Selects which kaleidoscope segment is currently being drawn (time-multiplexed). Animate to sweep around the circle.",
|
||||
"kaleidoscopePhase",
|
||||
VERSION_HINT,
|
||||
0.0, // default
|
||||
0.0, // min
|
||||
1.0, // max
|
||||
0.0001f, // step
|
||||
osci::LfoType::Sawtooth,
|
||||
55.0f // LFO frequency (Hz) – slow, visible rotation
|
||||
),
|
||||
}
|
||||
);
|
||||
eff->setName("Kaleidoscope");
|
||||
eff->setIcon(BinaryData::kaleidoscope_svg);
|
||||
return eff;
|
||||
}
|
||||
|
||||
private:
|
||||
OscirenderAudioProcessor &audioProcessor;
|
||||
double phase = 0.0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
#include "../PluginProcessor.h"
|
||||
|
||||
class MultiplexEffect : public osci::EffectApplication {
|
||||
public:
|
||||
explicit MultiplexEffect(OscirenderAudioProcessor &p) : audioProcessor(p) {}
|
||||
|
||||
osci::Point apply(int index, osci::Point input, const std::vector<std::atomic<double>>& values, double sampleRate) override {
|
||||
jassert(values.size() >= 6);
|
||||
jassert(values.size() >= 5);
|
||||
|
||||
double gridX = values[0].load() + 0.0001;
|
||||
double gridY = values[1].load() + 0.0001;
|
||||
double gridZ = values[2].load() + 0.0001;
|
||||
double interpolation = values[3].load();
|
||||
double phase = values[4].load();
|
||||
double gridDelay = values[5].load();
|
||||
|
||||
head++;
|
||||
|
||||
if (head >= buffer.size()) {
|
||||
if (head >= (int)buffer.size()) {
|
||||
head = 0;
|
||||
}
|
||||
|
||||
buffer[head] = input;
|
||||
|
||||
osci::Point grid = osci::Point(gridX, gridY, gridZ);
|
||||
|
|
@ -33,6 +34,8 @@ public:
|
|||
double position = phase * totalPositions;
|
||||
double delayPosition = static_cast<int>(position) / totalPositions;
|
||||
|
||||
phase = nextPhase(audioProcessor.frequency / totalPositions, sampleRate) / (2.0 * std::numbers::pi);
|
||||
|
||||
int delayedIndex = head - static_cast<int>(delayPosition * gridDelay * sampleRate);
|
||||
if (delayedIndex < 0) {
|
||||
delayedIndex += buffer.size();
|
||||
|
|
@ -53,13 +56,12 @@ public:
|
|||
|
||||
std::shared_ptr<osci::Effect> build() const override {
|
||||
auto eff = std::make_shared<osci::Effect>(
|
||||
std::make_shared<MultiplexEffect>(),
|
||||
std::make_shared<MultiplexEffect>(audioProcessor),
|
||||
std::vector<osci::EffectParameter*>{
|
||||
new osci::EffectParameter("Multiplex X", "Controls the horizontal grid size for the multiplex effect.", "multiplexGridX", VERSION_HINT, 2.0, 1.0, 8.0),
|
||||
new osci::EffectParameter("Multiplex Y", "Controls the vertical grid size for the multiplex effect.", "multiplexGridY", VERSION_HINT, 2.0, 1.0, 8.0),
|
||||
new osci::EffectParameter("Multiplex Z", "Controls the depth grid size for the multiplex effect.", "multiplexGridZ", VERSION_HINT, 1.0, 1.0, 8.0),
|
||||
new osci::EffectParameter("Multiplex Smooth", "Controls the smoothness of transitions between grid sizes.", "multiplexSmooth", VERSION_HINT, 0.0, 0.0, 1.0),
|
||||
new osci::EffectParameter("Multiplex Phase", "Controls the current phase of the multiplex grid animation.", "gridPhase", VERSION_HINT, 0.0, 0.0, 1.0, 0.0001f, osci::LfoType::Sawtooth, 55.0f),
|
||||
new osci::EffectParameter("Multiplex Delay", "Controls the delay of the audio samples used in the multiplex effect.", "gridDelay", VERSION_HINT, 0.0, 0.0, 1.0),
|
||||
}
|
||||
);
|
||||
|
|
@ -96,6 +98,8 @@ private:
|
|||
return point;
|
||||
}
|
||||
|
||||
OscirenderAudioProcessor &audioProcessor;
|
||||
double phase = 0.0; // Normalised 0..1 phase for multiplex traversal
|
||||
const static int MAX_DELAY = 192000 * 10;
|
||||
std::vector<osci::Point> buffer = std::vector<osci::Point>(MAX_DELAY);
|
||||
int head = 0;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
#include "VListBox.h"
|
||||
|
||||
// This class is a wrapper for a component that allows it to be used in a ListBox
|
||||
// Why is this needed?!?!?!?!
|
||||
|
|
@ -19,15 +20,18 @@ private:
|
|||
std::shared_ptr<juce::Component> component;
|
||||
};
|
||||
|
||||
class ComponentListModel : public juce::ListBoxModel
|
||||
class ComponentListModel : public VListBoxModel
|
||||
{
|
||||
public:
|
||||
ComponentListModel() {}
|
||||
ComponentListModel(int rowHeight) : rowHeight(rowHeight) {}
|
||||
~ComponentListModel() override {}
|
||||
|
||||
int getNumRows() override;
|
||||
void paintListBoxItem(int rowNumber, juce::Graphics& g, int width, int height, bool rowIsSelected) override;
|
||||
juce::Component* refreshComponentForRow(int sliderNum, bool isRowSelected, juce::Component *existingComponentToUpdate) override;
|
||||
int getRowHeight(int rowNumber) override {
|
||||
return rowHeight;
|
||||
}
|
||||
|
||||
void addComponent(std::shared_ptr<juce::Component> component) {
|
||||
components.push_back(component);
|
||||
|
|
@ -35,4 +39,5 @@ public:
|
|||
|
||||
private:
|
||||
std::vector<std::shared_ptr<juce::Component>> components;
|
||||
int rowHeight;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ effect(effect), audioProcessor(data.audioProcessor), editor(data.editor) {
|
|||
|
||||
list.setColour(effectComponentBackgroundColourId, juce::Colours::transparentBlack.withAlpha(0.2f));
|
||||
list.setModel(&listModel);
|
||||
list.setRowHeight(ROW_HEIGHT);
|
||||
list.updateContent();
|
||||
addAndMakeVisible(list);
|
||||
addAndMakeVisible(enabled);
|
||||
|
|
@ -111,11 +110,9 @@ void EffectsListComponent::paintOverChildren(juce::Graphics& g) {
|
|||
g.setColour(juce::Colours::black.withAlpha(0.3f));
|
||||
auto bounds = list.getBounds();
|
||||
bounds.removeFromBottom(PADDING);
|
||||
juce::Path path;
|
||||
path.addRoundedRectangle(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight(), OscirenderLookAndFeel::RECT_RADIUS, OscirenderLookAndFeel::RECT_RADIUS, false, true, false, true);
|
||||
|
||||
if (!enabled.getToggleState()) {
|
||||
g.fillPath(path);
|
||||
g.fillRect(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +124,7 @@ void EffectsListComponent::resized() {
|
|||
closeButton.setImageTransform(juce::AffineTransform::translation(0, -2));
|
||||
leftBar.removeFromLeft(20);
|
||||
enabled.setBounds(leftBar.withSizeKeepingCentre(30, 20));
|
||||
// TODO: this is super slow
|
||||
list.setBounds(area);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ public:
|
|||
|
||||
protected:
|
||||
osci::Effect& effect;
|
||||
ComponentListModel listModel;
|
||||
juce::ListBox list;
|
||||
ComponentListModel listModel { ROW_HEIGHT };
|
||||
VListBox list;
|
||||
jux::SwitchButton enabled = { effect.enabled };
|
||||
SvgButton closeButton = SvgButton("closeEffect", juce::String::createStringFromData(BinaryData::close_svg, BinaryData::close_svgSize), juce::Colours::white, juce::Colours::white);
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
addUsingNamespaceToJuceHeader="0" jucerFormatVersion="1" pluginCharacteristicsValue="pluginWantsMidiIn"
|
||||
pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender"
|
||||
cppLanguageStandard="20" projectLineFeed=" " headerPath="./include"
|
||||
version="2.6.1.0" companyName="James H Ball" companyWebsite="https://osci-render.com"
|
||||
version="2.6.1.1" companyName="James H Ball" companyWebsite="https://osci-render.com"
|
||||
companyEmail="james@ball.sh" defines="NOMINMAX=1 INTERNET_FLAG_NO_AUTO_REDIRECT=0 OSCI_PREMIUM=1 JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1 JUCE_MODAL_LOOPS_PERMITTED=1"
|
||||
pluginAUMainType="'aumf'" postExportShellCommandPosix="echo "Building LuaJIT for $OSTYPE..." && DIR=%%1%% %%1%%/luajit_linux_macos.sh ">
|
||||
<MAINGROUP id="j5Ge2T" name="osci-render">
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<JUCERPROJECT id="HH2E72" name="sosci" projectType="audioplug" useAppConfig="0"
|
||||
addUsingNamespaceToJuceHeader="0" jucerFormatVersion="1" pluginManufacturer="jameshball"
|
||||
aaxIdentifier="sh.ball.sosci" cppLanguageStandard="20" projectLineFeed=" "
|
||||
headerPath="./include" version="1.1.8.2" companyName="James H Ball"
|
||||
headerPath="./include" version="1.1.8.3" companyName="James H Ball"
|
||||
companyWebsite="https://osci-render.com" companyEmail="james@ball.sh"
|
||||
defines="NOMINMAX=1 INTERNET_FLAG_NO_AUTO_REDIRECT=0 OSCI_PREMIUM=1 JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1 JUCE_MODAL_LOOPS_PERMITTED=1"
|
||||
pluginManufacturerCode="Jhba" pluginCode="Sosc" pluginAUMainType="'aufx'">
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue