Merge pull request #278 from jameshball/develop

Merge develop into main for latest release
pull/277/head
James H Ball 2025-01-17 18:20:40 +00:00 zatwierdzone przez GitHub
commit 4642044a47
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
30 zmienionych plików z 501 dodań i 88 usunięć

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -39,12 +39,12 @@ CommonPluginEditor::CommonPluginEditor(CommonAudioProcessor& p, juce::String app
addAndMakeVisible(visualiser);
visualiserSettings.setLookAndFeel(&getLookAndFeel());
visualiserSettings.setSize(550, 550);
visualiserSettings.setSize(550, VISUALISER_SETTINGS_HEIGHT);
visualiserSettings.setColour(juce::ResizableWindow::backgroundColourId, Colours::dark);
recordingSettings.setLookAndFeel(&getLookAndFeel());
recordingSettings.setSize(300, 200);
recordingSettingsWindow.centreWithSize(300, 230);
recordingSettings.setSize(350, 230);
recordingSettingsWindow.centreWithSize(350, 260);
#if JUCE_WINDOWS
// if not standalone, use native title bar for compatibility with DAWs
recordingSettingsWindow.setUsingNativeTitleBar(processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone);
@ -84,6 +84,12 @@ bool CommonPluginEditor::keyPressed(const juce::KeyPress& key) {
saveProject();
} else if (key.getModifiers().isCommandDown() && key.getKeyCode() == 'O') {
openProject();
} else if (key.isKeyCode(juce::KeyPress::F11Key) && juce::JUCEApplicationBase::isStandaloneApp()) {
// set fullscreen
juce::StandaloneFilterWindow* window = findParentComponentOfClass<juce::StandaloneFilterWindow>();
if (window != nullptr) {
window->setFullScreen(!fullScreen);
}
}
return false;

Wyświetl plik

@ -25,6 +25,7 @@ public:
private:
CommonAudioProcessor& audioProcessor;
bool fullScreen = false;
juce::File applicationFolder = juce::File::getSpecialLocation(juce::File::SpecialLocationType::userApplicationDataDirectory)
#if JUCE_MAC
@ -48,6 +49,8 @@ public:
SharedTextureManager sharedTextureManager;
#endif
int VISUALISER_SETTINGS_HEIGHT = 750;
VisualiserSettings visualiserSettings = VisualiserSettings(audioProcessor.visualiserParameters, 3);
RecordingSettings recordingSettings = RecordingSettings(audioProcessor.recordingParameters);
SettingsWindow recordingSettingsWindow = SettingsWindow("Recording Settings", recordingSettings);

Wyświetl plik

@ -12,10 +12,9 @@
#include "components/AudioPlayerComponent.h"
//==============================================================================
CommonAudioProcessor::CommonAudioProcessor()
CommonAudioProcessor::CommonAudioProcessor(const BusesProperties& busesProperties)
#ifndef JucePlugin_PreferredChannelConfigurations
: AudioProcessor (BusesProperties().withInput("Input", juce::AudioChannelSet::namedChannelSet(3), true)
.withOutput("Output", juce::AudioChannelSet::stereo(), true))
: AudioProcessor(busesProperties)
#endif
{
// locking isn't necessary here because we are in the constructor
@ -25,7 +24,9 @@ CommonAudioProcessor::CommonAudioProcessor()
effects.push_back(effect);
}
effects.push_back(visualiserParameters.smoothEffect);
for (auto effect : visualiserParameters.audioEffects) {
effects.push_back(effect);
}
for (auto parameter : visualiserParameters.booleans) {
booleanParameters.push_back(parameter);

Wyświetl plik

@ -25,7 +25,7 @@ class CommonAudioProcessor : public juce::AudioProcessor, public SampleRateMana
#endif
{
public:
CommonAudioProcessor();
CommonAudioProcessor(const BusesProperties& busesProperties);
~CommonAudioProcessor() override;
void addAllParameters();

Wyświetl plik

@ -125,6 +125,7 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
};
BooleanParameter* visualiserFullScreen = audioProcessor.visualiserParameters.visualiserFullScreen;
pluginEditor.visualiser.setFullScreen(visualiserFullScreen->getBoolValue());
addAndMakeVisible(pluginEditor.visualiser);
pluginEditor.visualiser.setFullScreenCallback([this, visualiserFullScreen](FullScreenMode mode) {
@ -135,6 +136,8 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
} else if (mode == FullScreenMode::MAIN_COMPONENT) {
visualiserFullScreen->setBoolValueNotifyingHost(false);
}
pluginEditor.visualiser.setFullScreen(visualiserFullScreen->getBoolValue());
pluginEditor.resized();
pluginEditor.repaint();
@ -229,9 +232,9 @@ void MainComponent::resized() {
auto shiftedBounds = bounds;
shiftedBounds.setX(topLeft.getX());
shiftedBounds.setY(topLeft.getY());
if (minDim < 35) {
minDim = 35;
}
//if (minDim < 35) {
// minDim = 35;
//}
pluginEditor.visualiser.setBounds(shiftedBounds.withSizeKeepingCentre(minDim - 25, minDim));
}
}

Wyświetl plik

@ -151,7 +151,7 @@ void OscirenderAudioProcessorEditor::resized() {
bool luaFileOpen = false;
if (ableToEditFile) {
if (codeEditors[index]->isVisible()) {
if (index < codeEditors.size() && codeEditors[index]->isVisible()) {
editorVisible = true;
juce::Component dummy;
@ -197,7 +197,9 @@ void OscirenderAudioProcessorEditor::resized() {
collapseButton.setVisible(ableToEditFile);
codeEditors[index]->setVisible(fileOpen);
if (index < codeEditors.size()) {
codeEditors[index]->setVisible(fileOpen);
}
resizerBar.setVisible(fileOpen);
console.setVisible(luaFileOpen);

Wyświetl plik

@ -18,7 +18,7 @@
#include "audio/EffectParameter.h"
//==============================================================================
OscirenderAudioProcessor::OscirenderAudioProcessor() {
OscirenderAudioProcessor::OscirenderAudioProcessor() : CommonAudioProcessor(BusesProperties().withInput("Input", juce::AudioChannelSet::namedChannelSet(2), true).withOutput("Output", juce::AudioChannelSet::stereo(), true)) {
// locking isn't necessary here because we are in the constructor
toggleableEffects.push_back(std::make_shared<Effect>(

Wyświetl plik

@ -68,7 +68,7 @@ public:
"Frequency",
"Controls how many times per second the image is drawn, thereby controlling the pitch of the sound. Lower frequencies result in more-accurately drawn images, but more flickering, and vice versa.",
"frequency",
VERSION_HINT, 220.0, 0.0, 12000.0, 0.1
VERSION_HINT, 220.0, 0.0, 12000.0
)
);
@ -150,8 +150,8 @@ public:
BooleanParameter* animateFrames = new BooleanParameter("Animate", "animateFrames", VERSION_HINT, true, "Enables animation for files that have multiple frames, such as GIFs or Line Art.");
BooleanParameter* animationSyncBPM = new BooleanParameter("Sync To BPM", "animationSyncBPM", VERSION_HINT, false, "Synchronises the animation's framerate with the BPM of your DAW.");
FloatParameter* animationRate = new FloatParameter("Animation Rate", "animationRate", VERSION_HINT, 30, -1000, 1000, 0.01);
FloatParameter* animationOffset = new FloatParameter("Animation Offset", "animationOffset", VERSION_HINT, 0, -10000, 10000, 0.1);
FloatParameter* animationRate = new FloatParameter("Animation Rate", "animationRate", VERSION_HINT, 30, -1000, 1000);
FloatParameter* animationOffset = new FloatParameter("Animation Offset", "animationOffset", VERSION_HINT, 0, -10000, 10000);
BooleanParameter* invertImage = new BooleanParameter("Invert Image", "invertImage", VERSION_HINT, false, "Inverts the image so that dark pixels become light, and vice versa.");
std::shared_ptr<Effect> imageThreshold = std::make_shared<Effect>(

Wyświetl plik

@ -4,7 +4,9 @@
SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p) : CommonPluginEditor(p, "sosci", "sosci", 1180, 750), audioProcessor(p) {
initialiseMenuBar(model);
addAndMakeVisible(volume);
if (juce::JUCEApplication::isStandaloneApp()) {
addAndMakeVisible(volume);
}
addAndMakeVisible(visualiserSettingsWrapper);
BooleanParameter* visualiserFullScreen = audioProcessor.visualiserParameters.visualiserFullScreen;
@ -24,9 +26,21 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p) : CommonPluginEdito
resized();
visualiserFullScreen->addListener(this);
if (juce::JUCEApplication::isStandaloneApp()) {
juce::StandalonePluginHolder* standalone = juce::StandalonePluginHolder::getInstance();
juce::AudioDeviceManager& manager = standalone->deviceManager;
manager.addChangeListener(this);
currentInputDevice = getInputDeviceName();
}
}
SosciPluginEditor::~SosciPluginEditor() {
if (juce::JUCEApplication::isStandaloneApp()) {
juce::StandalonePluginHolder* standalone = juce::StandalonePluginHolder::getInstance();
juce::AudioDeviceManager& manager = standalone->deviceManager;
manager.removeChangeListener(this);
}
audioProcessor.visualiserParameters.visualiserFullScreen->removeListener(this);
menuBar.setModel(nullptr);
}
@ -43,11 +57,13 @@ void SosciPluginEditor::resized() {
} else {
menuBar.setBounds(area.removeFromTop(25));
auto volumeArea = area.removeFromLeft(30);
volume.setBounds(volumeArea.withSizeKeepingCentre(volumeArea.getWidth(), juce::jmin(volumeArea.getHeight(), 300)));
if (juce::JUCEApplication::isStandaloneApp()) {
auto volumeArea = area.removeFromLeft(30);
volume.setBounds(volumeArea.withSizeKeepingCentre(volumeArea.getWidth(), juce::jmin(volumeArea.getHeight(), 300)));
}
auto settingsArea = area.removeFromRight(juce::jmax(juce::jmin(0.4 * getWidth(), 550.0), 350.0));
visualiserSettings.setSize(settingsArea.getWidth(), 550);
visualiserSettings.setSize(settingsArea.getWidth(), VISUALISER_SETTINGS_HEIGHT);
visualiserSettingsWrapper.setBounds(settingsArea);
if (area.getWidth() < 10) {
@ -83,8 +99,12 @@ void SosciPluginEditor::filesDropped(const juce::StringArray& files, int x, int
void SosciPluginEditor::visualiserFullScreenChanged() {
bool fullScreen = audioProcessor.visualiserParameters.visualiserFullScreen->getBoolValue();
visualiser.setFullScreen(fullScreen);
volume.setVisible(!fullScreen);
if (juce::JUCEApplication::isStandaloneApp()) {
volume.setVisible(!fullScreen);
}
visualiserSettingsWrapper.setVisible(!fullScreen);
menuBar.setVisible(!fullScreen);
resized();
@ -98,3 +118,28 @@ void SosciPluginEditor::parameterValueChanged(int parameterIndex, float newValue
}
void SosciPluginEditor::parameterGestureChanged(int parameterIndex, bool gestureIsStarting) {}
void SosciPluginEditor::changeListenerCallback(juce::ChangeBroadcaster* source) {
if (juce::JUCEApplication::isStandaloneApp()) {
juce::String inputDevice = getInputDeviceName();
if (inputDevice != currentInputDevice) {
currentInputDevice = inputDevice;
// switch to getting audio from input if the user changes the input device
// because we assume they are debugging and want to hear the audio from mic
audioProcessor.stopAudioFile();
}
}
}
juce::String SosciPluginEditor::getInputDeviceName() {
if (juce::StandalonePluginHolder::getInstance() == nullptr) {
return "Unknown";
}
juce::StandalonePluginHolder* standalone = juce::StandalonePluginHolder::getInstance();
juce::AudioDeviceManager& manager = standalone->deviceManager;
auto device = manager.getCurrentAudioDevice();
auto deviceType = manager.getCurrentDeviceTypeObject();
int inputIndex = deviceType->getIndexOfDevice(device, true);
auto inputName = deviceType->getDeviceNames(true)[inputIndex];
return inputName;
}

Wyświetl plik

@ -9,7 +9,7 @@
#include "components/SosciMainMenuBarModel.h"
#include "components/SvgButton.h"
class SosciPluginEditor : public CommonPluginEditor, public juce::FileDragAndDropTarget, public juce::AudioProcessorParameter::Listener {
class SosciPluginEditor : public CommonPluginEditor, public juce::FileDragAndDropTarget, public juce::AudioProcessorParameter::Listener, public juce::ChangeListener {
public:
SosciPluginEditor(SosciAudioProcessor&);
~SosciPluginEditor() override;
@ -21,10 +21,15 @@ public:
void visualiserFullScreenChanged();
void parameterValueChanged(int parameterIndex, float newValue) override;
void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override;
void changeListenerCallback(juce::ChangeBroadcaster* source) override;
private:
SosciAudioProcessor& audioProcessor;
juce::String getInputDeviceName();
juce::String currentInputDevice;
ScrollableComponent visualiserSettingsWrapper = ScrollableComponent(visualiserSettings);
SosciMainMenuBarModel model{*this, audioProcessor};

Wyświetl plik

@ -2,7 +2,7 @@
#include "SosciPluginEditor.h"
#include "audio/EffectParameter.h"
SosciAudioProcessor::SosciAudioProcessor() {
SosciAudioProcessor::SosciAudioProcessor() : CommonAudioProcessor(BusesProperties().withInput("Input", juce::AudioChannelSet::namedChannelSet(4), true).withOutput("Output", juce::AudioChannelSet::stereo(), true)) {
// demo audio file on standalone only
if (juce::JUCEApplicationBase::isStandaloneApp()) {
std::unique_ptr<juce::InputStream> stream = std::make_unique<juce::MemoryInputStream>(BinaryData::sosci_flac, BinaryData::sosci_flacSize, false);
@ -62,14 +62,16 @@ void SosciAudioProcessor::processBlock(juce::AudioBuffer<float>& buffer, juce::M
// this is the point that the visualiser will draw
threadManager.write(point, "VisualiserComponent");
point.scale(volume, volume, 1.0);
if (juce::JUCEApplication::isStandaloneApp()) {
point.scale(volume, volume, 1.0);
// clip
point.x = juce::jmax(-threshold, juce::jmin(threshold.load(), point.x));
point.y = juce::jmax(-threshold, juce::jmin(threshold.load(), point.y));
// clip
point.x = juce::jmax(-threshold, juce::jmin(threshold.load(), point.x));
point.y = juce::jmax(-threshold, juce::jmin(threshold.load(), point.y));
// this is the point that the volume component will draw (i.e. post scale/clipping)
threadManager.write(point, "VolumeComponent");
// this is the point that the volume component will draw (i.e. post scale/clipping)
threadManager.write(point, "VolumeComponent");
}
if (output.getNumChannels() > 0) {
outputArray[0][sample] = point.x;

Wyświetl plik

@ -79,13 +79,6 @@ public:
}
}
void audioThreadCallback(const std::vector<float>& left, const std::vector<float>& right) {
juce::AudioBuffer<float> buffer(2, left.size());
buffer.copyFrom(0, 0, left.data(), left.size());
buffer.copyFrom(1, 0, right.data(), right.size());
audioThreadCallback(buffer);
}
void setRecordLength(double recordLength) {
recordingLength = recordLength;
}

Wyświetl plik

@ -328,9 +328,11 @@ class EffectParameter : public FloatParameter {
public:
std::atomic<bool> smoothValueChange = true;
LfoTypeParameter* lfo = new LfoTypeParameter(name + " LFO", paramID + "Lfo", getVersionHint(), 1);
FloatParameter* lfoRate = new FloatParameter(name + " LFO Rate", paramID + "LfoRate", getVersionHint(), 1.0f, 0.0f, 10000.0f, 0.01f, "Hz");
FloatParameter* lfoRate = new FloatParameter(name + " LFO Rate", paramID + "LfoRate", getVersionHint(), 1.0f, 0.0f, 10000.0f, 0.001f, "Hz");
BooleanParameter* sidechain = new BooleanParameter(name + " Sidechain Enabled", paramID + "Sidechain", getVersionHint(), false, "Toggles " + name + " Sidechain.");
std::atomic<float> phase = 0.0f;
// this is what the value will get reset to on double-click.
std::atomic<float> defaultValue;
juce::String description;
std::vector<juce::AudioProcessorParameter*> getParameters() {
@ -399,5 +401,5 @@ public:
}
}
EffectParameter(juce::String name, juce::String description, juce::String id, int versionHint, float value, float min, float max, float step = 0.01, bool smoothValueChange = true) : FloatParameter(name, id, versionHint, value, min, max, step), smoothValueChange(smoothValueChange), description(description) {}
EffectParameter(juce::String name, juce::String description, juce::String id, int versionHint, float value, float min, float max, float step = 0.0001, bool smoothValueChange = true) : FloatParameter(name, id, versionHint, value, min, max, step), smoothValueChange(smoothValueChange), description(description), defaultValue(value) {}
};

Wyświetl plik

@ -0,0 +1,35 @@
#include "StereoEffect.h"
StereoEffect::StereoEffect() {}
StereoEffect::~StereoEffect() {}
OsciPoint StereoEffect::apply(int index, OsciPoint input, const std::vector<std::atomic<double>>& values, double sampleRate) {
if (this->sampleRate != sampleRate) {
this->sampleRate = sampleRate;
initialiseBuffer(sampleRate);
}
double sampleOffset = values[0].load() / 10;
sampleOffset = juce::jlimit(0.0, 1.0, sampleOffset);
sampleOffset *= buffer.size();
head++;
if (head >= buffer.size()) {
head = 0;
}
buffer[head] = input;
int readHead = head - sampleOffset;
if (readHead < 0) {
readHead += buffer.size();
}
return OsciPoint(input.x, buffer[readHead].y, input.z);
}
void StereoEffect::initialiseBuffer(double sampleRate) {
buffer.clear();
buffer.resize(bufferLength * sampleRate);
head = 0;
}

Wyświetl plik

@ -0,0 +1,19 @@
#pragma once
#include "EffectApplication.h"
#include "../shape/OsciPoint.h"
class StereoEffect : public EffectApplication {
public:
StereoEffect();
~StereoEffect();
OsciPoint apply(int index, OsciPoint input, const std::vector<std::atomic<double>>& values, double sampleRate) override;
private:
void initialiseBuffer(double sampleRate);
const double bufferLength = 0.1;
double sampleRate = -1;
std::vector<OsciPoint> buffer;
int head = 0;
};

Wyświetl plik

@ -109,6 +109,9 @@ void AudioPlayerComponent::setPaused(bool paused) {
void AudioPlayerComponent::parserChanged() {
setup();
repaint();
if (onParserChanged != nullptr) {
onParserChanged();
}
}
void AudioPlayerComponent::resized() {

Wyświetl plik

@ -63,6 +63,9 @@ public:
void setup();
void parserChanged() override;
void setPaused(bool paused);
bool isInitialised() const { return audioProcessor.wavParser.isInitialised(); }
std::function<void()> onParserChanged;
private:
CommonAudioProcessor& audioProcessor;

Wyświetl plik

@ -17,11 +17,13 @@ EffectComponent::EffectComponent(Effect& effect, int index) : effect(effect), in
slider.setSliderStyle(juce::Slider::LinearHorizontal);
slider.setTextBoxStyle(juce::Slider::TextBoxRight, false, TEXT_BOX_WIDTH, slider.getTextBoxHeight());
slider.setNumDecimalPlacesToDisplay(4);
lfoSlider.setSliderStyle(juce::Slider::LinearHorizontal);
lfoSlider.setTextBoxStyle(juce::Slider::TextBoxRight, false, TEXT_BOX_WIDTH, lfoSlider.getTextBoxHeight());
lfoSlider.setTextValueSuffix("Hz");
lfoSlider.setColour(sliderThumbOutlineColourId, juce::Colour(0xff00ff00));
lfoSlider.setNumDecimalPlacesToDisplay(3);
label.setFont(juce::Font(14.0f));
@ -59,6 +61,7 @@ void EffectComponent::setupComponent() {
slider.setRange(parameter->min, parameter->max, parameter->step);
slider.setValue(parameter->getValueUnnormalised(), juce::dontSendNotification);
slider.setDoubleClickReturnValue(true, parameter->defaultValue);
lfoEnabled = parameter->lfo != nullptr && parameter->lfoRate != nullptr;
if (lfoEnabled) {
@ -81,6 +84,7 @@ void EffectComponent::setupComponent() {
lfoSlider.setRange(parameter->lfoRate->min, parameter->lfoRate->max, parameter->lfoRate->step);
lfoSlider.setValue(parameter->lfoRate->getValueUnnormalised(), juce::dontSendNotification);
lfoSlider.setSkewFactorFromMidPoint(parameter->lfoRate->min + 0.1 * (parameter->lfoRate->max - parameter->lfoRate->min));
lfoSlider.setDoubleClickReturnValue(true, 1.0);
if (lfo.getSelectedId() == static_cast<int>(LfoType::Static)) {
lfoSlider.setVisible(false);

Wyświetl plik

@ -13,6 +13,7 @@ VolumeComponent::VolumeComponent(CommonAudioProcessor& p) : AudioBackgroundThrea
auto volumeParam = audioProcessor.volumeEffect->parameters[0];
volumeSlider.setRange(volumeParam->min, volumeParam->max, volumeParam->step);
volumeSlider.setValue(volumeParam->getValueUnnormalised());
volumeSlider.setDoubleClickReturnValue(true, 1.0);
volumeSlider.setLookAndFeel(&thumbRadiusLookAndFeel);
volumeSlider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black);
@ -25,6 +26,7 @@ VolumeComponent::VolumeComponent(CommonAudioProcessor& p) : AudioBackgroundThrea
auto& thresholdParam = audioProcessor.thresholdEffect->parameters[0];
thresholdSlider.setRange(thresholdParam->min, thresholdParam->max, thresholdParam->step);
thresholdSlider.setValue(thresholdParam->getValueUnnormalised());
thresholdSlider.setDoubleClickReturnValue(true, 1.0);
thresholdSlider.setLookAndFeel(&thresholdLookAndFeel);
thresholdSlider.setColour(juce::Slider::ColourIds::thumbColourId, juce::Colours::black);

Wyświetl plik

@ -66,6 +66,16 @@ ImageParser::ImageParser(OscirenderAudioProcessor& p, juce::String extension, ju
}
}
}
if (frames.size() == 0) {
juce::MessageManager::callAsync([this] {
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::AlertIconType::WarningIcon, "Invalid GIF", "The image could not be loaded. Please try optimising the GIF with https://ezgif.com/optimize.");
});
width = 1;
height = 1;
frames.emplace_back(std::vector<uint8_t>(1));
}
setFrame(0);
}

Wyświetl plik

@ -11,6 +11,8 @@ RecordingSettings::RecordingSettings(RecordingParameters& ps) : parameters(ps) {
addAndMakeVisible(recordVideo);
addAndMakeVisible(compressionPreset);
addAndMakeVisible(compressionPresetLabel);
addAndMakeVisible(customSharedTextureOutputLabel);
addAndMakeVisible(customSharedTextureOutputEditor);
quality.setSliderOnValueChange();
quality.setRangeEnabled(false);
@ -34,6 +36,12 @@ RecordingSettings::RecordingSettings(RecordingParameters& ps) : parameters(ps) {
compressionPreset.addItemList(parameters.compressionPresets, 1);
compressionPreset.setSelectedId(parameters.compressionPresets.indexOf(parameters.compressionPreset) + 1);
compressionPresetLabel.setTooltip("The compression preset to use when recording video. Slower presets will produce smaller files at the expense of encoding time.");
customSharedTextureOutputLabel.setTooltip("Custom name for when creating a new Syphon/Spout server. WARNING: You should not use the same name when running multiple servers at once!.");
customSharedTextureOutputEditor.setText(parameters.customSharedTextureServerName);
customSharedTextureOutputEditor.onTextChange = [this] {
parameters.customSharedTextureServerName = customSharedTextureOutputEditor.getText();
};
#else
addAndMakeVisible(recordVideoWarning);
addAndMakeVisible(sosciLink);
@ -61,8 +69,13 @@ void RecordingSettings::resized() {
recordAudio.setBounds(area.removeFromTop(rowHeight));
recordVideo.setBounds(area.removeFromTop(rowHeight));
auto row = area.removeFromTop(rowHeight);
compressionPresetLabel.setBounds(row.removeFromLeft(140));
compressionPreset.setBounds(row.removeFromRight(80));
compressionPresetLabel.setBounds(row.removeFromLeft(170));
compressionPreset.setBounds(row.removeFromRight(100));
area.removeFromTop(5);
row = area.removeFromTop(rowHeight);
customSharedTextureOutputLabel.setBounds(row.removeFromLeft(170));
customSharedTextureOutputEditor.setBounds(row.removeFromRight(100));
#else
recordVideoWarning.setBounds(area.removeFromTop(2 * rowHeight));
area.removeFromTop(rowHeight / 2);

Wyświetl plik

@ -45,6 +45,7 @@ public:
recordAudio.save(settingsXml->createNewChildElement("recordAudio"));
recordVideo.save(settingsXml->createNewChildElement("recordVideo"));
settingsXml->setAttribute("compressionPreset", compressionPreset);
settingsXml->setAttribute("customSharedTextureServerName", customSharedTextureServerName);
auto qualityXml = settingsXml->createNewChildElement("quality");
qualityEffect.save(qualityXml);
@ -65,6 +66,9 @@ public:
if (settingsXml->hasAttribute("compressionPreset")) {
compressionPreset = settingsXml->getStringAttribute("compressionPreset");
}
if (settingsXml->hasAttribute("customSharedTextureServerName")) {
customSharedTextureServerName = settingsXml->getStringAttribute("customSharedTextureServerName");
}
if (auto* qualityXml = settingsXml->getChildByName("quality")) {
qualityEffect.load(qualityXml);
}
@ -72,6 +76,7 @@ public:
}
juce::StringArray compressionPresets = { "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow" };
juce::String customSharedTextureServerName = "";
};
class RecordingSettings : public juce::Component {
@ -102,6 +107,13 @@ public:
juce::String getCompressionPreset() {
return parameters.compressionPreset;
}
juce::String getCustomSharedTextureServerName() {
if (parameters.customSharedTextureServerName.isEmpty()) {
return "osci-render - " + juce::String(juce::Time::getCurrentTime().toMilliseconds());
}
return parameters.customSharedTextureServerName;
}
RecordingParameters& parameters;
@ -119,6 +131,9 @@ private:
juce::Label compressionPresetLabel{"Compression Speed", "Compression Speed"};
juce::ComboBox compressionPreset;
juce::Label customSharedTextureOutputLabel{"Custom Syphon/Spout Name", "Custom Syphon/Spout Name"};
juce::TextEditor customSharedTextureOutputEditor{"customSharedTextureOutputEditor"};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RecordingSettings)
};

Wyświetl plik

@ -115,8 +115,24 @@ VisualiserComponent::VisualiserComponent(
popoutWindow();
};
if (visualiserOnly && juce::JUCEApplication::isStandaloneApp()) {
addAndMakeVisible(audioInputButton);
audioInputButton.setTooltip("Appears red when audio input is being used. Click to enable audio input and close any open audio files.");
audioInputButton.setClickingTogglesState(false);
audioInputButton.setToggleState(!audioPlayer.isInitialised(), juce::NotificationType::dontSendNotification);
audioPlayer.onParserChanged = [this] {
juce::MessageManager::callAsync([this] {
audioInputButton.setToggleState(!audioPlayer.isInitialised(), juce::NotificationType::dontSendNotification);
});
};
audioInputButton.onClick = [this] {
audioProcessor.stopAudioFile();
};
}
addAndMakeVisible(audioPlayer);
audioPlayer.addMouseListener(static_cast<juce::Component*>(this), true);
openGLContext.setRenderer(this);
openGLContext.attachTo(*this);
@ -134,6 +150,13 @@ VisualiserComponent::~VisualiserComponent() {
});
}
void VisualiserComponent::setFullScreen(bool fullScreen) {
this->fullScreen = fullScreen;
hideButtonRow = false;
setMouseCursor(juce::MouseCursor::PointingHandCursor);
resized();
}
void VisualiserComponent::setFullScreenCallback(std::function<void(FullScreenMode)> callback) {
fullScreenCallback = callback;
}
@ -146,13 +169,22 @@ void VisualiserComponent::enableFullScreen() {
}
void VisualiserComponent::mouseDoubleClick(const juce::MouseEvent& event) {
enableFullScreen();
if (event.originalComponent == this) {
enableFullScreen();
}
}
void VisualiserComponent::runTask(const std::vector<OsciPoint>& points) {
{
juce::CriticalSection::ScopedLockType lock(samplesLock);
// copy the points before applying effects
audioOutputBuffer.setSize(2, points.size(), false, true, true);
for (int i = 0; i < points.size(); ++i) {
audioOutputBuffer.setSample(0, i, points[i].x);
audioOutputBuffer.setSample(1, i, points[i].y);
}
xSamples.clear();
ySamples.clear();
zSamples.clear();
@ -186,11 +218,21 @@ void VisualiserComponent::runTask(const std::vector<OsciPoint>& points) {
sampleCount++;
}
} else {
for (auto& point : points) {
OsciPoint smoothPoint = settings.parameters.smoothEffect->apply(0, point);
xSamples.push_back(smoothPoint.x);
ySamples.push_back(smoothPoint.y);
zSamples.push_back(smoothPoint.z);
for (OsciPoint point : points) {
for (auto& effect : settings.parameters.audioEffects) {
point = effect->apply(0, point);
}
#if SOSCI_FEATURES
if (settings.isFlippedHorizontal()) {
point.x = -point.x;
}
if (settings.isFlippedVertical()) {
point.y = -point.y;
}
#endif
xSamples.push_back(point.x);
ySamples.push_back(point.y);
zSamples.push_back(point.z);
}
}
@ -230,7 +272,7 @@ void VisualiserComponent::runTask(const std::vector<OsciPoint>& points) {
// this just triggers a repaint
triggerAsyncUpdate();
// wait for rendering to complete
// wait for rendering on the OpenGLRenderer thread to complete
renderingSemaphore.acquire();
}
@ -264,9 +306,49 @@ void VisualiserComponent::setPaused(bool paused) {
repaint();
}
void VisualiserComponent::mouseDrag(const juce::MouseEvent& event) {
timerId = -1;
}
void VisualiserComponent::mouseMove(const juce::MouseEvent& event) {
if (event.getScreenX() == lastMouseX && event.getScreenY() == lastMouseY) {
return;
}
hideButtonRow = false;
setMouseCursor(juce::MouseCursor::PointingHandCursor);
if (fullScreen) {
if (!getScreenBounds().removeFromBottom(25).contains(event.getScreenX(), event.getScreenY()) && !event.mods.isLeftButtonDown()) {
lastMouseX = event.getScreenX();
lastMouseY = event.getScreenY();
int newTimerId = juce::Random::getSystemRandom().nextInt();
timerId = newTimerId;
auto pos = event.getScreenPosition();
auto parent = this->parent;
juce::WeakReference<VisualiserComponent> weakRef = this;
juce::Timer::callAfterDelay(1000, [this, weakRef, newTimerId, pos, parent]() {
if (weakRef) {
if (parent == nullptr || parent->child == this) {
if (timerId == newTimerId && fullScreen) {
hideButtonRow = true;
setMouseCursor(juce::MouseCursor::NoCursor);
resized();
}
}
}
});
}
resized();
}
}
void VisualiserComponent::mouseDown(const juce::MouseEvent& event) {
if (event.mods.isLeftButtonDown() && child == nullptr && !record.getToggleState()) {
setPaused(active);
if (event.originalComponent == this) {
if (event.mods.isLeftButtonDown() && child == nullptr && !record.getToggleState()) {
setPaused(active);
}
}
}
@ -276,6 +358,9 @@ bool VisualiserComponent::keyPressed(const juce::KeyPress& key) {
fullScreenCallback(FullScreenMode::MAIN_COMPONENT);
}
return true;
} else if (key.isKeyCode(juce::KeyPress::spaceKey)) {
setPaused(active);
return true;
}
return false;
@ -412,7 +497,11 @@ void VisualiserComponent::setRecording(bool recording) {
void VisualiserComponent::resized() {
auto area = getLocalBounds();
buttonRow = area.removeFromBottom(25);
if (fullScreen && hideButtonRow) {
buttonRow = area.removeFromBottom(0);
} else {
buttonRow = area.removeFromBottom(25);
}
auto buttons = buttonRow;
if (parent == nullptr) {
fullScreenButton.setBounds(buttons.removeFromRight(30));
@ -426,6 +515,9 @@ void VisualiserComponent::resized() {
} else {
settingsButton.setVisible(false);
}
if (visualiserOnly && juce::JUCEApplication::isStandaloneApp()) {
audioInputButton.setBounds(buttons.removeFromRight(30));
}
#if SOSCI_FEATURES
sharedTextureButton.setBounds(buttons.removeFromRight(30));
#endif
@ -501,7 +593,7 @@ void VisualiserComponent::childUpdated() {
#if SOSCI_FEATURES
void VisualiserComponent::initialiseSharedTexture() {
sharedTextureSender = sharedTextureManager.addSender("osci-render - " + juce::String(juce::Time::getCurrentTime().toMilliseconds()), renderTexture.width, renderTexture.height);
sharedTextureSender = sharedTextureManager.addSender(recordingSettings.getCustomSharedTextureServerName(), renderTexture.width, renderTexture.height);
sharedTextureSender->initGL();
sharedTextureSender->setSharedTextureId(renderTexture.id);
sharedTextureSender->setDrawFunction([this] {
@ -649,11 +741,7 @@ void VisualiserComponent::renderOpenGL() {
}
#endif
if (recordingAudio) {
if (settings.isSweepEnabled()) {
audioRecorder.audioThreadCallback(ySamples, ySamples);
} else {
audioRecorder.audioThreadCallback(xSamples, ySamples);
}
audioRecorder.audioThreadCallback(audioOutputBuffer);
}
}
@ -740,7 +828,8 @@ void VisualiserComponent::setupTextures() {
blur4Texture = makeTexture(128, 128);
renderTexture = makeTexture(1024, 1024);
screenTexture = createScreenTexture();
screenOpenGLTexture.loadImage(emptyScreenImage);
screenTexture = { screenOpenGLTexture.getTextureID(), screenTextureImage.getWidth(), screenTextureImage.getHeight() };
#if SOSCI_FEATURES
glowTexture = makeTexture(512, 512);
@ -901,7 +990,6 @@ void VisualiserComponent::drawLine(const std::vector<float>& xPoints, const std:
setAdditiveBlending();
// TODO: need to add the last point from the previous frame to the start of the frame so they connect?
int nPoints = xPoints.size();
// Without this, there's an access violation that seems to occur only on some systems
@ -1029,7 +1117,11 @@ void VisualiserComponent::drawCRT() {
setShader(outputShader.get());
outputShader->setUniform("uExposure", 0.25f);
outputShader->setUniform("uLineSaturation", (float) settings.getLineSaturation());
#if SOSCI_FEATURES
outputShader->setUniform("uScreenSaturation", (float) settings.getScreenSaturation());
#else
outputShader->setUniform("uScreenSaturation", 1.0f);
#endif
outputShader->setUniform("uNoise", (float) settings.getNoise());
outputShader->setUniform("uRandom", juce::Random::getSystemRandom().nextFloat());
outputShader->setUniform("uGlow", (float) settings.getGlow());
@ -1102,12 +1194,16 @@ Texture VisualiserComponent::createScreenTexture() {
} else {
screenOpenGLTexture.loadImage(emptyScreenImage);
}
checkGLErrors(__FILE__, __LINE__);
Texture texture = { screenOpenGLTexture.getTextureID(), screenTextureImage.getWidth(), screenTextureImage.getHeight() };
if (screenOverlay == ScreenOverlay::Graticule || screenOverlay == ScreenOverlay::SmudgedGraticule) {
activateTargetTexture(texture);
checkGLErrors(__FILE__, __LINE__);
setNormalBlending();
checkGLErrors(__FILE__, __LINE__);
setShader(simpleShader.get());
checkGLErrors(__FILE__, __LINE__);
glColorMask(true, false, false, true);
std::vector<float> data;
@ -1153,9 +1249,9 @@ Texture VisualiserComponent::createScreenTexture() {
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * data.size(), data.data(), GL_STATIC_DRAW);
glVertexAttribPointer(glGetAttribLocation(simpleShader->getProgramID(), "vertexPosition"), 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
simpleShader->setUniform("colour", 0.01f, 0.1f, 0.01f, 1.0f);
simpleShader->setUniform("colour", 0.01f, 0.05f, 0.01f, 1.0f);
glLineWidth(2.0f);
glDrawArrays(GL_LINES, 0, data.size());
glDrawArrays(GL_LINES, 0, data.size() / 2);
glBindTexture(GL_TEXTURE_2D, targetTexture.value().id);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
@ -1163,7 +1259,7 @@ Texture VisualiserComponent::createScreenTexture() {
return texture;
}
void VisualiserComponent::checkGLErrors(const juce::String& location) {
void VisualiserComponent::checkGLErrors(juce::String file, int line) {
using namespace juce::gl;
GLenum error;
@ -1179,7 +1275,7 @@ void VisualiserComponent::checkGLErrors(const juce::String& location) {
case GL_INVALID_FRAMEBUFFER_OPERATION: errorMessage = "GL_INVALID_FRAMEBUFFER_OPERATION"; break;
default: errorMessage = "Unknown OpenGL error"; break;
}
DBG("OpenGL error at " + location + ": " + errorMessage);
DBG("OpenGL error at " + file + ":" + juce::String(line) + " - " + errorMessage);
}
}
@ -1217,7 +1313,7 @@ void VisualiserComponent::renderScope(const std::vector<float>& xPoints, const s
renderScale = (float)openGLContext.getRenderingScale();
drawLineTexture(xPoints, yPoints, zPoints);
checkGLErrors("drawLineTexture");
checkGLErrors(__FILE__, __LINE__);
drawCRT();
checkGLErrors("drawCRT");
checkGLErrors(__FILE__, __LINE__);
}

Wyświetl plik

@ -52,6 +52,7 @@ public:
std::function<void()> closeSettings;
void enableFullScreen();
void setFullScreen(bool fullScreen);
void setFullScreenCallback(std::function<void(FullScreenMode)> callback);
void mouseDoubleClick(const juce::MouseEvent& event) override;
void resized() override;
@ -60,6 +61,8 @@ public:
void runTask(const std::vector<OsciPoint>& points) override;
void stopTask() override;
void setPaused(bool paused);
void mouseDrag(const juce::MouseEvent& event) override;
void mouseMove(const juce::MouseEvent& event) override;
void mouseDown(const juce::MouseEvent& event) override;
bool keyPressed(const juce::KeyPress& key) override;
void handleAsyncUpdate() override;
@ -87,6 +90,7 @@ private:
SvgButton fullScreenButton{ "fullScreen", BinaryData::fullscreen_svg, juce::Colours::white, juce::Colours::white };
SvgButton popOutButton{ "popOut", BinaryData::open_in_new_svg, juce::Colours::white, juce::Colours::white };
SvgButton settingsButton{ "settings", BinaryData::cog_svg, juce::Colours::white, juce::Colours::white };
SvgButton audioInputButton{ "audioInput", BinaryData::microphone_svg, juce::Colours::white, juce::Colours::red };
#if SOSCI_FEATURES
SvgButton sharedTextureButton{ "sharedTexture", BinaryData::spout_svg, juce::Colours::white, juce::Colours::red };
@ -94,6 +98,11 @@ private:
SharedTextureSender* sharedTextureSender = nullptr;
#endif
int lastMouseX = 0;
int lastMouseY = 0;
int timerId = 0;
bool hideButtonRow = false;
bool fullScreen = false;
std::function<void(FullScreenMode)> fullScreenCallback;
VisualiserSettings& settings;
@ -170,6 +179,7 @@ private:
juce::CriticalSection samplesLock;
long sampleCount = 0;
juce::AudioBuffer<float> audioOutputBuffer;
std::vector<float> xSamples{2};
std::vector<float> ySamples{2};
std::vector<float> zSamples{2};
@ -228,7 +238,7 @@ private:
juce::OpenGLShaderProgram* currentShader;
float fadeAmount;
ScreenOverlay screenOverlay = settings.getScreenOverlay();
ScreenOverlay screenOverlay = ScreenOverlay::MAX;
const double RESAMPLE_RATIO = 6.0;
double sampleRate = -1;
@ -256,7 +266,7 @@ private:
void drawLine(const std::vector<float>& xPoints, const std::vector<float>& yPoints, const std::vector<float>& zPoints);
void fade();
void drawCRT();
void checkGLErrors(const juce::String& location);
void checkGLErrors(juce::String file, int line);
void viewportChanged(juce::Rectangle<int> area);
void renderScope(const std::vector<float>& xPoints, const std::vector<float>& yPoints, const std::vector<float>& zPoints);
@ -269,11 +279,14 @@ private:
juce::File audioFile;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserComponent)
JUCE_DECLARE_WEAK_REFERENCEABLE(VisualiserComponent)
};
class VisualiserWindow : public juce::DocumentWindow {
public:
VisualiserWindow(juce::String name, VisualiserComponent* parent) : parent(parent), wasPaused(!parent->active), juce::DocumentWindow(name, juce::Colours::black, juce::DocumentWindow::TitleBarButtons::allButtons) {}
VisualiserWindow(juce::String name, VisualiserComponent* parent) : parent(parent), wasPaused(!parent->active), juce::DocumentWindow(name, juce::Colours::black, juce::DocumentWindow::TitleBarButtons::allButtons) {
setAlwaysOnTop(true);
}
void closeButtonPressed() override {
parent->setPaused(wasPaused);

Wyświetl plik

@ -8,7 +8,6 @@ VisualiserSettings::VisualiserSettings(VisualiserParameters& p, int numChannels)
addAndMakeVisible(persistence);
addAndMakeVisible(hue);
addAndMakeVisible(lineSaturation);
addAndMakeVisible(screenSaturation);
addAndMakeVisible(focus);
addAndMakeVisible(noise);
addAndMakeVisible(glow);
@ -20,6 +19,16 @@ VisualiserSettings::VisualiserSettings(VisualiserParameters& p, int numChannels)
addAndMakeVisible(sweepToggle);
addAndMakeVisible(screenOverlayLabel);
addAndMakeVisible(screenOverlay);
#if SOSCI_FEATURES
addAndMakeVisible(screenSaturation);
addAndMakeVisible(stereo);
addAndMakeVisible(xOffset);
addAndMakeVisible(yOffset);
addAndMakeVisible(xScale);
addAndMakeVisible(yScale);
addAndMakeVisible(flipVerticalToggle);
addAndMakeVisible(flipHorizontalToggle);
#endif
for (int i = 1; i <= parameters.screenOverlay->max; i++) {
screenOverlay.addItem(parameters.screenOverlay->getText(parameters.screenOverlay->getNormalisedValue(i)), i);
@ -33,7 +42,6 @@ VisualiserSettings::VisualiserSettings(VisualiserParameters& p, int numChannels)
persistence.setSliderOnValueChange();
hue.setSliderOnValueChange();
lineSaturation.setSliderOnValueChange();
screenSaturation.setSliderOnValueChange();
focus.setSliderOnValueChange();
noise.setSliderOnValueChange();
glow.setSliderOnValueChange();
@ -53,6 +61,15 @@ VisualiserSettings::VisualiserSettings(VisualiserParameters& p, int numChannels)
resized();
};
#if SOSCI_FEATURES
screenSaturation.setSliderOnValueChange();
stereo.setSliderOnValueChange();
xOffset.setSliderOnValueChange();
yOffset.setSliderOnValueChange();
xScale.setSliderOnValueChange();
yScale.setSliderOnValueChange();
#endif
parameters.screenOverlay->addListener(this);
}
@ -77,15 +94,26 @@ void VisualiserSettings::resized() {
persistence.setBounds(area.removeFromTop(rowHeight));
hue.setBounds(area.removeFromTop(rowHeight));
lineSaturation.setBounds(area.removeFromTop(rowHeight));
#if SOSCI_FEATURES
screenSaturation.setBounds(area.removeFromTop(rowHeight));
#endif
focus.setBounds(area.removeFromTop(rowHeight));
noise.setBounds(area.removeFromTop(rowHeight));
glow.setBounds(area.removeFromTop(rowHeight));
ambient.setBounds(area.removeFromTop(rowHeight));
smooth.setBounds(area.removeFromTop(rowHeight));
#if SOSCI_FEATURES
stereo.setBounds(area.removeFromTop(rowHeight));
xScale.setBounds(area.removeFromTop(rowHeight));
yScale.setBounds(area.removeFromTop(rowHeight));
xOffset.setBounds(area.removeFromTop(rowHeight));
yOffset.setBounds(area.removeFromTop(rowHeight));
flipVerticalToggle.setBounds(area.removeFromTop(rowHeight));
flipHorizontalToggle.setBounds(area.removeFromTop(rowHeight));
#endif
upsamplingToggle.setBounds(area.removeFromTop(rowHeight));
sweepToggle.setBounds(area.removeFromTop(rowHeight));
sweepMs.setBounds(area.removeFromTop(rowHeight));
triggerValue.setBounds(area.removeFromTop(rowHeight));

Wyświetl plik

@ -8,6 +8,7 @@
#include "../LookAndFeel.h"
#include "../components/SwitchButton.h"
#include "../audio/SmoothEffect.h"
#include "../audio/StereoEffect.h"
enum class ScreenOverlay : int {
Empty = 1,
@ -93,6 +94,66 @@ public:
BooleanParameter* sweepEnabled = new BooleanParameter("Sweep", "sweepEnabled", VERSION_HINT, false, "Plots the audio signal over time, sweeping from left to right");
BooleanParameter* visualiserFullScreen = new BooleanParameter("Visualiser Fullscreen", "visualiserFullScreen", VERSION_HINT, false, "Makes the software visualiser fullscreen.");
#if SOSCI_FEATURES
BooleanParameter* flipVertical = new BooleanParameter("Flip Vertical", "flipVertical", VERSION_HINT, false, "Flips the visualiser vertically.");
BooleanParameter* flipHorizontal = new BooleanParameter("Flip Horizontal", "flipHorizontal", VERSION_HINT, false, "Flips the visualiser horizontally.");
std::shared_ptr<Effect> screenSaturationEffect = std::make_shared<Effect>(
new EffectParameter(
"Screen Saturation",
"Controls how saturated the colours are on the oscilloscope screen.",
"screenSaturation",
VERSION_HINT, 1.0, 0.0, 5.0
)
);
std::shared_ptr<StereoEffect> stereoEffectApplication = std::make_shared<StereoEffect>();
std::shared_ptr<Effect> stereoEffect = std::make_shared<Effect>(
stereoEffectApplication,
new EffectParameter(
"Stereo",
"Turns mono audio that is uninteresting to visualise into stereo audio that is interesting to visualise.",
"stereo",
VERSION_HINT, 0.0, 0.0, 1.0
)
);
std::shared_ptr<Effect> scaleEffect = std::make_shared<Effect>(
[this](int index, OsciPoint input, const std::vector<std::atomic<double>>& values, double sampleRate) {
input.scale(values[0].load(), values[1].load(), 1.0);
return input;
}, std::vector<EffectParameter*>{
new EffectParameter(
"X Scale",
"Controls the horizontal scale of the oscilloscope display.",
"xScale",
VERSION_HINT, 1.0, -3.0, 3.0
),
new EffectParameter(
"Y Scale",
"Controls the vertical scale of the oscilloscope display.",
"yScale",
VERSION_HINT, 1.0, -3.0, 3.0
),
});
std::shared_ptr<Effect> offsetEffect = std::make_shared<Effect>(
[this](int index, OsciPoint input, const std::vector<std::atomic<double>>& values, double sampleRate) {
input.translate(values[0].load(), values[1].load(), 0.0);
return input;
}, std::vector<EffectParameter*>{
new EffectParameter(
"X Offset",
"Controls the horizontal position offset of the oscilloscope display.",
"xOffset",
VERSION_HINT, 0.0, -1.0, 1.0
),
new EffectParameter(
"Y Offset",
"Controls the vertical position offset of the oscilloscope display.",
"yOffset",
VERSION_HINT, 0.0, -1.0, 1.0
),
});
#endif
std::shared_ptr<Effect> persistenceEffect = std::make_shared<Effect>(
new EffectParameter(
"Persistence",
@ -125,14 +186,6 @@ public:
VERSION_HINT, 1.0, 0.0, 5.0
)
);
std::shared_ptr<Effect> screenSaturationEffect = std::make_shared<Effect>(
new EffectParameter(
"Screen Saturation",
"Controls how saturated the colours are on the oscilloscope screen.",
"screenSaturation",
VERSION_HINT, 1.0, 0.0, 5.0
)
);
std::shared_ptr<Effect> focusEffect = std::make_shared<Effect>(
new EffectParameter(
"Focus",
@ -191,9 +244,39 @@ public:
)
);
std::vector<std::shared_ptr<Effect>> effects = {persistenceEffect, hueEffect, intensityEffect, lineSaturationEffect, screenSaturationEffect, focusEffect, noiseEffect, glowEffect, ambientEffect, sweepMsEffect, triggerValueEffect};
std::vector<BooleanParameter*> booleans = {upsamplingEnabled, visualiserFullScreen, sweepEnabled};
std::vector<IntParameter*> integers = {screenOverlay};
std::vector<std::shared_ptr<Effect>> effects = {
persistenceEffect,
hueEffect,
intensityEffect,
lineSaturationEffect,
focusEffect,
noiseEffect,
glowEffect,
ambientEffect,
sweepMsEffect,
triggerValueEffect,
};
std::vector<std::shared_ptr<Effect>> audioEffects = {
smoothEffect,
#if SOSCI_FEATURES
screenSaturationEffect,
stereoEffect,
scaleEffect,
offsetEffect,
#endif
};
std::vector<BooleanParameter*> booleans = {
upsamplingEnabled,
visualiserFullScreen,
sweepEnabled,
#if SOSCI_FEATURES
flipVertical,
flipHorizontal,
#endif
};
std::vector<IntParameter*> integers = {
screenOverlay,
};
};
class VisualiserSettings : public juce::Component, public juce::AudioProcessorParameter::Listener {
@ -222,9 +305,19 @@ public:
return parameters.lineSaturationEffect->getActualValue();
}
#if SOSCI_FEATURES
double getScreenSaturation() {
return parameters.screenSaturationEffect->getActualValue();
}
bool isFlippedVertical() {
return parameters.flipVertical->getBoolValue();
}
bool isFlippedHorizontal() {
return parameters.flipHorizontal->getBoolValue();
}
#endif
double getFocus() {
return parameters.focusEffect->getActualValue() / 100;
@ -270,7 +363,6 @@ private:
EffectComponent persistence{*parameters.persistenceEffect};
EffectComponent hue{*parameters.hueEffect};
EffectComponent lineSaturation{*parameters.lineSaturationEffect};
EffectComponent screenSaturation{*parameters.screenSaturationEffect};
EffectComponent focus{*parameters.focusEffect};
EffectComponent noise{*parameters.noiseEffect};
EffectComponent glow{*parameters.glowEffect};
@ -285,6 +377,18 @@ private:
jux::SwitchButton upsamplingToggle{parameters.upsamplingEnabled};
jux::SwitchButton sweepToggle{parameters.sweepEnabled};
#if SOSCI_FEATURES
EffectComponent screenSaturation{*parameters.screenSaturationEffect};
EffectComponent stereo{*parameters.stereoEffect};
EffectComponent xScale{*parameters.scaleEffect, 0};
EffectComponent yScale{*parameters.scaleEffect, 1};
EffectComponent xOffset{*parameters.offsetEffect, 0};
EffectComponent yOffset{*parameters.offsetEffect, 1};
jux::SwitchButton flipVerticalToggle{parameters.flipVertical};
jux::SwitchButton flipHorizontalToggle{parameters.flipHorizontal};
#endif
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserSettings)
};

Wyświetl plik

@ -29,8 +29,8 @@ elif [ "$OS" = "mac" ]; then
PROJUCER_OS="osx"
fi
# curl -s -S -L "https://api.juce.com/api/v1/download/juce/latest/$PROJUCER_OS" -o Projucer.zip
curl -s -S -L "https://github.com/juce-framework/JUCE/releases/download/8.0.4/juce-8.0.4-$PROJUCER_OS.zip" -o Projucer.zip
curl -s -S -L "https://api.juce.com/api/v1/download/juce/latest/$PROJUCER_OS" -o Projucer.zip
# curl -s -S -L "https://github.com/juce-framework/JUCE/releases/download/8.0.4/juce-8.0.4-$PROJUCER_OS.zip" -o Projucer.zip
unzip Projucer.zip
# Set Projucer path based on OS

Wyświetl plik

@ -4,7 +4,7 @@
addUsingNamespaceToJuceHeader="0" jucerFormatVersion="1" pluginCharacteristicsValue="pluginWantsMidiIn"
pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender"
cppLanguageStandard="20" projectLineFeed="&#10;" headerPath="./include"
version="2.4.2" companyName="James H Ball" companyWebsite="https://osci-render.com"
version="2.4.3.3" companyName="James H Ball" companyWebsite="https://osci-render.com"
companyEmail="james@ball.sh" defines="NOMINMAX=1&#10;INTERNET_FLAG_NO_AUTO_REDIRECT=0&#10;SOSCI_FEATURES=1"
pluginAUMainType="'aumf'">
<MAINGROUP id="j5Ge2T" name="osci-render">
@ -124,6 +124,9 @@
<FILE id="iUEfwT" name="SmoothEffect.cpp" compile="1" resource="0"
file="Source/audio/SmoothEffect.cpp"/>
<FILE id="Vwjht7" name="SmoothEffect.h" compile="0" resource="0" file="Source/audio/SmoothEffect.h"/>
<FILE id="agQEM3" name="StereoEffect.cpp" compile="1" resource="0"
file="Source/audio/StereoEffect.cpp"/>
<FILE id="WACNMe" name="StereoEffect.h" compile="0" resource="0" file="Source/audio/StereoEffect.h"/>
<FILE id="VBskjq" name="VectorCancellingEffect.cpp" compile="1" resource="0"
file="Source/audio/VectorCancellingEffect.cpp"/>
<FILE id="Be21D0" name="VectorCancellingEffect.h" compile="0" resource="0"

Wyświetl plik

@ -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="&#10;"
headerPath="./include" version="1.0.2" companyName="James H Ball"
headerPath="./include" version="1.0.3.3" companyName="James H Ball"
companyWebsite="https://osci-render.com" companyEmail="james@ball.sh"
defines="NOMINMAX=1&#10;INTERNET_FLAG_NO_AUTO_REDIRECT=0&#10;SOSCI_FEATURES=1"
pluginManufacturerCode="Jhba" pluginCode="Sosc" pluginAUMainType="'aufx'">
@ -108,6 +108,9 @@
<FILE id="vj5mRC" name="SmoothEffect.cpp" compile="1" resource="0"
file="Source/audio/SmoothEffect.cpp"/>
<FILE id="GSnwBW" name="SmoothEffect.h" compile="0" resource="0" file="Source/audio/SmoothEffect.h"/>
<FILE id="Iq5LKp" name="StereoEffect.cpp" compile="1" resource="0"
file="Source/audio/StereoEffect.cpp"/>
<FILE id="jq3EXV" name="StereoEffect.h" compile="0" resource="0" file="Source/audio/StereoEffect.h"/>
</GROUP>
<GROUP id="{CD81913A-7F0E-5898-DA77-5EBEB369DEB1}" name="components">
<FILE id="URb7Ok" name="AboutComponent.cpp" compile="1" resource="0"