kopia lustrzana https://github.com/jameshball/osci-render
Add pop-up for downloading ffmpeg and complete downloader implementation
rodzic
7b98b34b04
commit
f26ea1011a
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
|
@ -0,0 +1,93 @@
|
||||||
|
Copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
|
@ -26,6 +26,8 @@ OscirenderLookAndFeel::OscirenderLookAndFeel() {
|
||||||
setColour(juce::TooltipWindow::backgroundColourId, Colours::darker);
|
setColour(juce::TooltipWindow::backgroundColourId, Colours::darker);
|
||||||
setColour(juce::TooltipWindow::outlineColourId, juce::Colours::white);
|
setColour(juce::TooltipWindow::outlineColourId, juce::Colours::white);
|
||||||
setColour(juce::TextButton::buttonOnColourId, Colours::darker);
|
setColour(juce::TextButton::buttonOnColourId, Colours::darker);
|
||||||
|
setColour(juce::AlertWindow::outlineColourId, Colours::darker);
|
||||||
|
setColour(juce::AlertWindow::backgroundColourId, Colours::darker);
|
||||||
|
|
||||||
// combo box
|
// combo box
|
||||||
setColour(juce::ComboBox::backgroundColourId, Colours::veryDark);
|
setColour(juce::ComboBox::backgroundColourId, Colours::veryDark);
|
||||||
|
@ -80,12 +82,14 @@ OscirenderLookAndFeel::OscirenderLookAndFeel() {
|
||||||
setColour(juce::MidiKeyboardComponent::upDownButtonBackgroundColourId, Colours::veryDark);
|
setColour(juce::MidiKeyboardComponent::upDownButtonBackgroundColourId, Colours::veryDark);
|
||||||
setColour(juce::MidiKeyboardComponent::upDownButtonArrowColourId, juce::Colours::white);
|
setColour(juce::MidiKeyboardComponent::upDownButtonArrowColourId, juce::Colours::white);
|
||||||
|
|
||||||
|
// progress bar
|
||||||
|
setColour(juce::ProgressBar::backgroundColourId, juce::Colours::transparentBlack);
|
||||||
|
setColour(juce::ProgressBar::foregroundColourId, Colours::accentColor);
|
||||||
|
|
||||||
// UI colours
|
// UI colours
|
||||||
getCurrentColourScheme().setUIColour(ColourScheme::widgetBackground, Colours::veryDark);
|
getCurrentColourScheme().setUIColour(ColourScheme::widgetBackground, Colours::veryDark);
|
||||||
getCurrentColourScheme().setUIColour(ColourScheme::UIColour::defaultFill, Colours::accentColor);
|
getCurrentColourScheme().setUIColour(ColourScheme::UIColour::defaultFill, Colours::accentColor);
|
||||||
|
|
||||||
setDefaultSansSerifTypeface(juce::Typeface::createSystemTypefaceFor(BinaryData::font_ttf, BinaryData::font_ttfSize));
|
|
||||||
|
|
||||||
// I have to do this, otherwise components are initialised before the look and feel is set
|
// I have to do this, otherwise components are initialised before the look and feel is set
|
||||||
juce::LookAndFeel::setDefaultLookAndFeel(this);
|
juce::LookAndFeel::setDefaultLookAndFeel(this);
|
||||||
}
|
}
|
||||||
|
@ -372,3 +376,88 @@ void OscirenderLookAndFeel::drawCallOutBoxBackground(juce::CallOutBox& box, juce
|
||||||
g.setColour(juce::Colours::black);
|
g.setColour(juce::Colours::black);
|
||||||
g.strokePath(path, juce::PathStrokeType(1.0f));
|
g.strokePath(path, juce::PathStrokeType(1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OscirenderLookAndFeel::drawProgressBar(juce::Graphics& g, juce::ProgressBar& progressBar, int width, int height, double progress, const juce::String& textToShow) {
|
||||||
|
switch (progressBar.getResolvedStyle()) {
|
||||||
|
case juce::ProgressBar::Style::linear:
|
||||||
|
customDrawLinearProgressBar(g, progressBar, width, height, progress, textToShow);
|
||||||
|
break;
|
||||||
|
case juce::ProgressBar::Style::circular:
|
||||||
|
juce::LookAndFeel_V4::drawProgressBar(g, progressBar, width, height, progress, textToShow);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OscirenderLookAndFeel::customDrawLinearProgressBar(juce::Graphics& g, const juce::ProgressBar& progressBar, int width, int height, double progress, const juce::String& textToShow) {
|
||||||
|
auto background = progressBar.findColour(juce::ProgressBar::backgroundColourId);
|
||||||
|
auto foreground = progressBar.findColour(juce::ProgressBar::foregroundColourId).withAlpha(0.5f);
|
||||||
|
int rectRadius = 2;
|
||||||
|
|
||||||
|
auto barBounds = progressBar.getLocalBounds().toFloat();
|
||||||
|
|
||||||
|
g.setColour(background);
|
||||||
|
g.fillRoundedRectangle(barBounds, rectRadius);
|
||||||
|
|
||||||
|
juce::String text = textToShow.isEmpty() ? "waiting..." : textToShow;
|
||||||
|
|
||||||
|
if (progress >= 0.0f && progress <= 1.0f) {
|
||||||
|
juce::Path p;
|
||||||
|
p.addRoundedRectangle(barBounds, rectRadius);
|
||||||
|
g.reduceClipRegion(p);
|
||||||
|
|
||||||
|
barBounds.setWidth(barBounds.getWidth() * (float) progress);
|
||||||
|
g.setColour(foreground);
|
||||||
|
g.fillRoundedRectangle(barBounds, rectRadius);
|
||||||
|
} else {
|
||||||
|
if (progress == -2) {
|
||||||
|
background = juce::Colours::red;
|
||||||
|
text = "Error";
|
||||||
|
}
|
||||||
|
|
||||||
|
// spinning bar..
|
||||||
|
g.setColour(background);
|
||||||
|
|
||||||
|
auto stripeWidth = height * 2;
|
||||||
|
auto position = static_cast<int>(juce::Time::getMillisecondCounter() / 15) % stripeWidth;
|
||||||
|
|
||||||
|
juce::Path p;
|
||||||
|
|
||||||
|
for (auto x = static_cast<float> (-position); x < (float) (width + stripeWidth); x += (float) stripeWidth) {
|
||||||
|
p.addQuadrilateral (x, 0.0f,
|
||||||
|
x + (float) stripeWidth * 0.5f, 0.0f,
|
||||||
|
x, static_cast<float> (height),
|
||||||
|
x - (float) stripeWidth * 0.5f, static_cast<float> (height));
|
||||||
|
}
|
||||||
|
|
||||||
|
juce::Image im(juce::Image::ARGB, width, height, true);
|
||||||
|
|
||||||
|
{
|
||||||
|
juce::Graphics g2(im);
|
||||||
|
g2.setColour(foreground);
|
||||||
|
g2.fillRoundedRectangle(barBounds, rectRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.setTiledImageFill(im, 0, 0, 0.85f);
|
||||||
|
g.fillPath(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.setColour(juce::Colours::white);
|
||||||
|
juce::Font font = juce::Font(juce::FontOptions((float) height * 0.9f, juce::Font::bold));
|
||||||
|
g.setFont(font);
|
||||||
|
|
||||||
|
g.drawText(text, 0, 0, width, height, juce::Justification::centred, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
juce::Typeface::Ptr OscirenderLookAndFeel::getTypefaceForFont(const juce::Font& font) {
|
||||||
|
if (font.getTypefaceName() == juce::Font::getDefaultSansSerifFontName()) {
|
||||||
|
if (font.getTypefaceStyle() == "Regular") {
|
||||||
|
return regularTypeface;
|
||||||
|
} else if (font.getTypefaceStyle() == "Bold") {
|
||||||
|
return boldTypeface;
|
||||||
|
} else if (font.getTypefaceStyle() == "Italic") {
|
||||||
|
return italicTypeface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return juce::Font::getDefaultTypefaceForFont(font);
|
||||||
|
}
|
||||||
|
|
|
@ -66,6 +66,9 @@ public:
|
||||||
OscirenderLookAndFeel();
|
OscirenderLookAndFeel();
|
||||||
|
|
||||||
static const int RECT_RADIUS = 5;
|
static const int RECT_RADIUS = 5;
|
||||||
|
juce::Typeface::Ptr regularTypeface = juce::Typeface::createSystemTypefaceFor(BinaryData::FiraSansRegular_ttf, BinaryData::FiraSansRegular_ttfSize);
|
||||||
|
juce::Typeface::Ptr boldTypeface = juce::Typeface::createSystemTypefaceFor(BinaryData::FiraSansBold_ttf, BinaryData::FiraSansBold_ttfSize);
|
||||||
|
juce::Typeface::Ptr italicTypeface = juce::Typeface::createSystemTypefaceFor(BinaryData::FiraSansItalic_ttf, BinaryData::FiraSansItalic_ttfSize);
|
||||||
|
|
||||||
void drawLabel(juce::Graphics& g, juce::Label& label) override;
|
void drawLabel(juce::Graphics& g, juce::Label& label) override;
|
||||||
void fillTextEditorBackground(juce::Graphics& g, int width, int height, juce::TextEditor& textEditor) override;
|
void fillTextEditorBackground(juce::Graphics& g, int width, int height, juce::TextEditor& textEditor) override;
|
||||||
|
@ -97,4 +100,7 @@ public:
|
||||||
void drawToggleButton(juce::Graphics&, juce::ToggleButton&, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
|
void drawToggleButton(juce::Graphics&, juce::ToggleButton&, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override;
|
||||||
juce::MouseCursor getMouseCursorFor(juce::Component& component) override;
|
juce::MouseCursor getMouseCursorFor(juce::Component& component) override;
|
||||||
void drawCallOutBoxBackground(juce::CallOutBox& box, juce::Graphics& g, const juce::Path& path, juce::Image& cachedImage) override;
|
void drawCallOutBoxBackground(juce::CallOutBox& box, juce::Graphics& g, const juce::Path& path, juce::Image& cachedImage) override;
|
||||||
|
void drawProgressBar(juce::Graphics& g, juce::ProgressBar& progressBar, int width, int height, double progress, const juce::String& textToShow) override;
|
||||||
|
void customDrawLinearProgressBar(juce::Graphics& g, const juce::ProgressBar& progressBar, int width, int height, double progress, const juce::String& textToShow);
|
||||||
|
juce::Typeface::Ptr getTypefaceForFont(const juce::Font& font) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -131,6 +131,9 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr
|
||||||
}
|
}
|
||||||
|
|
||||||
OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() {
|
OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() {
|
||||||
|
if (audioProcessor.haltRecording != nullptr) {
|
||||||
|
audioProcessor.haltRecording();
|
||||||
|
}
|
||||||
setLookAndFeel(nullptr);
|
setLookAndFeel(nullptr);
|
||||||
juce::Desktop::getInstance().setDefaultLookAndFeel(nullptr);
|
juce::Desktop::getInstance().setDefaultLookAndFeel(nullptr);
|
||||||
juce::MessageManagerLock lock;
|
juce::MessageManagerLock lock;
|
||||||
|
|
|
@ -67,6 +67,9 @@ SosciPluginEditor::SosciPluginEditor(SosciAudioProcessor& p)
|
||||||
}
|
}
|
||||||
|
|
||||||
SosciPluginEditor::~SosciPluginEditor() {
|
SosciPluginEditor::~SosciPluginEditor() {
|
||||||
|
if (audioProcessor.haltRecording != nullptr) {
|
||||||
|
audioProcessor.haltRecording();
|
||||||
|
}
|
||||||
setLookAndFeel(nullptr);
|
setLookAndFeel(nullptr);
|
||||||
juce::Desktop::getInstance().setDefaultLookAndFeel(nullptr);
|
juce::Desktop::getInstance().setDefaultLookAndFeel(nullptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include "DownloaderComponent.h"
|
#include "DownloaderComponent.h"
|
||||||
|
|
||||||
DownloaderComponent::DownloaderComponent(juce::URL url, juce::File file, juce::String title, juce::Component* parent) : juce::ThreadWithProgressWindow(title, true, true, 1000, juce::String(), parent), url(url), file(file) {
|
DownloaderComponent::DownloaderComponent(juce::URL url, juce::File file) : juce::Thread("DownloaderComponent"), url(url), file(file) {
|
||||||
|
addChildComponent(progressBar);
|
||||||
|
addChildComponent(successLabel);
|
||||||
|
|
||||||
|
successLabel.setText(file.getFileName() + " downloaded!", juce::dontSendNotification);
|
||||||
|
|
||||||
if (url.toString(false).endsWithIgnoreCase(".gz")) {
|
if (url.toString(false).endsWithIgnoreCase(".gz")) {
|
||||||
uncompressOnFinish = true;
|
uncompressOnFinish = true;
|
||||||
this->file = file.getSiblingFile(file.getFileName() + ".gz");
|
this->file = file.getSiblingFile(file.getFileName() + ".gz");
|
||||||
|
@ -15,26 +20,52 @@ void DownloaderComponent::run() {
|
||||||
juce::CriticalSection::ScopedTryLockType lock(taskLock);
|
juce::CriticalSection::ScopedTryLockType lock(taskLock);
|
||||||
if (lock.isLocked() && task != nullptr) {
|
if (lock.isLocked() && task != nullptr) {
|
||||||
if (task->isFinished()) {
|
if (task->isFinished()) {
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wait(100);
|
wait(100);
|
||||||
}
|
}
|
||||||
|
threadComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloaderComponent::threadComplete(bool userPressedCancel) {
|
void DownloaderComponent::threadComplete() {
|
||||||
if (!userPressedCancel && uncompressOnFinish && task->isFinished() && !task->hadError()) {
|
bool error = task->hadError();
|
||||||
|
if (uncompressOnFinish && task->isFinished() && !error) {
|
||||||
juce::FileInputStream input(file);
|
juce::FileInputStream input(file);
|
||||||
juce::GZIPDecompressorInputStream decompressedInput(&input, false, juce::GZIPDecompressorInputStream::gzipFormat);
|
juce::GZIPDecompressorInputStream decompressedInput(&input, false, juce::GZIPDecompressorInputStream::gzipFormat);
|
||||||
juce::File uncompressedFile = file.getSiblingFile(file.getFileNameWithoutExtension());
|
juce::File uncompressedFile = file.getSiblingFile(file.getFileNameWithoutExtension());
|
||||||
juce::FileOutputStream output(uncompressedFile);
|
juce::FileOutputStream output(uncompressedFile);
|
||||||
if (output.writeFromInputStream(decompressedInput, -1) < 1) {
|
if (output.writeFromInputStream(decompressedInput, -1) < 1) {
|
||||||
uncompressedFile.deleteFile();
|
uncompressedFile.deleteFile();
|
||||||
|
error = true;
|
||||||
} else {
|
} else {
|
||||||
uncompressedFile.setExecutePermission(true);
|
uncompressedFile.setExecutePermission(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
file.deleteFile();
|
||||||
|
progressValue = -2;
|
||||||
|
} else {
|
||||||
|
progressValue = 1;
|
||||||
|
if (onSuccessfulDownload != nullptr) {
|
||||||
|
onSuccessfulDownload();
|
||||||
|
}
|
||||||
|
juce::MessageManager::callAsync([this]() {
|
||||||
|
progressBar.setVisible(false);
|
||||||
|
successLabel.setVisible(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
juce::Timer::callAfterDelay(3000, [this]() {
|
||||||
|
successLabel.setVisible(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DownloaderComponent::resized() {
|
||||||
|
progressBar.setBounds(getLocalBounds());
|
||||||
|
successLabel.setBounds(getLocalBounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloaderComponent::finished(juce::URL::DownloadTask* task, bool success) {
|
void DownloaderComponent::finished(juce::URL::DownloadTask* task, bool success) {
|
||||||
|
@ -42,9 +73,16 @@ void DownloaderComponent::finished(juce::URL::DownloadTask* task, bool success)
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloaderComponent::progress(juce::URL::DownloadTask* task, juce::int64 bytesDownloaded, juce::int64 totalLength) {
|
void DownloaderComponent::progress(juce::URL::DownloadTask* task, juce::int64 bytesDownloaded, juce::int64 totalLength) {
|
||||||
setProgress((float)bytesDownloaded / (float)totalLength);
|
if (uncompressOnFinish) {
|
||||||
|
progressValue = ((double) bytesDownloaded / (double) totalLength) * 0.9;
|
||||||
|
} else {
|
||||||
|
progressValue = (double) bytesDownloaded / (double) totalLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloaderComponent::download() {
|
void DownloaderComponent::download() {
|
||||||
launchThread();
|
progressValue = -1;
|
||||||
|
successLabel.setVisible(false);
|
||||||
|
progressBar.setVisible(true);
|
||||||
|
startThread();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,20 +19,26 @@ private:
|
||||||
std::unique_ptr<juce::URL::DownloadTask>& task;
|
std::unique_ptr<juce::URL::DownloadTask>& task;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DownloaderComponent : public juce::ThreadWithProgressWindow, public juce::URL::DownloadTaskListener {
|
class DownloaderComponent : public juce::Component, public juce::Thread, public juce::URL::DownloadTaskListener {
|
||||||
public:
|
public:
|
||||||
DownloaderComponent(juce::URL url, juce::File file, juce::String title, juce::Component* parent);
|
DownloaderComponent(juce::URL url, juce::File file);
|
||||||
|
|
||||||
void download();
|
void download();
|
||||||
void run() override;
|
void run() override;
|
||||||
void threadComplete(bool userPressedCancel) override;
|
void threadComplete();
|
||||||
|
void resized() override;
|
||||||
void finished(juce::URL::DownloadTask* task, bool success) override;
|
void finished(juce::URL::DownloadTask* task, bool success) override;
|
||||||
void progress(juce::URL::DownloadTask* task, juce::int64 bytesDownloaded, juce::int64 totalLength) override;
|
void progress(juce::URL::DownloadTask* task, juce::int64 bytesDownloaded, juce::int64 totalLength) override;
|
||||||
|
|
||||||
|
std::function<void()> onSuccessfulDownload;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
juce::URL url;
|
juce::URL url;
|
||||||
juce::File file;
|
juce::File file;
|
||||||
|
double progressValue = -1;
|
||||||
|
juce::ProgressBar progressBar = juce::ProgressBar(progressValue);
|
||||||
|
juce::Label successLabel;
|
||||||
juce::CriticalSection taskLock;
|
juce::CriticalSection taskLock;
|
||||||
std::unique_ptr<juce::URL::DownloadTask> task;
|
std::unique_ptr<juce::URL::DownloadTask> task;
|
||||||
std::unique_ptr<DownloaderThread> downloader;
|
std::unique_ptr<DownloaderThread> downloader;
|
||||||
|
|
|
@ -9,6 +9,7 @@ AudioBackgroundThread::AudioBackgroundThread(const juce::String& name, AudioBack
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioBackgroundThread::~AudioBackgroundThread() {
|
AudioBackgroundThread::~AudioBackgroundThread() {
|
||||||
|
deleting = true;
|
||||||
setShouldBeRunning(false);
|
setShouldBeRunning(false);
|
||||||
manager.unregisterThread(this);
|
manager.unregisterThread(this);
|
||||||
}
|
}
|
||||||
|
@ -69,7 +70,9 @@ void AudioBackgroundThread::start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioBackgroundThread::stop() {
|
void AudioBackgroundThread::stop() {
|
||||||
stopTask();
|
if (!deleting) {
|
||||||
|
stopTask();
|
||||||
|
}
|
||||||
consumer->forceNotify();
|
consumer->forceNotify();
|
||||||
stopThread(1000);
|
stopThread(1000);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ private:
|
||||||
std::unique_ptr<BufferConsumer> consumer = nullptr;
|
std::unique_ptr<BufferConsumer> consumer = nullptr;
|
||||||
bool shouldBeRunning = false;
|
bool shouldBeRunning = false;
|
||||||
std::atomic<bool> isPrepared = false;
|
std::atomic<bool> isPrepared = false;
|
||||||
|
std::atomic<bool> deleting = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,13 @@
|
||||||
#include "TexturedVertexShader.glsl"
|
#include "TexturedVertexShader.glsl"
|
||||||
|
|
||||||
VisualiserComponent::VisualiserComponent(juce::File ffmpegFile, std::function<void()>& haltRecording, AudioBackgroundThreadManager& threadManager, VisualiserSettings& settings, VisualiserComponent* parent, bool visualiserOnly) : ffmpegFile(ffmpegFile), haltRecording(haltRecording), settings(settings), threadManager(threadManager), visualiserOnly(visualiserOnly), AudioBackgroundThread("VisualiserComponent" + juce::String(parent != nullptr ? " Child" : ""), threadManager), parent(parent) {
|
VisualiserComponent::VisualiserComponent(juce::File ffmpegFile, std::function<void()>& haltRecording, AudioBackgroundThreadManager& threadManager, VisualiserSettings& settings, VisualiserComponent* parent, bool visualiserOnly) : ffmpegFile(ffmpegFile), haltRecording(haltRecording), settings(settings), threadManager(threadManager), visualiserOnly(visualiserOnly), AudioBackgroundThread("VisualiserComponent" + juce::String(parent != nullptr ? " Child" : ""), threadManager), parent(parent) {
|
||||||
|
addAndMakeVisible(ffmpegDownloader);
|
||||||
|
|
||||||
|
ffmpegDownloader.onSuccessfulDownload = [this] {
|
||||||
|
juce::MessageManager::callAsync([this] {
|
||||||
|
record.setEnabled(true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
haltRecording = [this] {
|
haltRecording = [this] {
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
|
@ -21,14 +28,6 @@ VisualiserComponent::VisualiserComponent(juce::File ffmpegFile, std::function<vo
|
||||||
record.setPulseAnimation(true);
|
record.setPulseAnimation(true);
|
||||||
record.onClick = [this] {
|
record.onClick = [this] {
|
||||||
setRecording(record.getToggleState());
|
setRecording(record.getToggleState());
|
||||||
stopwatch.stop();
|
|
||||||
stopwatch.reset();
|
|
||||||
|
|
||||||
if (record.getToggleState()) {
|
|
||||||
stopwatch.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
resized();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
addAndMakeVisible(stopwatch);
|
addAndMakeVisible(stopwatch);
|
||||||
|
@ -169,10 +168,27 @@ bool VisualiserComponent::keyPressed(const juce::KeyPress& key) {
|
||||||
void VisualiserComponent::setFullScreen(bool fullScreen) {}
|
void VisualiserComponent::setFullScreen(bool fullScreen) {}
|
||||||
|
|
||||||
void VisualiserComponent::setRecording(bool recording) {
|
void VisualiserComponent::setRecording(bool recording) {
|
||||||
|
stopwatch.stop();
|
||||||
|
stopwatch.reset();
|
||||||
|
|
||||||
if (recording) {
|
if (recording) {
|
||||||
if (!ffmpegFile.exists()) {
|
if (!ffmpegFile.exists()) {
|
||||||
ffmpegDownloader.download();
|
// ask the user if they want to download ffmpeg
|
||||||
record.setToggleState(false, juce::NotificationType::sendNotification);
|
juce::MessageBoxOptions options = juce::MessageBoxOptions()
|
||||||
|
.withTitle("FFmpeg not found")
|
||||||
|
.withMessage("FFmpeg not found. This is required to record video to .mp4.\n\nWould you like to download it now?")
|
||||||
|
.withButton("Yes")
|
||||||
|
.withButton("No")
|
||||||
|
.withIconType(juce::AlertWindow::WarningIcon)
|
||||||
|
.withAssociatedComponent(this);
|
||||||
|
|
||||||
|
juce::AlertWindow::showAsync(options, [this](int result) {
|
||||||
|
if (result == 1) {
|
||||||
|
record.setEnabled(false);
|
||||||
|
ffmpegDownloader.download();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
record.setToggleState(false, juce::NotificationType::dontSendNotification);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
juce::TemporaryFile tempFile = juce::TemporaryFile(".mp4");
|
juce::TemporaryFile tempFile = juce::TemporaryFile(".mp4");
|
||||||
|
@ -191,6 +207,7 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
}
|
}
|
||||||
framePixels.resize(renderTexture.width * renderTexture.height * 4);
|
framePixels.resize(renderTexture.width * renderTexture.height * 4);
|
||||||
setPaused(false);
|
setPaused(false);
|
||||||
|
stopwatch.start();
|
||||||
} else if (ffmpeg != nullptr) {
|
} else if (ffmpeg != nullptr) {
|
||||||
#if JUCE_WINDOWS
|
#if JUCE_WINDOWS
|
||||||
_pclose(ffmpeg);
|
_pclose(ffmpeg);
|
||||||
|
@ -202,6 +219,7 @@ void VisualiserComponent::setRecording(bool recording) {
|
||||||
setBlockOnAudioThread(recording);
|
setBlockOnAudioThread(recording);
|
||||||
numFrames = 0;
|
numFrames = 0;
|
||||||
record.setToggleState(recording, juce::NotificationType::dontSendNotification);
|
record.setToggleState(recording, juce::NotificationType::dontSendNotification);
|
||||||
|
resized();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualiserComponent::resized() {
|
void VisualiserComponent::resized() {
|
||||||
|
@ -221,13 +239,16 @@ void VisualiserComponent::resized() {
|
||||||
} else {
|
} else {
|
||||||
stopwatch.setVisible(false);
|
stopwatch.setVisible(false);
|
||||||
}
|
}
|
||||||
|
if (child == nullptr) {
|
||||||
|
auto bounds = buttonRow.removeFromRight(160);
|
||||||
|
ffmpegDownloader.setBounds(bounds.withSizeKeepingCentre(bounds.getWidth() - 10, bounds.getHeight() - 10));
|
||||||
|
}
|
||||||
viewportArea = area;
|
viewportArea = area;
|
||||||
viewportChanged(viewportArea);
|
viewportChanged(viewportArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualiserComponent::popoutWindow() {
|
void VisualiserComponent::popoutWindow() {
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
record.setEnabled(false);
|
|
||||||
auto visualiser = new VisualiserComponent(ffmpegFile, haltRecording, threadManager, settings, this);
|
auto visualiser = new VisualiserComponent(ffmpegFile, haltRecording, threadManager, settings, this);
|
||||||
visualiser->settings.setLookAndFeel(&getLookAndFeel());
|
visualiser->settings.setLookAndFeel(&getLookAndFeel());
|
||||||
visualiser->openSettings = openSettings;
|
visualiser->openSettings = openSettings;
|
||||||
|
@ -247,7 +268,8 @@ void VisualiserComponent::popoutWindow() {
|
||||||
|
|
||||||
void VisualiserComponent::childUpdated() {
|
void VisualiserComponent::childUpdated() {
|
||||||
popOutButton.setVisible(child == nullptr);
|
popOutButton.setVisible(child == nullptr);
|
||||||
record.setEnabled(child == nullptr);
|
ffmpegDownloader.setVisible(child == nullptr);
|
||||||
|
record.setVisible(child == nullptr);
|
||||||
if (child != nullptr) {
|
if (child != nullptr) {
|
||||||
haltRecording = [this] {
|
haltRecording = [this] {
|
||||||
setRecording(false);
|
setRecording(false);
|
||||||
|
@ -826,6 +848,10 @@ void VisualiserComponent::paint(juce::Graphics& g) {
|
||||||
g.setColour(juce::Colours::black);
|
g.setColour(juce::Colours::black);
|
||||||
g.fillRect(buttonRow);
|
g.fillRect(buttonRow);
|
||||||
if (!active) {
|
if (!active) {
|
||||||
|
// draw a translucent overlay
|
||||||
|
g.setColour(juce::Colours::black.withAlpha(0.5f));
|
||||||
|
g.fillRect(viewportArea);
|
||||||
|
|
||||||
g.setColour(juce::Colours::white);
|
g.setColour(juce::Colours::white);
|
||||||
g.setFont(30.0f);
|
g.setFont(30.0f);
|
||||||
juce::String text = child == nullptr ? "Paused" : "Open in another window";
|
juce::String text = child == nullptr ? "Paused" : "Open in another window";
|
||||||
|
|
|
@ -112,7 +112,7 @@ private:
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
+ ".gz";
|
+ ".gz";
|
||||||
DownloaderComponent ffmpegDownloader{ffmpegURL, ffmpegFile, "Downloading ffmpeg...", this};
|
DownloaderComponent ffmpegDownloader{ffmpegURL, ffmpegFile};
|
||||||
|
|
||||||
Semaphore renderingSemaphore{0};
|
Semaphore renderingSemaphore{0};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,12 @@
|
||||||
<MAINGROUP id="j5Ge2T" name="osci-render">
|
<MAINGROUP id="j5Ge2T" name="osci-render">
|
||||||
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
|
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
|
||||||
<GROUP id="{8930EC48-30FD-646B-9DC5-0861171F8B2E}" name="fonts">
|
<GROUP id="{8930EC48-30FD-646B-9DC5-0861171F8B2E}" name="fonts">
|
||||||
<FILE id="sqtSiu" name="font.ttf" compile="0" resource="1" file="Resources/fonts/font.ttf"/>
|
<FILE id="GXGPCT" name="FiraSans-Bold.ttf" compile="0" resource="1"
|
||||||
|
file="Resources/fonts/FiraSans-Bold.ttf"/>
|
||||||
|
<FILE id="TvdkVI" name="FiraSans-Italic.ttf" compile="0" resource="1"
|
||||||
|
file="Resources/fonts/FiraSans-Italic.ttf"/>
|
||||||
|
<FILE id="uStS0H" name="FiraSans-Regular.ttf" compile="0" resource="1"
|
||||||
|
file="Resources/fonts/FiraSans-Regular.ttf"/>
|
||||||
</GROUP>
|
</GROUP>
|
||||||
<GROUP id="{F3815953-00C0-3876-5552-BDE98F3233D9}" name="gpla">
|
<GROUP id="{F3815953-00C0-3876-5552-BDE98F3233D9}" name="gpla">
|
||||||
<FILE id="euGQq0" name="fallback.gpla" compile="0" resource="1" file="Resources/gpla/fallback.gpla"/>
|
<FILE id="euGQq0" name="fallback.gpla" compile="0" resource="1" file="Resources/gpla/fallback.gpla"/>
|
||||||
|
@ -137,6 +142,10 @@
|
||||||
file="Source/components/ComponentList.cpp"/>
|
file="Source/components/ComponentList.cpp"/>
|
||||||
<FILE id="HGTPEW" name="ComponentList.h" compile="0" resource="0" file="Source/components/ComponentList.h"/>
|
<FILE id="HGTPEW" name="ComponentList.h" compile="0" resource="0" file="Source/components/ComponentList.h"/>
|
||||||
<FILE id="IvySRY" name="DoubleTextBox.h" compile="0" resource="0" file="Source/components/DoubleTextBox.h"/>
|
<FILE id="IvySRY" name="DoubleTextBox.h" compile="0" resource="0" file="Source/components/DoubleTextBox.h"/>
|
||||||
|
<FILE id="Jh9JQ3" name="DownloaderComponent.cpp" compile="1" resource="0"
|
||||||
|
file="Source/components/DownloaderComponent.cpp"/>
|
||||||
|
<FILE id="rCLnwK" name="DownloaderComponent.h" compile="0" resource="0"
|
||||||
|
file="Source/components/DownloaderComponent.h"/>
|
||||||
<FILE id="poPVxL" name="DraggableListBox.cpp" compile="1" resource="0"
|
<FILE id="poPVxL" name="DraggableListBox.cpp" compile="1" resource="0"
|
||||||
file="Source/components/DraggableListBox.cpp"/>
|
file="Source/components/DraggableListBox.cpp"/>
|
||||||
<FILE id="Y9NEGn" name="DraggableListBox.h" compile="0" resource="0"
|
<FILE id="Y9NEGn" name="DraggableListBox.h" compile="0" resource="0"
|
||||||
|
|
|
@ -10,7 +10,12 @@
|
||||||
<MAINGROUP id="j5Ge2T" name="sosci">
|
<MAINGROUP id="j5Ge2T" name="sosci">
|
||||||
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
|
<GROUP id="{5ABCED88-0059-A7AF-9596-DBF91DDB0292}" name="Resources">
|
||||||
<GROUP id="{1C0FC3AA-01F6-8768-381C-200ED18AB5F2}" name="fonts">
|
<GROUP id="{1C0FC3AA-01F6-8768-381C-200ED18AB5F2}" name="fonts">
|
||||||
<FILE id="sQn22Z" name="font.ttf" compile="0" resource="1" file="Resources/fonts/font.ttf"/>
|
<FILE id="R0Gs1t" name="FiraSans-Bold.ttf" compile="0" resource="1"
|
||||||
|
file="Resources/fonts/FiraSans-Bold.ttf"/>
|
||||||
|
<FILE id="IueZb0" name="FiraSans-Italic.ttf" compile="0" resource="1"
|
||||||
|
file="Resources/fonts/FiraSans-Italic.ttf"/>
|
||||||
|
<FILE id="arLp4R" name="FiraSans-Regular.ttf" compile="0" resource="1"
|
||||||
|
file="Resources/fonts/FiraSans-Regular.ttf"/>
|
||||||
</GROUP>
|
</GROUP>
|
||||||
<GROUP id="{525C568C-29E9-D0A2-9773-8A04981C5575}" name="images">
|
<GROUP id="{525C568C-29E9-D0A2-9773-8A04981C5575}" name="images">
|
||||||
<FILE id="jI9VSZ" name="logo.png" compile="0" resource="1" file="Resources/images/logo.png"/>
|
<FILE id="jI9VSZ" name="logo.png" compile="0" resource="1" file="Resources/images/logo.png"/>
|
||||||
|
|
Ładowanie…
Reference in New Issue