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

WrapUp the Features of the Tuning Editor #5241

Merged
merged 2 commits into from
Oct 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/surge-xt/gui/SurgeGUIEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2838,10 +2838,6 @@ juce::PopupMenu SurgeGUIEditor::makeTuningMenu(const juce::Point<int> &where, bo

tuningSubMenu.addSeparator();

tuningSubMenu.addItem(Surge::GUI::toOSCaseForMenu("Show Current Tuning Information..."),
(!this->synth->storage.isStandardTuning), false,
[this]() { showHTML(this->tuningToHtml()); });

tuningSubMenu.addItem(Surge::GUI::toOSCaseForMenu("Factory Tuning Library..."), [this]() {
auto path = this->synth->storage.datapath / "tuning_library";
Surge::GUI::openFileOrFolder(path);
Expand Down
2 changes: 1 addition & 1 deletion src/surge-xt/gui/SurgeGUIEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,11 +603,11 @@ class SurgeGUIEditor : public Surge::GUI::IComponentTagValue::Listener,

public:
bool useDevMenu = false;
SurgeSynthEditor *juceEditor{nullptr};

private:
float blinktimer = 0;
bool blinkstate = false;
SurgeSynthEditor *juceEditor{nullptr};
int firstIdleCountdown = 0;

juce::PopupMenu makeSmoothMenu(const juce::Point<int> &where,
Expand Down
1 change: 1 addition & 0 deletions src/surge-xt/gui/SurgeGUIEditorOverlays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ std::unique_ptr<Surge::Overlays::OverlayComponent> SurgeGUIEditor::createOverlay

auto pt = std::make_unique<Surge::Overlays::TuningOverlay>();
pt->setStorage(&(this->synth->storage));
pt->setEditor(this);
pt->setSkin(currentSkin, bitmapStore);
pt->setTuning(synth->storage.currentTuning);
pt->setEnclosingParentPosition(juce::Rectangle<int>(px, py, w, h));
Expand Down
1 change: 1 addition & 0 deletions src/surge-xt/gui/overlays/OverlayComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct OverlayComponent : juce::Component
bool canTearOut{false};
void setCanTearOut(bool b) { canTearOut = b; }
bool getCanTearOut() { return canTearOut; }
virtual void onTearOutChanged(bool isTornOut) {}

std::pair<bool, Surge::Storage::DefaultKey> canMoveAround{false, Surge::Storage::nKeys};
void setCanMoveAround(std::pair<bool, Surge::Storage::DefaultKey> b) { canMoveAround = b; }
Expand Down
6 changes: 6 additions & 0 deletions src/surge-xt/gui/overlays/OverlayWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ void OverlayWrapper::doTearOut(const juce::Point<int> &showAt)
if (auto oc = dynamic_cast<Surge::Overlays::OverlayComponent *>(primaryChild.get()))
{
t = oc->getEnclosingParentTitle();
oc->onTearOutChanged(true);
}
auto dw = std::make_unique<TearOutWindow>(t, juce::DocumentWindow::closeButton |
juce::DocumentWindow::minimiseButton);
Expand Down Expand Up @@ -219,6 +220,11 @@ void OverlayWrapper::doTearIn()
setBounds(locationBeforeTearOut);
parentBeforeTearOut->addAndMakeVisible(*this);
parentBeforeTearOut = nullptr;

if (auto oc = dynamic_cast<Surge::Overlays::OverlayComponent *>(primaryChild.get()))
{
oc->onTearOutChanged(false);
}
}

void OverlayWrapper::mouseDown(const juce::MouseEvent &e)
Expand Down
167 changes: 157 additions & 10 deletions src/surge-xt/gui/overlays/TuningOverlays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "SurgeStorage.h"
#include "UserDefaults.h"
#include "SurgeGUIUtils.h"
#include "SurgeGUIEditor.h"
#include "SurgeSynthEditor.h" // bit gross but so I can do DnD
#include "fmt/core.h"
#include <chrono>

Expand Down Expand Up @@ -226,25 +228,67 @@ class TuningTableListBoxModel : public juce::TableListBoxModel,

class RadialScaleGraph;

class RadialScaleGraph : public juce::Component
class RadialScaleGraph : public juce::Component, juce::TextEditor::Listener
{
public:
RadialScaleGraph()
{
toneList = std::make_unique<juce::Viewport>();
toneInterior = std::make_unique<juce::Component>();
toneList->setViewedComponent(toneInterior.get(), false);
addAndMakeVisible(*toneList);

setTuning(Tunings::Tuning(Tunings::evenTemperament12NoteScale(), Tunings::tuneA69To(440)));
}

void setTuning(const Tunings::Tuning &t)
{
int priorLen = tuning.scale.count;
tuning = t;
scale = t.scale;

if (toneEditors.empty() || priorLen != scale.count || toneEditors.size() != scale.count + 1)
{
toneInterior->removeAllChildren();
auto w = usedForSidebar - 15;
auto m = 2;
auto h = 24;
toneInterior->setSize(w, (scale.count + 1) * (h + m));
toneEditors.clear();
for (int i = 0; i < scale.count + 1; ++i)
{
auto te = std::make_unique<juce::TextEditor>("tone");
te->setText(std::to_string(i), juce::NotificationType::dontSendNotification);
te->setBounds(m, i * (h + m) + m, w - 2 * m, h);
te->setEnabled(i != 0);
te->addListener(this);
toneInterior->addAndMakeVisible(*te);
toneEditors.push_back(std::move(te));
}
}

toneEditors[0]->setText("-", juce::NotificationType::dontSendNotification);
for (int i = 0; i < scale.count; ++i)
{
auto td = fmt::format("{:.5f}", scale.tones[i].cents);
if (scale.tones[i].type == Tunings::Tone::kToneRatio)
{
td = fmt::format("{:d}/{:d}", scale.tones[i].ratio_n, scale.tones[i].ratio_d);
}
toneEditors[i + 1]->setText(td, juce::NotificationType::dontSendNotification);
}

notesOn.clear();
notesOn.resize(scale.count);
for (int i = 0; i < scale.count; ++i)
notesOn[i] = false;
setNotesOn(bitset);
}

private:
void textEditorReturnKeyPressed(TextEditor &editor) override;

public:
virtual void paint(juce::Graphics &g) override;
Tunings::Tuning tuning;
Tunings::Scale scale;
Expand All @@ -254,6 +298,15 @@ class RadialScaleGraph : public juce::Component

juce::AffineTransform screenTransform, screenTransformInverted;
std::function<void(int index, double)> onToneChanged = [](int, double) {};
std::function<void(int index, const std::string &s)> onToneStringChanged =
[](int, const std::string &) {};
static constexpr int usedForSidebar = 140;

std::unique_ptr<juce::Viewport> toneList;
std::unique_ptr<juce::Component> toneInterior;
std::vector<std::unique_ptr<juce::TextEditor>> toneEditors;

void resized() override { toneList->setBounds(0, 0, usedForSidebar, getHeight()); }

std::vector<bool> notesOn;
std::bitset<128> bitset{0};
Expand All @@ -270,6 +323,24 @@ class RadialScaleGraph : public juce::Component
notesOn[tuning.scalePositionForMidiNote(i)] = true;
}
}

for (int i = 0; i < scale.count + 1; ++i)
{
auto ni = i % (scale.count);
if (notesOn[ni])
{
toneEditors[i]->setColour(juce::TextEditor::ColourIds::backgroundColourId,
juce::Colour(0xFFaaaa50));
}
else
{
toneEditors[i]->setColour(juce::TextEditor::ColourIds::backgroundColourId,
juce::Colours::black);
}
toneEditors[i]->repaint();
}
toneInterior->repaint();
toneList->repaint();
repaint();
}
virtual void mouseMove(const juce::MouseEvent &e) override;
Expand All @@ -287,7 +358,7 @@ void RadialScaleGraph::paint(Graphics &g)
notesOn[i] = 0;
}
g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
int w = getWidth();
int w = getWidth() - usedForSidebar;
int h = getHeight();
float r = std::min(w, h) / 2.1;
float xo = (w - 2 * r) / 2.0;
Expand All @@ -296,10 +367,12 @@ void RadialScaleGraph::paint(Graphics &g)

