Merge pull request #284 from jameshball/develop

Release v2.4.10.3
pull/296/head
James H Ball 2025-02-15 17:54:13 +00:00 zatwierdzone przez GitHub
commit 9460737544
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
24 zmienionych plików z 1642 dodań i 92 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
#include "CommonPluginProcessor.h"
#include "CommonPluginEditor.h"
#include <juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h>
#include "CustomStandaloneFilterWindow.h"
CommonPluginEditor::CommonPluginEditor(CommonAudioProcessor& p, juce::String appName, juce::String projectFileType, int defaultWidth, int defaultHeight)
: AudioProcessorEditor(&p), audioProcessor(p), appName(appName), projectFileType(projectFileType)

Wyświetl plik

@ -52,9 +52,9 @@ public:
#endif
#if SOSCI_FEATURES
int VISUALISER_SETTINGS_HEIGHT = 1100;
int VISUALISER_SETTINGS_HEIGHT = 1250;
#else
int VISUALISER_SETTINGS_HEIGHT = 700;
int VISUALISER_SETTINGS_HEIGHT = 800;
#endif
VisualiserSettings visualiserSettings = VisualiserSettings(audioProcessor.visualiserParameters, 3);

Wyświetl plik

@ -0,0 +1,247 @@
/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
#include <juce_core/system/juce_TargetPlatform.h>
#if JucePlugin_Build_Standalone
#if ! JUCE_MODULE_AVAILABLE_juce_audio_utils
#error To compile AudioUnitv3 and/or Standalone plug-ins, you need to add the juce_audio_utils and juce_audio_devices modules!
#endif
#include <juce_core/system/juce_TargetPlatform.h>
#include <juce_audio_plugin_client/detail/juce_CheckSettingMacros.h>
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
#include <juce_audio_plugin_client/detail/juce_IncludeModuleHeaders.h>
#include <juce_gui_basics/native/juce_WindowsHooks_windows.h>
#include <juce_audio_plugin_client/detail/juce_PluginUtilities.h>
#include <juce_audio_devices/juce_audio_devices.h>
#include <juce_gui_extra/juce_gui_extra.h>
#include <juce_audio_utils/juce_audio_utils.h>
// You can set this flag in your build if you need to specify a different
// standalone JUCEApplication class for your app to use. If you don't
// set it then by default we'll just create a simple one as below.
#if JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP
// #include <juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h>
#include "CustomStandaloneFilterWindow.h"
namespace juce
{
//==============================================================================
class CustomStandaloneFilterApp final : public JUCEApplication
{
public:
CustomStandaloneFilterApp()
{
PropertiesFile::Options options;
options.applicationName = CharPointer_UTF8 (JucePlugin_Name);
options.filenameSuffix = ".settings";
options.osxLibrarySubFolder = "Application Support";
#if JUCE_LINUX || JUCE_BSD
options.folderName = "~/.config";
#else
options.folderName = "";
#endif
appProperties.setStorageParameters (options);
}
const String getApplicationName() override { return CharPointer_UTF8 (JucePlugin_Name); }
const String getApplicationVersion() override { return JucePlugin_VersionString; }
bool moreThanOneInstanceAllowed() override { return true; }
void anotherInstanceStarted (const String& commandLine) override
{
if (mainWindow != nullptr)
{
mainWindow->toFront(true);
mainWindow->handleCommandLine(commandLine);
}
}
virtual StandaloneFilterWindow* createWindow()
{
if (Desktop::getInstance().getDisplays().displays.isEmpty())
{
// No displays are available, so no window will be created!
jassertfalse;
return nullptr;
}
return new StandaloneFilterWindow (getApplicationName(),
LookAndFeel::getDefaultLookAndFeel().findColour (ResizableWindow::backgroundColourId),
createPluginHolder());
}
virtual std::unique_ptr<StandalonePluginHolder> createPluginHolder()
{
constexpr auto autoOpenMidiDevices =
#if (JUCE_ANDROID || JUCE_IOS) && ! JUCE_DONT_AUTO_OPEN_MIDI_DEVICES_ON_MOBILE
true;
#else
false;
#endif
#ifdef JucePlugin_PreferredChannelConfigurations
constexpr StandalonePluginHolder::PluginInOuts channels[] { JucePlugin_PreferredChannelConfigurations };
const Array<StandalonePluginHolder::PluginInOuts> channelConfig (channels, juce::numElementsInArray (channels));
#else
const Array<StandalonePluginHolder::PluginInOuts> channelConfig;
#endif
return std::make_unique<StandalonePluginHolder> (appProperties.getUserSettings(),
false,
String{},
nullptr,
channelConfig,
autoOpenMidiDevices);
}
//==============================================================================
void initialise (const String& commandLine) override
{
mainWindow = rawToUniquePtr (createWindow());
if (mainWindow != nullptr)
{
#if JUCE_STANDALONE_FILTER_WINDOW_USE_KIOSK_MODE
Desktop::getInstance().setKioskModeComponent (mainWindow.get(), false);
#endif
mainWindow->setVisible (true);
}
else
{
pluginHolder = createPluginHolder();
mainWindow->handleCommandLine(commandLine);
}
}
void shutdown() override
{
pluginHolder = nullptr;
mainWindow = nullptr;
appProperties.saveIfNeeded();
}
//==============================================================================
void systemRequestedQuit() override
{
if (pluginHolder != nullptr)
pluginHolder->savePluginState();
if (mainWindow != nullptr)
mainWindow->pluginHolder->savePluginState();
if (ModalComponentManager::getInstance()->cancelAllModalComponents())
{
Timer::callAfterDelay (100, []()
{
if (auto app = JUCEApplicationBase::getInstance())
app->systemRequestedQuit();
});
}
else
{
quit();
}
}
protected:
ApplicationProperties appProperties;
std::unique_ptr<StandaloneFilterWindow> mainWindow;
private:
std::unique_ptr<StandalonePluginHolder> pluginHolder;
};
} // namespace juce
#if JucePlugin_Build_Standalone && JUCE_IOS
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes")
using namespace juce;
bool JUCE_CALLTYPE juce_isInterAppAudioConnected()
{
if (auto holder = StandalonePluginHolder::getInstance())
return holder->isInterAppAudioConnected();
return false;
}
void JUCE_CALLTYPE juce_switchToHostApplication()
{
if (auto holder = StandalonePluginHolder::getInstance())
holder->switchToHostApplication();
}
Image JUCE_CALLTYPE juce_getIAAHostIcon (int size)
{
if (auto holder = StandalonePluginHolder::getInstance())
return holder->getIAAHostIcon (size);
return Image();
}
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
#endif
#if JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP
// extern juce::JUCEApplicationBase* juce_CreateApplication();
JUCE_CREATE_APPLICATION_DEFINE (juce::CustomStandaloneFilterApp)
#if JUCE_IOS
extern void* juce_GetIOSCustomDelegateClass();
#endif
#else
JUCE_CREATE_APPLICATION_DEFINE (juce::CustomStandaloneFilterApp)
#endif
#if ! JUCE_USE_CUSTOM_PLUGIN_STANDALONE_ENTRYPOINT
// JUCE_MAIN_FUNCTION_DEFINITION
#endif
#endif

