Fix several bugs on Windows, make more stable, and make visualiser consistent across sample rates

pull/249/head
James H Ball 2024-08-20 21:25:31 +01:00 zatwierdzone przez James H Ball
rodzic 8deba8dc7c
commit 9bfdca7b99
7 zmienionych plików z 99 dodań i 72 usunięć

Wyświetl plik

@ -119,6 +119,15 @@
let isDebug = true;
let paused = false;
Juce.getNativeFunction("isPaused")().then(isPaused => {
paused = isPaused;
if (isPaused) {
overlay.style.display = "flex";
} else {
overlay.style.display = "none";
}
});
let openInAnotherWindow = false;
let externalSampleRate = 96000;
let externalBufferSize = 1920;

Wyświetl plik

@ -247,7 +247,7 @@ var Render =
drawLineTexture : function(xPoints, yPoints)
{
this.fadeAmount = Math.pow(0.5, controls.persistence)*0.2*AudioSystem.bufferSize/512 ;
this.fadeAmount = Math.min(1, Math.pow(0.5, controls.persistence) * 0.4);
this.activateTargetTexture(this.lineTexture);
this.fade();
//gl.clear(gl.COLOR_BUFFER_BIT);
@ -432,9 +432,12 @@ var Render =
gl.uniform1f(program.uGain, Math.pow(2.0,controls.mainGain)*450/512);
if (controls.invertXY) gl.uniform1f(program.uInvert, -1.0);
else gl.uniform1f(program.uInvert, 1.0);
if (controls.disableFilter) gl.uniform1f(program.uIntensity, 0.005*(Filter.steps+1.5));
var intensity = 0.02 * (41000 / externalSampleRate);
if (controls.disableFilter) gl.uniform1f(program.uIntensity, intensity *(Filter.steps+1.5));
// +1.5 needed above for some reason for the brightness to match
else gl.uniform1f(program.uIntensity, 0.005);
else gl.uniform1f(program.uIntensity, intensity);
gl.uniform1f(program.uFadeAmount, this.fadeAmount);
gl.uniform1f(program.uNEdges, this.nEdges);
@ -745,11 +748,10 @@ function drawCRTFrame(timeStamp) {
var xSamples = new Float32Array(externalBufferSize);
var ySamples = new Float32Array(externalBufferSize);
const bufferSizeFn = Juce.getNativeFunction("bufferSize");
Juce.getNativeFunction("bufferSize")().then(bufferSize => {
externalBufferSize = bufferSize;
Juce.getNativeFunction("sampleRate")().then(sampleRate => {
externalSampleRate = sampleRate;
externalSampleRate = sampleRate;
xSamples = new Float32Array(externalBufferSize);
ySamples = new Float32Array(externalBufferSize);
Render.init();

Wyświetl plik

@ -161,14 +161,14 @@ public:
// visualiser settings
BooleanParameter* graticuleEnabled = new BooleanParameter("Show Graticule", "graticuleEnabled", VERSION_HINT, true, "Show the graticule or grid lines over the oscilloscope display.");
BooleanParameter* smudgesEnabled = new BooleanParameter("Show Smudges", "smudgesEnabled", VERSION_HINT, true, "Adds a subtle layer of dirt/smudges to the oscilloscope display to make it look more realistic.");
BooleanParameter* upsamplingEnabled = new BooleanParameter("Upsample Audio", "upsamplingEnabled", VERSION_HINT, true, "Upsamples the audio before visualising it to make it appear more realistic, at the expense of performance.");
BooleanParameter* upsamplingEnabled = new BooleanParameter("Upsample Audio", "upsamplingEnabled", VERSION_HINT, false, "Upsamples the audio before visualising it to make it appear more realistic, at the expense of performance.");
BooleanParameter* legacyVisualiserEnabled = new BooleanParameter("Use Legacy Visualiser", "legacyVisualiserEnabled", VERSION_HINT, false, "Replaces the realistic oscilloscope visualiser with the legacy visualiser. This may improve performance.");
std::shared_ptr<Effect> persistenceEffect = std::make_shared<Effect>(
new EffectParameter(
"Persistence",
"Controls how long the light glows for on the oscilloscope display.",
"persistence",
VERSION_HINT, 0.0, -1.0, 2.0
VERSION_HINT, 0.5, 0, 6.0
)
);
std::shared_ptr<Effect> hueEffect = std::make_shared<Effect>(
@ -184,7 +184,7 @@ public:
"Intensity",
"Controls how bright the light glows for on the oscilloscope display.",
"intensity",
VERSION_HINT, 1.0, -2.0, 2.0
VERSION_HINT, 3.0, 0.0, 10.0
)
);

Wyświetl plik

@ -68,7 +68,6 @@ void MainMenuBarModel::menuItemSelected(int menuItemID, int topLevelMenuIndex) {
break;
case 1: {
audioProcessor.legacyVisualiserEnabled->setBoolValueNotifyingHost(!audioProcessor.legacyVisualiserEnabled->getBoolValue());
editor.visualiser.setVisualiserType(audioProcessor.legacyVisualiserEnabled->getBoolValue());
menuItemsChanged();
} break;
case 2: {

Wyświetl plik

@ -2,6 +2,8 @@
#include "VisualiserComponent.h"
VisualiserComponent::VisualiserComponent(OscirenderAudioProcessor& p, VisualiserComponent* parent, bool useOldVisualiser) : backgroundColour(juce::Colours::black), waveformColour(juce::Colour(0xff00ff00)), audioProcessor(p), oldVisualiser(useOldVisualiser), juce::Thread("VisualiserComponent"), parent(parent) {
setVisualiserType(oldVisualiser);
resetBuffer();
startTimerHz(60);
startThread();
@ -11,13 +13,11 @@ VisualiserComponent::VisualiserComponent(OscirenderAudioProcessor& p, Visualiser
settings.setLookAndFeel(&getLookAndFeel());
settings.setSize(550, 230);
settingsWindow.setContentNonOwned(&settings, true);
settingsWindow.centreWithSize(550, 230);
setMouseCursor(juce::MouseCursor::PointingHandCursor);
setWantsKeyboardFocus(true);
addAndMakeVisible(browser);
setVisualiserType(oldVisualiser);
roughness.textBox.setValue(audioProcessor.roughness);
roughness.textBox.onValueChange = [this]() {
audioProcessor.roughness = (int) roughness.textBox.getValue();
@ -140,8 +140,8 @@ void VisualiserComponent::run() {
juce::WeakReference<VisualiserComponent> visualiser(this);
if (!oldVisualiser) {
juce::MessageManager::callAsync([this, visualiser] () {
if (visualiser) {
browser.emitEventIfBrowserIsVisible("audioUpdated", juce::Base64::toBase64(buffer.data(), buffer.size() * sizeof(float)));
if (visualiser != nullptr && browser != nullptr) {
browser->emitEventIfBrowserIsVisible("audioUpdated", juce::Base64::toBase64(buffer.data(), buffer.size() * sizeof(float)));
}
});
}
@ -223,13 +223,14 @@ void VisualiserComponent::setFullScreen(bool fullScreen) {}
void VisualiserComponent::setVisualiserType(bool oldVisualiser) {
this->oldVisualiser = oldVisualiser;
if (oldVisualiser) {
// required to hide the browser - it is buggy if we use setVisible(false) on Windows
browser.goToURL("about:blank");
} else {
browser.goToURL(juce::WebBrowserComponent::getResourceProviderRoot() + "oscilloscope.html");
if (child != nullptr) {
child->setVisualiserType(oldVisualiser);
}
if (oldVisualiser) {
browser.reset();
} else {
initialiseBrowser();
}
resized();
}
void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area) {
@ -262,19 +263,73 @@ void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area
}
}
void VisualiserComponent::initialiseBrowser() {
browser = std::make_unique<juce::WebBrowserComponent>(
juce::WebBrowserComponent::Options()
.withNativeIntegrationEnabled()
.withResourceProvider(provider)
.withBackend(juce::WebBrowserComponent::Options::Backend::webview2)
.withKeepPageLoadedWhenBrowserIsHidden()
.withWinWebView2Options(
juce::WebBrowserComponent::Options::WinWebView2{}
.withUserDataFolder(juce::File::getSpecialLocation(juce::File::SpecialLocationType::userApplicationDataDirectory).getChildFile("osci-render"))
.withStatusBarDisabled()
.withBuiltInErrorPageDisabled()
)
.withNativeFunction("toggleFullscreen", [this](auto& var, auto complete) {
enableFullScreen();
})
.withNativeFunction("popout", [this](auto& var, auto complete) {
popoutWindow();
})
.withNativeFunction("settings", [this](auto& var, auto complete) {
openSettings();
})
.withNativeFunction("isDebug", [this](auto& var, auto complete) {
#if JUCE_DEBUG
complete(true);
#else
complete(false);
#endif
})
.withNativeFunction("isOverlay", [this](auto& var, auto complete) {
complete(parent != nullptr);
})
.withNativeFunction("isPaused", [this](auto& var, auto complete) {
complete(!active);
})
.withNativeFunction("pause", [this](auto& var, auto complete) {
setPaused(active);
})
.withNativeFunction("getSettings", [this](auto& var, auto complete) {
complete(settings.getSettings());
})
.withNativeFunction("bufferSize", [this](auto& var, auto complete) {
complete((int) tempBuffer.size() / 2);
})
.withNativeFunction("sampleRate", [this](auto& var, auto complete) {
complete(sampleRate);
})
);
addAndMakeVisible(*browser);
browser->goToURL(juce::WebBrowserComponent::getResourceProviderRoot() + "oscilloscope.html");
resized();
}
void VisualiserComponent::resetBuffer() {
sampleRate = (int) audioProcessor.currentSampleRate;
tempBuffer = std::vector<float>(2 * sampleRate * BUFFER_LENGTH_SECS);
if (!oldVisualiser) {
browser.goToURL(juce::WebBrowserComponent::getResourceProviderRoot() + "oscilloscope.html");
if (!oldVisualiser && isShowing()) {
juce::MessageManager::callAsync([this] () {
initialiseBrowser();
});
}
}
void VisualiserComponent::resized() {
if (oldVisualiser) {
browser.setBounds(0, 0, 0, 0);
} else {
browser.setBounds(getLocalBounds());
if (!oldVisualiser) {
browser->setBounds(getLocalBounds());
}
auto area = getLocalBounds();
area.removeFromBottom(5);
@ -290,11 +345,11 @@ void VisualiserComponent::resized() {
}
void VisualiserComponent::childChanged() {
browser.emitEventIfBrowserIsVisible("childPresent", child != nullptr);
browser->emitEventIfBrowserIsVisible("childPresent", child != nullptr);
}
void VisualiserComponent::popoutWindow() {
auto visualiser = new VisualiserComponent(audioProcessor, this);
auto visualiser = new VisualiserComponent(audioProcessor, this, oldVisualiser);
visualiser->settings.setLookAndFeel(&getLookAndFeel());
child = visualiser;
childChanged();
@ -305,6 +360,7 @@ void VisualiserComponent::popoutWindow() {
popout->setUsingNativeTitleBar(true);
popout->setResizable(true, false);
popout->setVisible(true);
popout->centreWithSize(300, 300);
setPaused(true);
resized();
popOutButton.setVisible(false);

Wyświetl plik

@ -21,9 +21,6 @@ public:
VisualiserComponent(OscirenderAudioProcessor& p, VisualiserComponent* parent = nullptr, bool useOldVisualiser = false);
~VisualiserComponent() override;
void setIntensity(double intensity);
void setPersistence(double persistence);
void setHue(double hue);
void openSettings();
void childChanged();
void enableFullScreen();
@ -109,46 +106,10 @@ private:
juce::WebBrowserComponent::Resource resource = { data, mimeType };
return resource;
};
std::unique_ptr<juce::WebBrowserComponent> browser = nullptr;
juce::WebBrowserComponent browser = juce::WebBrowserComponent(
juce::WebBrowserComponent::Options()
.withNativeIntegrationEnabled()
.withResourceProvider(provider)
.withBackend(juce::WebBrowserComponent::Options::Backend::webview2)
.withWinWebView2Options(juce::WebBrowserComponent::Options::WinWebView2{})
.withNativeFunction("toggleFullscreen", [this](auto& var, auto complete) {
enableFullScreen();
})
.withNativeFunction("popout", [this](auto& var, auto complete) {
popoutWindow();
})
.withNativeFunction("settings", [this](auto& var, auto complete) {
openSettings();
})
.withNativeFunction("isDebug", [this](auto& var, auto complete) {
#if JUCE_DEBUG
complete(true);
#else
complete(false);
#endif
})
.withNativeFunction("isOverlay", [this](auto& var, auto complete) {
complete(parent != nullptr);
})
.withNativeFunction("pause", [this](auto& var, auto complete) {
setPaused(active);
})
.withNativeFunction("getSettings", [this](auto& var, auto complete) {
complete(settings.getSettings());
})
.withNativeFunction("bufferSize", [this](auto& var, auto complete) {
complete((int) tempBuffer.size() / 2);
})
.withNativeFunction("sampleRate", [this](auto& var, auto complete) {
complete(sampleRate);
})
);
void initialiseBrowser();
void resetBuffer();
void popoutWindow();

Wyświetl plik

@ -30,8 +30,8 @@ void VisualiserSettings::resized() {
juce::var VisualiserSettings::getSettings() {
auto settings = new juce::DynamicObject();
settings->setProperty("intensity", audioProcessor.intensityEffect->getActualValue());
settings->setProperty("persistence", audioProcessor.persistenceEffect->getActualValue());
settings->setProperty("intensity", audioProcessor.intensityEffect->getActualValue() - 2);
settings->setProperty("persistence", audioProcessor.persistenceEffect->getActualValue() - 1.33);
settings->setProperty("hue", audioProcessor.hueEffect->getActualValue());
settings->setProperty("graticule", audioProcessor.graticuleEnabled->getBoolValue());
settings->setProperty("smudges", audioProcessor.smudgesEnabled->getBoolValue());