Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add wasm builds; requires emsdk path #1928

Merged
merged 14 commits into from
Jan 25, 2025
53 changes: 52 additions & 1 deletion Source/Components/PropertiesPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -1097,12 +1097,63 @@ class PropertiesPanel : public Component {

void resized() override
{
auto labelBounds = getLocalBounds().removeFromRight(getWidth() / (2 - hideLabel));
auto labelBounds = getLocalBounds().removeFromRight(getWidth() / 2);
label.setBounds(labelBounds);
browseButton.setBounds(labelBounds.removeFromRight(getHeight()));
}
};

struct DirectoryPathComponent final : public PropertiesPanelProperty {
Label label;
SmallIconButton browseButton = SmallIconButton(Icons::Folder);
Value property;

DirectoryPathComponent(String const& propertyName, Value& value)
: PropertiesPanelProperty(propertyName)
, property(value)
{
label.setEditable(true, false);
label.getTextValue().referTo(property);
label.addMouseListener(this, true);
label.setFont(Font(14));
label.attachToComponent(&browseButton, true);

addAndMakeVisible(label);
addAndMakeVisible(browseButton);

browseButton.onClick = [this] {
Dialogs::showOpenDialog([this](URL const& url) {
auto const result = url.getLocalFile();
if (result.exists()) {
label.setText(result.getFullPathName(), sendNotification);
}
},
false, true, "", "", getTopLevelComponent());
};
}

PropertiesPanelProperty* createCopy() override
{
return new DirectoryPathComponent(getName(), property);
}

void paint(Graphics& g) override
{
PropertiesPanelProperty::paint(g);

g.setColour(findColour(PlugDataColour::panelBackgroundColourId));
g.fillRect(getLocalBounds().removeFromRight(getHeight()));
}

void resized() override
{
auto labelBounds = getLocalBounds().removeFromRight(getWidth() / 2);
label.setBounds(labelBounds);
browseButton.setBounds(labelBounds.removeFromRight(getHeight()));
}
};


