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 isDebug = true;
let paused = false; 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 openInAnotherWindow = false;
let externalSampleRate = 96000; let externalSampleRate = 96000;
let externalBufferSize = 1920; let externalBufferSize = 1920;

Wyświetl plik

@ -247,7 +247,7 @@ var Render =
drawLineTexture : function(xPoints, yPoints) 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.activateTargetTexture(this.lineTexture);
this.fade(); this.fade();
//gl.clear(gl.COLOR_BUFFER_BIT); //gl.clear(gl.COLOR_BUFFER_BIT);
@ -432,9 +432,12 @@ var Render =
gl.uniform1f(program.uGain, Math.pow(2.0,controls.mainGain)*450/512); gl.uniform1f(program.uGain, Math.pow(2.0,controls.mainGain)*450/512);
if (controls.invertXY) gl.uniform1f(program.uInvert, -1.0); if (controls.invertXY) gl.uniform1f(program.uInvert, -1.0);
else 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 // +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.uFadeAmount, this.fadeAmount);
gl.uniform1f(program.uNEdges, this.nEdges); gl.uniform1f(program.uNEdges, this.nEdges);
@ -745,11 +748,10 @@ function drawCRTFrame(timeStamp) {
var xSamples = new Float32Array(externalBufferSize); var xSamples = new Float32Array(externalBufferSize);
var ySamples = new Float32Array(externalBufferSize); var ySamples = new Float32Array(externalBufferSize);
const bufferSizeFn = Juce.getNativeFunction("bufferSize");
Juce.getNativeFunction("bufferSize")().then(bufferSize => { Juce.getNativeFunction("bufferSize")().then(bufferSize => {
externalBufferSize = bufferSize; externalBufferSize = bufferSize;
Juce.getNativeFunction("sampleRate")().then(sampleRate => { Juce.getNativeFunction("sampleRate")().then(sampleRate => {
externalSampleRate = sampleRate; externalSampleRate = sampleRate;
xSamples = new Float32Array(externalBufferSize); xSamples = new Float32Array(externalBufferSize);
ySamples = new Float32Array(externalBufferSize); ySamples = new Float32Array(externalBufferSize);
Render.init(); Render.init();

Wyświetl plik

@ -161,14 +161,14 @@ public:
// visualiser settings // visualiser settings
BooleanParameter* graticuleEnabled = new BooleanParameter("Show Graticule", "graticuleEnabled", VERSION_HINT, true, "Show the graticule or grid lines over the oscilloscope display."); 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* 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."); 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>( std::shared_ptr<Effect> persistenceEffect = std::make_shared<Effect>(
new EffectParameter( new EffectParameter(
"Persistence", "Persistence",
"Controls how long the light glows for on the oscilloscope display.", "Controls how long the light glows for on the oscilloscope display.",
"persistence", "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>( std::shared_ptr<Effect> hueEffect = std::make_shared<Effect>(
@ -184,7 +184,7 @@ public:
"Intensity", "Intensity",
"Controls how bright the light glows for on the oscilloscope display.", "Controls how bright the light glows for on the oscilloscope display.",
"intensity", "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; break;
case 1: { case 1: {
audioProcessor.legacyVisualiserEnabled->setBoolValueNotifyingHost(!audioProcessor.legacyVisualiserEnabled->getBoolValue()); audioProcessor.legacyVisualiserEnabled->setBoolValueNotifyingHost(!audioProcessor.legacyVisualiserEnabled->getBoolValue());
editor.visualiser.setVisualiserType(audioProcessor.legacyVisualiserEnabled->getBoolValue());
menuItemsChanged(); menuItemsChanged();
} break; } break;
case 2: { case 2: {

Wyświetl plik

@ -2,6 +2,8 @@
#include "VisualiserComponent.h" #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) { 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(); resetBuffer();
startTimerHz(60); startTimerHz(60);
startThread(); startThread();
@ -11,13 +13,11 @@ VisualiserComponent::VisualiserComponent(OscirenderAudioProcessor& p, Visualiser
settings.setLookAndFeel(&getLookAndFeel()); settings.setLookAndFeel(&getLookAndFeel());
settings.setSize(550, 230); settings.setSize(550, 230);
settingsWindow.setContentNonOwned(&settings, true); settingsWindow.setContentNonOwned(&settings, true);
settingsWindow.centreWithSize(550, 230);
setMouseCursor(juce::MouseCursor::PointingHandCursor); setMouseCursor(juce::MouseCursor::PointingHandCursor);
setWantsKeyboardFocus(true); setWantsKeyboardFocus(true);
addAndMakeVisible(browser);
setVisualiserType(oldVisualiser);
roughness.textBox.setValue(audioProcessor.roughness); roughness.textBox.setValue(audioProcessor.roughness);
roughness.textBox.onValueChange = [this]() { roughness.textBox.onValueChange = [this]() {
audioProcessor.roughness = (int) roughness.textBox.getValue(); audioProcessor.roughness = (int) roughness.textBox.getValue();
@ -140,8 +140,8 @@ void VisualiserComponent::run() {
juce::WeakReference<VisualiserComponent> visualiser(this); juce::WeakReference<VisualiserComponent> visualiser(this);
if (!oldVisualiser) { if (!oldVisualiser) {
juce::MessageManager::callAsync([this, visualiser] () { juce::MessageManager::callAsync([this, visualiser] () {
if (visualiser) { if (visualiser != nullptr && browser != nullptr) {
browser.emitEventIfBrowserIsVisible("audioUpdated", juce::Base64::toBase64(buffer.data(), buffer.size() * sizeof(float))); 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) { void VisualiserComponent::setVisualiserType(bool oldVisualiser) {
this->oldVisualiser = oldVisualiser; this->oldVisualiser = oldVisualiser;
if (oldVisualiser) { if (child != nullptr) {
// required to hide the browser - it is buggy if we use setVisible(false) on Windows child->setVisualiserType(oldVisualiser);
browser.goToURL("about:blank"); }
} else { if (oldVisualiser) {
browser.goToURL(juce::WebBrowserComponent::getResourceProviderRoot() + "oscilloscope.html"); browser.reset();
} else {
initialiseBrowser();
} }
resized();
} }
void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area) { 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() { void VisualiserComponent::resetBuffer() {
sampleRate = (int) audioProcessor.currentSampleRate; sampleRate = (int) audioProcessor.currentSampleRate;
tempBuffer = std::vector<float>(2 * sampleRate * BUFFER_LENGTH_SECS); tempBuffer = std::vector<float>(2 * sampleRate * BUFFER_LENGTH_SECS);
if (!oldVisualiser) { if (!oldVisualiser && isShowing()) {
browser.goToURL(juce::WebBrowserComponent::getResourceProviderRoot() + "oscilloscope.html"); juce::MessageManager::callAsync([this] () {
initialiseBrowser();
});
} }
} }
void VisualiserComponent::resized() { void VisualiserComponent::resized() {
if (oldVisualiser) { if (!oldVisualiser) {
browser.setBounds(0, 0, 0, 0); browser->setBounds(getLocalBounds());
} else {
browser.setBounds(getLocalBounds());
} }
auto area = getLocalBounds(); auto area = getLocalBounds();
area.removeFromBottom(5); area.removeFromBottom(5);
@ -290,11 +345,11 @@ void VisualiserComponent::resized() {
} }
void VisualiserComponent::childChanged() { void VisualiserComponent::childChanged() {
browser.emitEventIfBrowserIsVisible("childPresent", child != nullptr); browser->emitEventIfBrowserIsVisible("childPresent", child != nullptr);
} }
void VisualiserComponent::popoutWindow() { void VisualiserComponent::popoutWindow() {
auto visualiser = new VisualiserComponent(audioProcessor, this); auto visualiser = new VisualiserComponent(audioProcessor, this, oldVisualiser);
visualiser->settings.setLookAndFeel(&getLookAndFeel()); visualiser->settings.setLookAndFeel(&getLookAndFeel());
child = visualiser; child = visualiser;
childChanged(); childChanged();
@ -305,6 +360,7 @@ void VisualiserComponent::popoutWindow() {
popout->setUsingNativeTitleBar(true); popout->setUsingNativeTitleBar(true);
popout->setResizable(true, false); popout->setResizable(true, false);
popout->setVisible(true); popout->setVisible(true);
popout->centreWithSize(300, 300);
setPaused(true); setPaused(true);
resized(); resized();
popOutButton.setVisible(false); popOutButton.setVisible(false);

Wyświetl plik

@ -21,9 +21,6 @@ public:
VisualiserComponent(OscirenderAudioProcessor& p, VisualiserComponent* parent = nullptr, bool useOldVisualiser = false); VisualiserComponent(OscirenderAudioProcessor& p, VisualiserComponent* parent = nullptr, bool useOldVisualiser = false);
~VisualiserComponent() override; ~VisualiserComponent() override;
void setIntensity(double intensity);
void setPersistence(double persistence);
void setHue(double hue);
void openSettings(); void openSettings();
void childChanged(); void childChanged();
void enableFullScreen(); void enableFullScreen();
@ -109,46 +106,10 @@ private:
juce::WebBrowserComponent::Resource resource = { data, mimeType }; juce::WebBrowserComponent::Resource resource = { data, mimeType };
return resource; return resource;
}; };
std::unique_ptr<juce::WebBrowserComponent> browser = nullptr;
juce::WebBrowserComponent browser = juce::WebBrowserComponent( void initialiseBrowser();
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 resetBuffer(); void resetBuffer();
void popoutWindow(); void popoutWindow();

Wyświetl plik

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