Plik diff jest za duży Load Diff

Wyświetl plik

@ -10,7 +10,7 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
fileButton.setButtonText("Choose File(s)");
fileButton.onClick = [this] {
chooser = std::make_unique<juce::FileChooser>("Open", audioProcessor.lastOpenedDirectory, "*.obj;*.svg;*.lua;*.txt;*.gpla;*.gif;*.png;*.jpg;*.jpeg;*.wav;*.aiff");
chooser = std::make_unique<juce::FileChooser>("Open", audioProcessor.lastOpenedDirectory, "*.obj;*.svg;*.lua;*.txt;*.gpla;*.gif;*.png;*.jpg;*.jpeg;*.wav;*.aiff;*.ogg;*.flac;*.mp3");
auto flags = juce::FileBrowserComponent::openMode | juce::FileBrowserComponent::canSelectMultipleItems |
juce::FileBrowserComponent::canSelectFiles;

Wyświetl plik

@ -1,6 +1,6 @@
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include <juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h>
#include "CustomStandaloneFilterWindow.h"
OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioProcessor& p) : CommonPluginEditor(p, "osci-render", "osci", 1100, 750), audioProcessor(p), collapseButton("Collapse", juce::Colours::white, juce::Colours::white, juce::Colours::white) {
#if !SOSCI_FEATURES
@ -109,6 +109,9 @@ bool OscirenderAudioProcessorEditor::isInterestedInFileDrag(const juce::StringAr
return
file.hasFileExtension("wav") ||
file.hasFileExtension("aiff") ||
file.hasFileExtension("ogg") ||
file.hasFileExtension("flac") ||
file.hasFileExtension("mp3") ||
file.hasFileExtension("osci") ||
file.hasFileExtension("txt") ||
file.hasFileExtension("lua") ||
@ -139,7 +142,8 @@ void OscirenderAudioProcessorEditor::filesDropped(const juce::StringArray& files
}
bool OscirenderAudioProcessorEditor::isBinaryFile(juce::String name) {
return name.endsWith(".gpla") || name.endsWith(".gif") || name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".wav") || name.endsWith(".aiff");
name = name.toLowerCase();
return name.endsWith(".gpla") || name.endsWith(".gif") || name.endsWith(".png") || name.endsWith(".jpg") || name.endsWith(".jpeg") || name.endsWith(".wav") || name.endsWith(".aiff") || name.endsWith(".ogg") || name.endsWith(".mp3") || name.endsWith(".flac");
}
// parsersLock must be held

Wyświetl plik

@ -321,7 +321,7 @@ void OscirenderAudioProcessor::openFile(int index) {
if (index < 0 || index >= fileBlocks.size()) {
return;
}
parsers[index]->parse(juce::String(fileIds[index]), fileNames[index].fromLastOccurrenceOf(".", true, false), std::make_unique<juce::MemoryInputStream>(*fileBlocks[index], false), font);
parsers[index]->parse(juce::String(fileIds[index]), fileNames[index].fromLastOccurrenceOf(".", true, false).toLowerCase(), std::make_unique<juce::MemoryInputStream>(*fileBlocks[index], false), font);
changeCurrentFile(index);
}

Wyświetl plik

@ -1,6 +1,6 @@
#include "SosciPluginProcessor.h"
#include "SosciPluginEditor.h"
#include <juce_audio_plugin_client/Standalone/juce_StandaloneFilterWindow.h>
#include "CustomStandaloneFilterWindow.h"
SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p) : CommonPluginEditor(p, "sosci", "sosci", 1180, 750), audioProcessor(p) {
initialiseMenuBar(model);

Wyświetl plik

@ -192,7 +192,9 @@ void EffectComponent::parameterGestureChanged(int parameterIndex, bool gestureIs
void EffectComponent::handleAsyncUpdate() {
setupComponent();
getParentComponent()->repaint();
if (auto* parent = getParentComponent()) {
parent->repaint();
}
}
void EffectComponent::setRangeEnabled(bool enabled) {

Wyświetl plik

@ -10,9 +10,9 @@ OsciMainMenuBarModel::OsciMainMenuBarModel(OscirenderAudioProcessor& p, Oscirend
addTopLevelMenu("Audio");
}
addMenuItem(0, "Open", [this] { editor.openProject(); });
addMenuItem(0, "Save", [this] { editor.saveProject(); });
addMenuItem(0, "Save As", [this] { editor.saveProjectAs(); });
addMenuItem(0, "Open Project", [this] { editor.openProject(); });
addMenuItem(0, "Save Project", [this] { editor.saveProject(); });
addMenuItem(0, "Save Project As", [this] { editor.saveProjectAs(); });
if (editor.processor.wrapperType == juce::AudioProcessor::WrapperType::wrapperType_Standalone) {
addMenuItem(0, "Create New Project", [this] { editor.resetToDefault(); });
}

Wyświetl plik

@ -12,6 +12,9 @@ ImageParser::ImageParser(OscirenderAudioProcessor& p, juce::String extension, ju
if (output.openedOk()) {
output.write(image.getData(), image.getSize());
output.flush();
} else {
handleError("The image could not be loaded.");
return;
}
}
@ -43,38 +46,45 @@ ImageParser::ImageParser(OscirenderAudioProcessor& p, juce::String extension, ju
}
gd_close_gif(gif);
} else {
handleError("The image could not be loaded. Please try optimising the GIF with https://ezgif.com/optimize.");
return;
}
} else {
juce::Image image = juce::ImageFileFormat::loadFrom(file);
image.desaturate();
width = image.getWidth();
height = image.getHeight();
int frameSize = width * height;
visited = std::vector<bool>(frameSize, false);
frames.emplace_back(std::vector<uint8_t>(frameSize));
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
juce::Colour pixel = image.getPixelAt(x, y);
int index = y * width + x;
// RGB should be equal since we have desaturated
int value = pixel.getRed();
// value of 0 is reserved for transparent pixels
frames[0][index] = pixel.isTransparent() ? 0 : juce::jmax(1, value);
if (image.isValid()) {
image.desaturate();
width = image.getWidth();
height = image.getHeight();
int frameSize = width * height;
visited = std::vector<bool>(frameSize, false);
frames.emplace_back(std::vector<uint8_t>(frameSize));
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
juce::Colour pixel = image.getPixelAt(x, y);
int index = y * width + x;
// RGB should be equal since we have desaturated
int value = pixel.getRed();
// value of 0 is reserved for transparent pixels
frames[0][index] = pixel.isTransparent() ? 0 : juce::jmax(1, value);
}
}
} else {
handleError("The image could not be loaded.");
return;
}
}
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));
if (extension.equalsIgnoreCase(".gif")) {
handleError("The image could not be loaded. Please try optimising the GIF with https://ezgif.com/optimize.");
} else {
handleError("The image could not be loaded.");
}
return;
}
setFrame(0);
@ -82,6 +92,17 @@ ImageParser::ImageParser(OscirenderAudioProcessor& p, juce::String extension, ju
ImageParser::~ImageParser() {}
void ImageParser::handleError(juce::String message) {
juce::MessageManager::callAsync([this, message] {
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::AlertIconType::WarningIcon, "Error", message);
});
width = 1;
height = 1;
frames.emplace_back(std::vector<uint8_t>(1));
setFrame(0);
}
void ImageParser::setFrame(int index) {
// Ensure that the frame number is within the bounds of the number of frames
// This weird modulo trick is to handle negative numbers
@ -160,20 +181,52 @@ void ImageParser::findNearestNeighbour(int searchRadius, float thresholdPow, int
}
OsciPoint ImageParser::getSample() {
if (count % jumpFrequency() == 0) {
resetPosition();
if (ALGORITHM == "HILLIGOSS") {
if (count % jumpFrequency() == 0) {
resetPosition();
}
if (count % 10 * jumpFrequency() == 0) {
std::fill(visited.begin(), visited.end(), false);
}
float thresholdPow = audioProcessor.imageThreshold->getActualValue() * 10 + 1;
findNearestNeighbour(10, thresholdPow, audioProcessor.imageStride->getActualValue(), audioProcessor.invertImage->getValue());
float maxDim = juce::jmax(width, height);
count++;
float widthDiff = (maxDim - width) / 2;
float heightDiff = (maxDim - height) / 2;
return OsciPoint(2 * (currentX + widthDiff) / maxDim - 1, 2 * (currentY + heightDiff) / maxDim - 1);
} else {
double scanIncrement = audioProcessor.imageStride->getActualValue() / 100;
double pixel = 0;
int maxIterations = 10000;
while (pixel <= audioProcessor.imageThreshold->getActualValue() && maxIterations > 0) {
int x = (int) ((scanX + 1) * width / 2);
int y = (int) ((scanY + 1) * height / 2);
pixel = getPixelValue(x, y, audioProcessor.invertImage->getValue());
double increment = 0.01;
if (pixel > audioProcessor.imageThreshold->getActualValue()) {
increment = (1 - tanh(4 * pixel)) * 0.3;
}
scanX += increment;
if (scanX >= 1) {
scanX = -1;
scanY -= scanIncrement;
}
if (scanY < -1) {
double offset = ((scanCount % 15) / 15.0) * scanIncrement;
scanY = 1 - offset;
scanCount++;
}
maxIterations--;
}
return OsciPoint(scanX, scanY);
}
if (count % 10 * jumpFrequency() == 0) {
std::fill(visited.begin(), visited.end(), false);
}
float thresholdPow = audioProcessor.imageThreshold->getActualValue() * 10 + 1;
findNearestNeighbour(10, thresholdPow, audioProcessor.imageStride->getActualValue(), audioProcessor.invertImage->getValue());
float maxDim = juce::jmax(width, height);
count++;
float widthDiff = (maxDim - width) / 2;
float heightDiff = (maxDim - height) / 2;
return OsciPoint(2 * (currentX + widthDiff) / maxDim - 1, 2 * (currentY + heightDiff) / maxDim - 1);
}

Wyświetl plik

@ -21,6 +21,9 @@ private:
void findWhite(double thresholdPow, bool invert);
bool isOverThreshold(double pixel, double thresholdValue);
int jumpFrequency();
void handleError(juce::String message);
const juce::String ALGORITHM = "HILLIGOSS";
OscirenderAudioProcessor& audioProcessor;
juce::Random rng;
@ -30,4 +33,9 @@ private:
int currentX, currentY;
int width, height;
int count = 0;
// experiments
double scanX = -1;
double scanY = 1;
int scanCount = 0;
};

Wyświetl plik

@ -41,8 +41,7 @@ void FileParser::parse(juce::String fileId, juce::String extension, std::unique_
}
if (isBinary) {
gpla = std::make_shared<LineArtParser>(gplaData, bytesRead);
}
else {
} else {
stream->setPosition(0);
gpla = std::make_shared<LineArtParser>(stream->readEntireStreamAsString());
}
@ -50,9 +49,13 @@ void FileParser::parse(juce::String fileId, juce::String extension, std::unique_
juce::MemoryBlock buffer{};
int bytesRead = stream->readIntoMemoryBlock(buffer);
img = std::make_shared<ImageParser>(audioProcessor, extension, buffer);
} else if (extension == ".wav" || extension == ".aiff") {
} else if (extension == ".wav" || extension == ".aiff" || extension == ".flac" || extension == ".ogg" || extension == ".mp3") {
wav = std::make_shared<WavParser>(audioProcessor);
wav->parse(std::move(stream));
if (!wav->parse(std::move(stream))) {
juce::MessageManager::callAsync([this] {
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::AlertIconType::WarningIcon, "Error", "The audio file could not be loaded.");
});
}
}
isAnimatable = gpla != nullptr || (img != nullptr && extension == ".gif");