g.saveState();

screenTransform = AffineTransform::scale(1.0 / (1.0 + outerRadiusExtension * 1.1))
screenTransform = AffineTransform()
.scaled(1.0 / (1.0 + outerRadiusExtension * 1.1))
.scaled(r, -r)
.translated(r, r)
.translated(xo, yo);
.translated(xo, yo)
.translated(usedForSidebar, 0);
screenTransformInverted = screenTransform.inverted();

g.addTransform(screenTransform);
Expand Down Expand Up @@ -462,6 +535,7 @@ struct IntervalMatrix : public juce::Component
};

distanceButton = std::make_unique<juce::ToggleButton>("Show Distance from Even");
distanceButton->setToggleState(false, juce::NotificationType::dontSendNotification);
distanceButton->onClick = [this]() {
intervalPainter->mode = IntervalPainter::DIST;
intervalPainter->repaint();
Expand Down Expand Up @@ -490,7 +564,7 @@ struct IntervalMatrix : public juce::Component
{
INTERV,
DIST
} mode;
} mode{INTERV};
IntervalPainter(IntervalMatrix *m) : matrix(m) {}

static constexpr int cellH{14}, cellW{35};
Expand Down Expand Up @@ -783,12 +857,23 @@ void RadialScaleGraph::mouseDrag(const juce::MouseEvent &e)
}
}

void RadialScaleGraph::textEditorReturnKeyPressed(TextEditor &editor)
{
for (int i = 1; i <= scale.count; ++i)
{
if (&editor == toneEditors[i].get())
{
onToneStringChanged(i - 1, editor.getText().toStdString());
}
}
}