class ActionComponent final : public PropertiesPanelProperty {

bool mouseIsOver = false;
Expand Down
10 changes: 8 additions & 2 deletions Source/Dialogs/Dialogs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,10 +834,16 @@ void Dialogs::showOpenDialog(std::function<void(URL)> const& callback, bool cons
if (!initialFile.exists())
initialFile = ProjectInfo::appDataDir;

auto fileChooserText = "Choose file to open...";

if (!canSelectFiles && canSelectDirectories) {
fileChooserText = "Select directory...";
}

#if JUCE_IOS
fileChooser = std::make_unique<FileChooser>("Choose file to open...", initialFile, "*", nativeDialog, false, parentComponent);
fileChooser = std::make_unique<FileChooser>(fileChooserText, initialFile, "*", nativeDialog, false, parentComponent);
#else
fileChooser = std::make_unique<FileChooser>("Choose file to open...", initialFile, extension, nativeDialog, false, nullptr);
fileChooser = std::make_unique<FileChooser>(fileChooserText, initialFile, extension, nativeDialog, false, nullptr);
#endif
auto openChooserFlags = FileBrowserComponent::openMode;

Expand Down
6 changes: 5 additions & 1 deletion Source/Heavy/HeavyExportDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "DaisyExporter.h"
#include "OWLExporter.h"
#include "PdExporter.h"
#include "WASMExporter.h"

class ExporterSettingsPanel final : public Component
, private ListBoxModel {
Expand All @@ -41,7 +42,8 @@ class ExporterSettingsPanel final : public Component
"Electro-Smith Daisy",
"DPF Audio Plugin",
"OWL Platform",
"Pd External"
"Pd External",
"WebAssembly"
};

ExporterSettingsPanel(PluginEditor* editor, ExportingProgressView* exportingView)
Expand All @@ -51,6 +53,7 @@ class ExporterSettingsPanel final : public Component
addChildComponent(views.add(new DPFExporter(editor, exportingView)));
addChildComponent(views.add(new OWLExporter(editor, exportingView)));
addChildComponent(views.add(new PdExporter(editor, exportingView)));
addChildComponent(views.add(new WASMExporter(editor, exportingView)));

addAndMakeVisible(listBox);

Expand Down Expand Up @@ -104,6 +107,7 @@ class ExporterSettingsPanel final : public Component
state.appendChild(views[2]->getState(), nullptr);
state.appendChild(views[3]->getState(), nullptr);
state.appendChild(views[4]->getState(), nullptr);
dromer marked this conversation as resolved.
Show resolved Hide resolved
state.appendChild(views[5]->getState(), nullptr);

auto settingsTree = SettingsFile::getInstance()->getValueTree();

Expand Down
111 changes: 111 additions & 0 deletions Source/Heavy/WASMExporter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
// Copyright (c) 2024 Timothy Schoen and Wasted Audio
// For information on usage and redistribution, and for a DISCLAIMER OF ALL
// WARRANTIES, see the file, "LICENSE.txt," in this distribution.
*/

class WASMExporter : public ExporterBase {
public:

Value emsdkPathValue;

WASMExporter(PluginEditor* editor, ExportingProgressView* exportingView)
: ExporterBase(editor, exportingView)
{
PropertiesArray properties;
properties.add(new PropertiesPanel::DirectoryPathComponent("EMSDK path", emsdkPathValue));

for (auto* property : properties) {
property->setPreferredHeight(28);
}

emsdkPathValue.addListener(this);

panel.addSection("WASM", properties);
}

ValueTree getState() override
{
ValueTree stateTree("WASM");

stateTree.setProperty("inputPatchValue", getValue<String>(inputPatchValue), nullptr);
stateTree.setProperty("projectNameValue", getValue<String>(projectNameValue), nullptr);
stateTree.setProperty("projectCopyrightValue", getValue<String>(projectCopyrightValue), nullptr);
stateTree.setProperty("emsdkPathValue", getValue<String>(emsdkPathValue), nullptr);

return stateTree;
}

void setState(ValueTree& stateTree) override
{
auto tree = stateTree.getChildWithName("WASM");
inputPatchValue = tree.getProperty("inputPatchValue");
projectNameValue = tree.getProperty("projectNameValue");
projectCopyrightValue = tree.getProperty("projectCopyrightValue");
emsdkPathValue = tree.getProperty("emsdkPathValue");
}

void valueChanged(Value& v) override
{
ExporterBase::valueChanged(v);

String const emsdkPath = getValue<String>(emsdkPathValue);

if (emsdkPath.isNotEmpty()) {
exportButton.setEnabled(true);
} else {
exportButton.setEnabled(false);
}
}

bool performExport(String pdPatch, String outdir, String name, String copyright, StringArray searchPaths) override
{
exportingView->showState(ExportingProgressView::Exporting);

StringArray args = { heavyExecutable.getFullPathName(), pdPatch, "-o" + outdir };

name = name.replaceCharacter('-', '_');
args.add("-n" + name);

if (copyright.isNotEmpty()) {
args.add("--copyright");
args.add("\"" + copyright + "\"");
}

auto emsdkPath = getValue<String>(emsdkPathValue);

args.add("-v");
args.add("-gjs");

String paths = "-p";
for (auto& path : searchPaths) {
paths += " " + path;
}

args.add(paths);

if (shouldQuit)
return true;

auto buildScript = "source " + emsdkPath + "/emsdk_env.sh; " + args.joinIntoString(" ");

Toolchain::startShellScript(buildScript, this);

waitForProcessToFinish(-1);
exportingView->flushConsole();

if (shouldQuit)
return true;

auto outputFile = File(outdir);
outputFile.getChildFile("c").deleteRecursively();
outputFile.getChildFile("ir").deleteRecursively();
outputFile.getChildFile("hv").deleteRecursively();

// Delay to get correct exit code
Time::waitForMillisecondCounter(Time::getMillisecondCounter() + 300);

bool generationExitCode = getExitCode();
return generationExitCode;
}
};