Wyświetl plik

@ -22,6 +22,10 @@ SvgParser::SvgParser(juce::String svgFile) {
}
}
juce::MessageManager::callAsync([this] {
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::AlertIconType::WarningIcon, "Error", "The SVG could not be loaded.");
});
// draw an X to indicate an error.
shapes.push_back(std::make_unique<Line>(-0.5, -0.5, 0.5, 0.5));
shapes.push_back(std::make_unique<Line>(-0.5, 0.5, 0.5, -0.5));

Wyświetl plik

@ -9,7 +9,6 @@ uniform float uSize;
uniform float uIntensity;
uniform vec2 uOffset;
uniform vec2 uScale;
uniform float uScreenOverlay;
uniform float uFishEye;
uniform sampler2D uScreen;
varying float vSize;

Wyświetl plik

@ -7,6 +7,7 @@ uniform float uSize;
uniform float uNEdges;
uniform float uFadeAmount;
uniform float uIntensity;
uniform bool uShutterSync;
uniform float uGain;
attribute vec3 aStart, aEnd;
attribute float aIdx;
@ -25,8 +26,8 @@ void main () {
vec2 aStartPos = aStart.xy;
vec2 aEndPos = aEnd.xy;
float aStartBrightness = aStart.z;
float aEndBrightness = aEnd.z;
float aStartBrightness = clamp(aStart.z, 0.0, 1.0);
float aEndBrightness = clamp(aEnd.z, 0.0, 1.0);
// `dir` vector is storing the normalized difference
// between end and start
@ -56,17 +57,22 @@ void main () {
uvl.w = aStartBrightness;
}
// `side` corresponds to shift to the "right" or "left"
float side = (mod(idx, 2.0)-0.5)*2.0;
float side = (mod(idx, 2.0) - 0.5) * 2.0;
uvl.y = side * vSize;
uvl.w *= intensity * mix(1.0-uFadeAmount, 1.0, floor(aIdx / 4.0 + 0.5)/uNEdges);
float intensityScale = floor(aIdx / 4.0 + 0.5)/uNEdges;
if (uShutterSync) {
float avgIntensityScale = floor(uNEdges / 4.0 + 0.5)/uNEdges;
intensityScale = avgIntensityScale;
}
float intensityFade = mix(1.0 - uFadeAmount, 1.0, intensityScale);
uvl.w *= intensity * intensityFade;
vec4 pos = vec4((current+(tang*dir+norm*side)*vSize)*uInvert,0.0,1.0);
gl_Position = pos;
vTexCoord = 0.5*pos.xy+0.5;
//float seed = floor(aIdx/4.0);
//seed = mod(sin(seed*seed), 7.0);
//if (mod(seed/2.0, 1.0)<0.5) gl_Position = vec4(10.0);
vTexCoord = 0.5 * pos.xy + 0.5;
}
)";

