Flip gionometer and add warning message if opening an obj file that is too large

pull/298/head
James H Ball 2025-04-04 11:28:13 +01:00
rodzic 02095d3a15
commit c205de10b7
8 zmienionych plików z 112 dodań i 11 usunięć

Wyświetl plik

@ -41,9 +41,7 @@ MainComponent::MainComponent(OscirenderAudioProcessor& p, OscirenderAudioProcess
if (index == -1) {
return;
}
pluginEditor.removeCodeEditor(audioProcessor.getCurrentFileIndex());
audioProcessor.removeFile(audioProcessor.getCurrentFileIndex());
pluginEditor.fileUpdated(audioProcessor.getCurrentFileName());
};
closeFileButton.setTooltip("Close the currently open file.");

Wyświetl plik

@ -2,7 +2,20 @@
#include "PluginEditor.h"
#include "CustomStandaloneFilterWindow.h"
void OscirenderAudioProcessorEditor::registerFileRemovedCallback() {
audioProcessor.setFileRemovedCallback([this](int index) {
removeCodeEditor(index);
fileUpdated(audioProcessor.getCurrentFileName());
juce::MessageManager::callAsync([this] {
resized();
});
});
}
OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioProcessor& p) : CommonPluginEditor(p, "osci-render", "osci", 1100, 750), audioProcessor(p), collapseButton("Collapse", juce::Colours::white, juce::Colours::white, juce::Colours::white) {
// Register the file removal callback
registerFileRemovedCallback();
#if !SOSCI_FEATURES
addAndMakeVisible(upgradeButton);
upgradeButton.onClick = [this] {
@ -85,6 +98,9 @@ OscirenderAudioProcessorEditor::OscirenderAudioProcessorEditor(OscirenderAudioPr
}
OscirenderAudioProcessorEditor::~OscirenderAudioProcessorEditor() {
// Clear the file removal callback
audioProcessor.setFileRemovedCallback(nullptr);
menuBar.setModel(nullptr);
juce::MessageManagerLock lock;
audioProcessor.broadcaster.removeChangeListener(this);

Wyświetl plik

@ -34,6 +34,8 @@ public:
void editCustomFunction(bool enabled);
private:
void registerFileRemovedCallback();
OscirenderAudioProcessor& audioProcessor;
public:

Wyświetl plik

@ -293,6 +293,11 @@ void OscirenderAudioProcessor::addFile(juce::String fileName, std::shared_ptr<ju
openFile(fileBlocks.size() - 1);
}
// Setter for the callback
void OscirenderAudioProcessor::setFileRemovedCallback(std::function<void(int)> callback) {
fileRemovedCallback = std::move(callback);
}
// parsersLock AND effectsLock must be locked before calling this function
void OscirenderAudioProcessor::removeFile(int index) {
if (index < 0 || index >= fileBlocks.size()) {
@ -303,11 +308,32 @@ void OscirenderAudioProcessor::removeFile(int index) {
fileIds.erase(fileIds.begin() + index);
parsers.erase(parsers.begin() + index);
sounds.erase(sounds.begin() + index);
auto newFileIndex = index;
if (newFileIndex >= fileBlocks.size()) {
newFileIndex = fileBlocks.size() - 1;
}
changeCurrentFile(newFileIndex);
// Notify the editor about the file removal
if (fileRemovedCallback) {
fileRemovedCallback(index);
}
}
// parsersLock AND effectsLock must be locked before calling this function
void OscirenderAudioProcessor::removeParser(FileParser* parser) {
int parserIndex = -1;
for (int i = 0; i < parsers.size(); i++) {
if (parsers[i].get() == parser) {
parserIndex = i;
break;
}
}
if (parserIndex >= 0) {
removeFile(parserIndex);
}
}
int OscirenderAudioProcessor::numFiles() {
@ -321,7 +347,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).toLowerCase(), std::make_unique<juce::MemoryInputStream>(*fileBlocks[index], false), font);
parsers[index]->parse(juce::String(fileIds[index]), fileNames[index], fileNames[index].fromLastOccurrenceOf(".", true, false).toLowerCase(), std::make_unique<juce::MemoryInputStream>(*fileBlocks[index], false), font);
changeCurrentFile(index);
}

Wyświetl plik

@ -184,6 +184,9 @@ public:
std::function<void()> haltRecording;
// Add a callback to notify the editor when a file is removed
std::function<void(int)> fileRemovedCallback;
void addLuaSlider();
void updateEffectPrecedence();
void updateFileBlock(int index, std::shared_ptr<juce::MemoryBlock> block);
@ -205,6 +208,13 @@ public:
void addErrorListener(ErrorListener* listener);
void removeErrorListener(ErrorListener* listener);
void notifyErrorListeners(int lineNumber, juce::String id, juce::String error);
// Setter for the callback
void setFileRemovedCallback(std::function<void(int)> callback);
// Added declaration for the new `removeParser` method.
void removeParser(FileParser* parser);
private:
std::atomic<bool> prevMidiEnabled = !midiEnabled->getBoolValue();

Wyświetl plik

@ -4,9 +4,10 @@
#include <numbers>
#include "../PluginProcessor.h"
FileParser::FileParser(OscirenderAudioProcessor &p, std::function<void(int, juce::String, juce::String)> errorCallback) : errorCallback(errorCallback), audioProcessor(p) {}
FileParser::FileParser(OscirenderAudioProcessor &p, std::function<void(int, juce::String, juce::String)> errorCallback)
: errorCallback(errorCallback), audioProcessor(p) {}
void FileParser::parse(juce::String fileId, juce::String extension, std::unique_ptr<juce::InputStream> stream, juce::Font font) {
void FileParser::parse(juce::String fileId, juce::String fileName, juce::String extension, std::unique_ptr<juce::InputStream> stream, juce::Font font) {
juce::SpinLock::ScopedLockType scope(lock);
if (extension == ".lua" && lua != nullptr && lua->isFunctionValid()) {
@ -22,7 +23,54 @@ void FileParser::parse(juce::String fileId, juce::String extension, std::unique_
wav = nullptr;
if (extension == ".obj") {
object = std::make_shared<WorldObject>(stream->readEntireStreamAsString().toStdString());
// Check file size before parsing
const int64_t fileSize = stream->getTotalLength();
const int64_t oneMB = 1024 * 1024; // 1MB in bytes
// Save the file content to avoid losing it after the async operation
juce::String objContent = stream->readEntireStreamAsString();
if (fileSize > oneMB) {
// For large files, show an async warning dialog
const double fileSizeMB = fileSize / (1024.0 * 1024.0);
juce::MessageManager::callAsync([this, objContent, fileSizeMB, fileName]() {
juce::String message = juce::String::formatted(
"The OBJ file '%s' you're trying to open is %.2f MB in size, which may cause performance issues. "
"Would you like to continue loading it?", fileName.toRawUTF8(), fileSizeMB);
// Show async dialog with callbacks for user response
juce::AlertWindow::showOkCancelBox(
juce::AlertWindow::WarningIcon,
"Large OBJ File",
message,
"Continue",
"Cancel",
nullptr,
juce::ModalCallbackFunction::create([this, objContent](int result) {
if (result == 1) { // 1 = OK button pressed
juce::SpinLock::ScopedLockType scope(lock);
// User chose to continue, load the file
object = std::make_shared<WorldObject>(objContent.toStdString());
} else {
// User canceled, fully close this file parser
juce::SpinLock::ScopedLockType scope(lock);
disable(); // Mark this parser as inactive
// Notify the processor to remove this parser
juce::MessageManager::callAsync([this] {
juce::SpinLock::ScopedLockType lock1(audioProcessor.parsersLock);
juce::SpinLock::ScopedLockType lock2(audioProcessor.effectsLock);
audioProcessor.removeParser(this);
});
}
})
);
});
} else {
// For small files, load immediately
object = std::make_shared<WorldObject>(objContent.toStdString());
}
} else if (extension == ".svg") {
svg = std::make_shared<SvgParser>(stream->readEntireStreamAsString());
} else if (extension == ".txt") {
@ -52,8 +100,10 @@ void FileParser::parse(juce::String fileId, juce::String extension, std::unique_
} else if (extension == ".wav" || extension == ".aiff" || extension == ".flac" || extension == ".ogg" || extension == ".mp3") {
wav = std::make_shared<WavParser>(audioProcessor);
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.");
juce::MessageManager::callAsync([this, fileName] {
juce::AlertWindow::showMessageBoxAsync(juce::AlertWindow::AlertIconType::WarningIcon,
"Error Loading " + fileName,
"The audio file '" + fileName + "' could not be loaded.");
});
}
}

Wyświetl plik

@ -15,7 +15,7 @@ class FileParser {
public:
FileParser(OscirenderAudioProcessor &p, std::function<void(int, juce::String, juce::String)> errorCallback = nullptr);
void parse(juce::String fileName, juce::String extension, std::unique_ptr<juce::InputStream> stream, juce::Font font);
void parse(juce::String fileId, juce::String fileName, juce::String extension, std::unique_ptr<juce::InputStream> stream, juce::Font font);
std::vector<std::unique_ptr<Shape>> nextFrame();
OsciPoint nextSample(lua_State*& L, LuaVariables& vars);
void closeLua(lua_State*& L);
@ -39,7 +39,6 @@ private:
bool active = true;
bool sampleSource = false;
juce::SpinLock lock;
std::shared_ptr<WorldObject> object;

Wyświetl plik

@ -243,7 +243,7 @@ void VisualiserComponent::runTask(const std::vector<OsciPoint>& points) {
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);
point.rotate(0, 0, -juce::MathConstants<double>::pi / 4);
}
#endif