struct SCLKBMDisplay : public juce::Component,
Surge::GUI::SkinConsumingComponent,
juce::TextEditor::Listener,
juce::Button::Listener
{
SCLKBMDisplay()
SCLKBMDisplay(TuningOverlay *o) : overlay(o)
{
scl = std::make_unique<juce::TextEditor>();
scl->setFont(Surge::GUI::getFontManager()->getFiraMonoAtSize(10));
Expand All @@ -808,6 +893,14 @@ struct SCLKBMDisplay : public juce::Component,
apply->addListener(this);
apply->setEnabled(false);
addAndMakeVisible(*apply);

exportButton = std::make_unique<juce::TextButton>("Export HTML", "Export HTML");
exportButton->addListener(this);
addAndMakeVisible(*exportButton);

libButton = std::make_unique<juce::TextButton>("Tuning Library", "Tuning Library");
libButton->addListener(this);
addAndMakeVisible(*libButton);
}
void setTuning(const Tunings::Tuning &t)
{
Expand All @@ -824,18 +917,36 @@ struct SCLKBMDisplay : public juce::Component,
scl->setBounds(2, 2, w / 2 - 4, h - 4);
kbm->setBounds(w / 2 + 2, 2, w / 2 - 4, h - 4);
apply->setBounds(w - 102, h + 2, 100, 18);
exportButton->setBounds(w - 204, h + 2, 100, 18);
libButton->setBounds(w - 306, h + 2, 100, 18);
}

void textEditorTextChanged(TextEditor &editor) override { apply->setEnabled(true); }
void buttonClicked(Button *button) override
{
onTextChanged(scl->getText().toStdString(), kbm->getText().toStdString());
if (button == apply.get())
{
onTextChanged(scl->getText().toStdString(), kbm->getText().toStdString());
}
if (button == exportButton.get())
{
if (overlay && overlay->editor)
{
overlay->editor->showHTML(overlay->editor->tuningToHtml());
}
}
if (button == libButton.get())
{
auto path = overlay->storage->datapath / "tuning_library";
Surge::GUI::openFileOrFolder(path);
}
}
std::function<void(const std::string &scl, const std::string &kbl)> onTextChanged =
[](auto a, auto b) {};

std::unique_ptr<juce::TextEditor> scl, kbm;
std::unique_ptr<juce::Button> apply;
std::unique_ptr<juce::Button> apply, exportButton, libButton;
TuningOverlay *overlay{nullptr};

JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SCLKBMDisplay);
};
Expand All @@ -858,20 +969,22 @@ TuningOverlay::TuningOverlay()
tabArea =
std::make_unique<juce::TabbedComponent>(juce::TabbedButtonBar::Orientation::TabsAtBottom);

sclKbmDisplay = std::make_unique<SCLKBMDisplay>();
sclKbmDisplay = std::make_unique<SCLKBMDisplay>(this);
sclKbmDisplay->onTextChanged = [this](const std::string &s, const std::string &k) {
this->onNewSCLKBM(s, k);
};

radialScaleGraph = std::make_unique<RadialScaleGraph>();
radialScaleGraph->onToneChanged = [this](int note, double d) { this->onToneChanged(note, d); };
radialScaleGraph->onToneStringChanged = [this](int note, const std::string &d) {
this->onToneStringChanged(note, d);
};

intervalMatrix = std::make_unique<IntervalMatrix>(this);

tabArea->addTab("SCL/KBM", juce::Colours::black, sclKbmDisplay.get(), false);
tabArea->addTab("Radial", juce::Colours::black, radialScaleGraph.get(), false);
tabArea->addTab("Interval", juce::Colours::black, intervalMatrix.get(), false);
tabArea->addTab("Generators", juce::Colours::black, new juce::Label("S"), true);
addAndMakeVisible(*tabArea);
}

Expand Down Expand Up @@ -906,6 +1019,23 @@ void TuningOverlay::onToneChanged(int tone, double newCentsValue)
}
}

void TuningOverlay::onToneStringChanged(int tone, const std::string &newStringValue)
{
if (storage)
{
try
{
auto parsed = Tunings::toneFromString(newStringValue);
storage->currentScale.tones[tone] = parsed;
recalculateScaleText();
}
catch (Tunings::TuningError &e)
{
storage->reportError(e.what(), "Tuning Tone Conversion");
}
}
}

void TuningOverlay::onNewSCLKBM(const std::string &scl, const std::string &kbm)
{
if (!storage)
Expand Down Expand Up @@ -978,5 +1108,22 @@ void TuningOverlay::onSkinChanged()
tuningKeyboardTable->repaint();
}

void TuningOverlay::onTearOutChanged(bool isTornOut) { doDnD = isTornOut; }
bool TuningOverlay::isInterestedInFileDrag(const StringArray &files)
{
if (!doDnD)
return false;
if (editor)
return editor->juceEditor->isInterestedInFileDrag(files);
return false;
}
void TuningOverlay::filesDropped(const StringArray &files, int x, int y)
{
if (!doDnD)
return;
if (editor)
editor->juceEditor->filesDropped(files, x, y);
}

} // namespace Overlays
} // namespace Surge
Loading