Wyświetl plik

@ -65,7 +65,7 @@ void main() {
// r components have grid; g components do not.
vec4 screen = texture2D(uTexture3, vTexCoord);
vec4 tightGlow = texture2D(uTexture1, linePos);
vec4 scatter = texture2D(uTexture2, linePos) + (1.0 - uRealScreen) * max(uAmbient - 0.35, 0.0);
vec4 scatter = texture2D(uTexture2, linePos);
if (uRealScreen > 0.5) {
vec4 reflection = texture2D(uTexture4, vTexCoord);
@ -73,8 +73,14 @@ void main() {
scatter += max4(screenGlow * reflection * max(1.0 - 0.5 * uAmbient, 0.0), vec4(0.0));
}
float light = line.r + uGlow * 1.5 * screen.g * screen.g * tightGlow.r;
light += uGlow * 0.3 * scatter.g * (2.0 + 1.0 * screen.g + 0.5 * screen.r);
// making the range of the glow slider more useful
float glow = 1.05 * pow(uGlow, 1.5);
float light = line.r + glow * 1.5 * screen.g * screen.g * tightGlow.r;
float scatterScalar = 0.3 * (2.0 + 1.0 * screen.g + 0.5 * screen.r);
light += glow * scatter.g * scatterScalar;
// add ambient light to graticule
light += (1.0 - uRealScreen) * max(uAmbient - 0.35, 0.0) * scatterScalar;
float tlight = 1.0-pow(2.0, -uExposure*light);
float tlight2 = tlight * tlight * tlight;
gl_FragColor.rgb = mix(uColour, vec3(1.0), 0.3+tlight2*tlight2*uOverexposure) * tlight;

Wyświetl plik

@ -239,6 +239,14 @@ void VisualiserComponent::runTask(const std::vector<OsciPoint>& points) {
for (const OsciPoint& rawPoint : points) {
OsciPoint point = applyEffects(rawPoint);
#if SOSCI_FEATURES
if (settings.isGoniometer()) {
// x and y go to a diagonal currently, so we need to scale them down, and rotate them
point.scale(1.0 / std::sqrt(2.0), 1.0 / std::sqrt(2.0), 1.0);
point.rotate(0, 0, juce::MathConstants<double>::pi / 4);
}
#endif
xSamples.push_back(point.x);
ySamples.push_back(point.y);
zSamples.push_back(point.z);
@ -1083,8 +1091,11 @@ void VisualiserComponent::drawLine(const std::vector<float>& xPoints, const std:
setOffsetAndScale(lineShader.get());
#if SOSCI_FEATURES
lineShader->setUniform("uScreenOverlay", (GLfloat) screenOverlay);
lineShader->setUniform("uFishEye", screenOverlay == ScreenOverlay::VectorDisplay ? VECTOR_DISPLAY_FISH_EYE : 0.0f);
lineShader->setUniform("uShutterSync", settings.getShutterSync());
#else
lineShader->setUniform("uFishEye", 0.0f);
lineShader->setUniform("uShutterSync", false);
#endif
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);

Wyświetl plik

@ -240,7 +240,7 @@ private:
juce::OpenGLShaderProgram* currentShader;
float fadeAmount;
ScreenOverlay screenOverlay = ScreenOverlay::MAX;
ScreenOverlay screenOverlay = ScreenOverlay::INVALID;
const double RESAMPLE_RATIO = 6.0;
double sampleRate = -1;

Wyświetl plik

@ -19,6 +19,8 @@ VisualiserSettings::VisualiserSettings(VisualiserParameters& p, int numChannels)
addAndMakeVisible(screenColour);
addAndMakeVisible(flipVerticalToggle);
addAndMakeVisible(flipHorizontalToggle);
addAndMakeVisible(goniometerToggle);
addAndMakeVisible(shutterSyncToggle);
#endif
for (int i = 1; i <= parameters.screenOverlay->max; i++) {
@ -81,6 +83,8 @@ void VisualiserSettings::resized() {
area.removeFromTop(10);
flipVerticalToggle.setBounds(area.removeFromTop(rowHeight));
flipHorizontalToggle.setBounds(area.removeFromTop(rowHeight));
goniometerToggle.setBounds(area.removeFromTop(rowHeight));
shutterSyncToggle.setBounds(area.removeFromTop(rowHeight));
#endif
#if !SOSCI_FEATURES

Wyświetl plik

@ -11,6 +11,7 @@
#include "../audio/StereoEffect.h"
enum class ScreenOverlay : int {
INVALID = -1,
Empty = 1,
Graticule = 2,
Smudged = 3,
@ -97,6 +98,8 @@ public:
#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.");
BooleanParameter* goniometer = new BooleanParameter("Goniometer", "goniometer", VERSION_HINT, false, "Rotates the visualiser to replicate a goniometer display to show the phase relationship between two channels.");
BooleanParameter* shutterSync = new BooleanParameter("Shutter Sync", "shutterSync", VERSION_HINT, false, "Controls whether the camera's shutter speed is in sync with framerate. This makes the brightness of a single frame constant. This can be beneficial when the drawing frequency and frame rate are in sync.");
std::shared_ptr<Effect> screenSaturationEffect = std::make_shared<Effect>(
new EffectParameter(
@ -301,6 +304,8 @@ public:
#if SOSCI_FEATURES
flipVertical,
flipHorizontal,
goniometer,
shutterSync,
#endif
};
std::vector<IntParameter*> integers = {
@ -389,6 +394,14 @@ public:
bool isFlippedHorizontal() {
return parameters.flipHorizontal->getBoolValue();
}
bool isGoniometer() {
return parameters.goniometer->getBoolValue();
}
bool getShutterSync() {
return parameters.shutterSync->getBoolValue();
}
#endif
double getFocus() {
@ -505,6 +518,8 @@ private:
jux::SwitchButton flipVerticalToggle{parameters.flipVertical};
jux::SwitchButton flipHorizontalToggle{parameters.flipHorizontal};
jux::SwitchButton goniometerToggle{parameters.goniometer};
jux::SwitchButton shutterSyncToggle{parameters.shutterSync};
#endif
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(VisualiserSettings)

Wyświetl plik

@ -23,17 +23,6 @@ eval "$RESAVE_COMMAND"
if [ "$OS" = "mac" ]; then
cd "$ROOT/Builds/$PLUGIN/MacOSX"
xcodebuild -configuration Release || exit 1
cp -R "$ROOT/Builds/$PLUGIN/MacOSX/build/Release/$PLUGIN.app" "$ROOT/ci/bin/$OUTPUT_NAME.app"
cp -R ~/Library/Audio/Plug-Ins/VST3/$PLUGIN.vst3 "$ROOT/ci/bin/$OUTPUT_NAME.vst3"
cp -R ~/Library/Audio/Plug-Ins/Components/$PLUGIN.component "$ROOT/ci/bin/$OUTPUT_NAME.component"
cd "$ROOT/ci/bin"
zip -r ${OUTPUT_NAME}-mac.vst3.zip $OUTPUT_NAME.vst3
zip -r ${OUTPUT_NAME}-mac.component.zip $OUTPUT_NAME.component
zip -r ${OUTPUT_NAME}-mac.app.zip $OUTPUT_NAME.app
cp ${OUTPUT_NAME}*.zip "$ROOT/bin"
fi
# Build linux version
@ -41,13 +30,13 @@ if [ "$OS" = "linux" ]; then
cd "$ROOT/Builds/$PLUGIN/LinuxMakefile"
make CONFIG=Release
cp -r ./build/$PLUGIN.vst3 "$ROOT/ci/bin/$OUTPUT_NAME.vst3"
cp -r ./build/$PLUGIN "$ROOT/ci/bin/$OUTPUT_NAME"
cp -r ./build/$PLUGIN.vst3 "$ROOT/ci/bin/$PLUGIN.vst3"
cp -r ./build/$PLUGIN "$ROOT/ci/bin/$PLUGIN"
cd "$ROOT/ci/bin"
zip -r ${OUTPUT_NAME}-linux-vst3.zip $OUTPUT_NAME.vst3
zip -r ${OUTPUT_NAME}-linux.zip $OUTPUT_NAME
zip -r ${OUTPUT_NAME}-linux-vst3.zip $PLUGIN.vst3
zip -r ${OUTPUT_NAME}-linux.zip $PLUGIN
cp ${OUTPUT_NAME}*.zip "$ROOT/bin"
fi
@ -60,10 +49,7 @@ if [ "$OS" = "win" ]; then
cd "$ROOT/Builds/$PLUGIN/VisualStudio2022"
"$MSBUILD_EXE" "$PLUGIN.sln" "//p:VisualStudioVersion=16.0" "//m" "//t:Build" "//p:Configuration=Release" "//p:Platform=x64" "//p:PreferredToolArchitecture=x64" "//restore" "//p:RestorePackagesConfig=true"
cd "$ROOT/ci/bin"
cp "$ROOT/Builds/$PLUGIN/VisualStudio2022/x64/Release/Standalone Plugin/$PLUGIN.exe" "$ROOT/bin/$OUTPUT_NAME-win.exe"
cp "$ROOT/Builds/$PLUGIN/VisualStudio2022/x64/Release/Standalone Plugin/$PLUGIN.pdb" "$ROOT/bin/$OUTPUT_NAME-win.pdb"
cp -r "$ROOT/Builds/$PLUGIN/VisualStudio2022/x64/Release/VST3/$PLUGIN.vst3/Contents/x86_64-win/$PLUGIN.vst3" "$ROOT/bin/$OUTPUT_NAME-win.vst3"
cp "$ROOT/Builds/$PLUGIN/VisualStudio2022/x64/Release/Standalone Plugin/$PLUGIN.pdb" "$ROOT/bin/$OUTPUT_NAME.pdb"
fi
cd "$ROOT"

Wyświetl plik

@ -4,8 +4,8 @@
addUsingNamespaceToJuceHeader="0" jucerFormatVersion="1" pluginCharacteristicsValue="pluginWantsMidiIn"
pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender"
cppLanguageStandard="20" projectLineFeed="&#10;" headerPath="./include"
version="2.4.8.0" 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"
version="2.4.10.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&#10;JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1"
pluginAUMainType="'aumf'">
<MAINGROUP id="j5Ge2T" name="osci-render">
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
@ -673,6 +673,10 @@
file="Source/CommonPluginProcessor.cpp"/>
<FILE id="PGeV6d" name="CommonPluginProcessor.h" compile="0" resource="0"
file="Source/CommonPluginProcessor.h"/>
<FILE id="TPGMru" name="CustomStandalone.cpp" compile="1" resource="0"
file="Source/CustomStandalone.cpp"/>
<FILE id="J0sbNw" name="CustomStandaloneFilterWindow.h" compile="0"
resource="0" file="Source/CustomStandaloneFilterWindow.h"/>
<FILE id="I44EdJ" name="EffectsComponent.cpp" compile="1" resource="0"
file="Source/EffectsComponent.cpp"/>
<FILE id="qxxNX3" name="EffectsComponent.h" compile="0" resource="0"

Wyświetl plik

@ -3,9 +3,9 @@
<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.1.2.0" companyName="James H Ball"
headerPath="./include" version="1.1.4.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"
defines="NOMINMAX=1&#10;INTERNET_FLAG_NO_AUTO_REDIRECT=0&#10;SOSCI_FEATURES=1&#10;JUCE_USE_CUSTOM_PLUGIN_STANDALONE_APP=1"
pluginManufacturerCode="Jhba" pluginCode="Sosc" pluginAUMainType="'aufx'">
<MAINGROUP id="j5Ge2T" name="sosci">
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
@ -76,6 +76,10 @@
</GROUP>
</GROUP>
<GROUP id="{75439074-E50C-362F-1EDF-8B4BE9011259}" name="Source">
<FILE id="fqqP0r" name="CustomStandalone.cpp" compile="1" resource="0"
file="Source/CustomStandalone.cpp"/>
<FILE id="TFmWW0" name="CustomStandaloneFilterWindow.h" compile="0"
resource="0" file="Source/CustomStandaloneFilterWindow.h"/>
<GROUP id="{C63A0AA5-8550-16AC-EE89-C05416216534}" name="wav">
<FILE id="jxAiTf" name="WavParser.cpp" compile="1" resource="0" file="Source/wav/WavParser.cpp"/>
<FILE id="Q6iTsL" name="WavParser.h" compile="0" resource="0" file="Source/wav/WavParser.h"/>