kopia lustrzana https://github.com/jameshball/osci-render
Fix several bugs on Windows, make more stable, and make visualiser consistent across sample rates
rodzic
8deba8dc7c
commit
9bfdca7b99
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
Ładowanie…
Reference in New Issue