diff --git a/assets/original-vector/SVG/exported/bmp00102.svg b/assets/original-vector/SVG/exported/bmp00102.svg index a5e805bf7ca..83452ae4fec 100644 --- a/assets/original-vector/SVG/exported/bmp00102.svg +++ b/assets/original-vector/SVG/exported/bmp00102.svg @@ -1,6 +1,6 @@ - + bmp00102 Created with Sketch. @@ -62,8 +62,8 @@ - - + + @@ -92,12 +92,12 @@ - - + + - + @@ -107,16 +107,17 @@ - + - + + - - + + @@ -236,7 +237,7 @@ - + diff --git a/assets/original-vector/SVG/master/Surge_OG.sketch b/assets/original-vector/SVG/master/Surge_OG.sketch index 3791dff07a7..d6a77b02e39 100644 Binary files a/assets/original-vector/SVG/master/Surge_OG.sketch and b/assets/original-vector/SVG/master/Surge_OG.sketch differ diff --git a/premake5.lua b/premake5.lua index 82ea93d56aa..ca96a47a845 100644 --- a/premake5.lua +++ b/premake5.lua @@ -207,6 +207,7 @@ function plugincommon() "src/common/gui/CNumberField.cpp", "src/common/gui/COscillatorDisplay.cpp", "src/common/gui/CPatchBrowser.cpp", + "src/common/gui/CStatusPanel.cpp", "src/common/gui/CScalableBitmap.cpp", "src/common/gui/CSnapshotMenu.cpp", "src/common/gui/CSurgeSlider.cpp", diff --git a/src/common/SurgePatch.cpp b/src/common/SurgePatch.cpp index 40eb9b800df..ecb2a6cb7a0 100644 --- a/src/common/SurgePatch.cpp +++ b/src/common/SurgePatch.cpp @@ -709,6 +709,7 @@ void SurgePatch::update_controls(bool init, if (t_osc) { t_osc->init_ctrltypes(); + t_osc->handleStreamingMismatches( streamingRevision, currentSynthStreamingRevision ); if (init || (init_osc == &sc.osc[osc])) t_osc->init_default_values(); delete t_osc; @@ -993,7 +994,9 @@ void SurgePatch::load_xml(const void* data, int datasize, bool is_preset) int revision = 0; patch->QueryIntAttribute("revision", &revision); - + streamingRevision = revision; + currentSynthStreamingRevision = ff_revision; + TiXmlElement* meta = TINYXML_SAFE_TO_ELEMENT(patch->FirstChild("meta")); if (meta) { @@ -1355,6 +1358,20 @@ void SurgePatch::load_xml(const void* data, int datasize, bool is_preset) p = TINYXML_SAFE_TO_ELEMENT(p->NextSibling("entry")); } + patchTuning.tuningStoredInPatch = false; + TiXmlElement *pt = TINYXML_SAFE_TO_ELEMENT(patch->FirstChild("patchTuning")); + if( pt ) + { + const char* td; + if( pt && + (td = pt->Attribute("v") )) + { + patchTuning.tuningStoredInPatch = true; + auto tc = base64_decode(td); + patchTuning.tuningContents = tc; + } + } + dawExtraState.isPopulated = false; TiXmlElement *de = TINYXML_SAFE_TO_ELEMENT(patch->FirstChild("dawExtraState")); if( de ) @@ -1579,6 +1596,15 @@ unsigned int SurgePatch::save_xml(void** data) // allocates mem, must be freed b patch.InsertEndChild(mw); } + if( patchTuning.tuningStoredInPatch ) + { + TiXmlElement pt( "patchTuning" ); + pt.SetAttribute("v", base64_encode( (unsigned const char *)patchTuning.tuningContents.c_str(), + patchTuning.tuningContents.size() ).c_str() ); + + patch.InsertEndChild(pt); + } + TiXmlElement dawExtraXML("dawExtraState"); dawExtraXML.SetAttribute( "populated", dawExtraState.isPopulated ? 1 : 0 ); diff --git a/src/common/SurgeStorage.h b/src/common/SurgeStorage.h index 8f6db5372c4..eba8b6c9beb 100644 --- a/src/common/SurgeStorage.h +++ b/src/common/SurgeStorage.h @@ -402,6 +402,13 @@ struct DAWExtraStateStorage std::string tuningContents = ""; }; + +struct PatchTuningStorage +{ + bool tuningStoredInPatch = false; + std::string tuningContents = ""; +}; + class SurgeStorage; class SurgePatch @@ -438,6 +445,7 @@ class SurgePatch StepSequencerStorage stepsequences[2][n_lfos]; + PatchTuningStorage patchTuning; DAWExtraStateStorage dawExtraState; std::vector param_ptr; @@ -453,6 +461,9 @@ class SurgePatch std::string name, category, author, comment; // metaparameters char CustomControllerLabel[n_customcontrollers][16]; + + int streamingRevision; + int currentSynthStreamingRevision; }; struct Patch diff --git a/src/common/SurgeSynthesizerIO.cpp b/src/common/SurgeSynthesizerIO.cpp index 58ebdae785d..d3da10ca126 100644 --- a/src/common/SurgeSynthesizerIO.cpp +++ b/src/common/SurgeSynthesizerIO.cpp @@ -176,6 +176,25 @@ void SurgeSynthesizer::loadPatch(int id) loadRaw(data, cs, true); free(data); + /* + ** OK so at this point we may have loaded a patch with a tuning override + */ + if( storage.getPatch().patchTuning.tuningStoredInPatch ) + { + if( storage.isStandardTuning ) + storage.retuneToScale(Surge::Storage::parseSCLData(storage.getPatch().patchTuning.tuningContents )); + else + { + auto okc = Surge::UserInteractions::promptOKCancel(std::string("The patch you loaded contains a recommended tuning, but you ") + + "already have a tuning in place. Do you want to override your current tuning " + + "with the patch sugeested tuning?", + "Replace Tuning? (The rest of the patch will still load)."); + if( okc == Surge::UserInteractions::MessageResult::OK ) + storage.retuneToScale(Surge::Storage::parseSCLData(storage.getPatch().patchTuning.tuningContents)); + } + + } + masterfade = 1.f; #if AU /* AUPreset preset; diff --git a/src/common/dsp/Oscillator.cpp b/src/common/dsp/Oscillator.cpp index fd00c7a29e6..8944444025d 100644 --- a/src/common/dsp/Oscillator.cpp +++ b/src/common/dsp/Oscillator.cpp @@ -186,6 +186,18 @@ float osc_sine::valueFromSinAndCos(float svalue, float cvalue) return pvalue; } +void osc_sine::handleStreamingMismatches(int streamingRevision, int currentSynthStreamingRevision) +{ + if( streamingRevision <= 10 ) + { + oscdata->p[1].val.f = 0; + } + if( streamingRevision <= 9 ) + { + oscdata->p[0].val.i = 0; + } +} + void osc_sine::init_ctrltypes() { oscdata->p[0].set_name("WaveShape"); diff --git a/src/common/dsp/Oscillator.h b/src/common/dsp/Oscillator.h index 7499cbd4019..a68c50f8502 100644 --- a/src/common/dsp/Oscillator.h +++ b/src/common/dsp/Oscillator.h @@ -34,6 +34,11 @@ class alignas(16) Oscillator return (float)(M_PI * (16.35159783) * storage->note_to_pitch(x) * dsamplerate_os_inv); } + virtual void handleStreamingMismatches(int streamingRevision, int currentSynthStreamingRevision) + { + // No-op here. + } + protected: SurgeStorage* storage; OscillatorStorage* oscdata; @@ -64,6 +69,7 @@ class osc_sine : public Oscillator float lastvalue = 0; float valueFromSinAndCos(float svalue, float cvalue); + virtual void handleStreamingMismatches(int s, int synths) override; }; class FMOscillator : public Oscillator diff --git a/src/common/gui/CPatchBrowser.cpp b/src/common/gui/CPatchBrowser.cpp index c5b97d3b43f..53039cc6c18 100644 --- a/src/common/gui/CPatchBrowser.cpp +++ b/src/common/gui/CPatchBrowser.cpp @@ -13,7 +13,6 @@ extern CFontRef patchNameFont; void CPatchBrowser::draw(CDrawContext* dc) { - dc->setFillColor(kBlackCColor); CRect size = getViewSize(); CRect ar(size); ar.inset(1, 0); @@ -41,7 +40,6 @@ void CPatchBrowser::draw(CDrawContext* dc) dc->drawString(category.c_str(), al, kLeftText, true); al.offset(0, 12); dc->drawString(author.c_str(), al, kLeftText, true); - setDirty(false); } diff --git a/src/common/gui/CPatchBrowser.h b/src/common/gui/CPatchBrowser.h index a48823c73f2..5702b1ada95 100644 --- a/src/common/gui/CPatchBrowser.h +++ b/src/common/gui/CPatchBrowser.h @@ -8,6 +8,7 @@ class CPatchBrowser : public VSTGUI::CControl { public: + CPatchBrowser(const VSTGUI::CRect& size, VSTGUI::IControlListener* listener, long tag, SurgeStorage* storage) : VSTGUI::CControl(size, listener, tag, 0) { @@ -52,6 +53,7 @@ class CPatchBrowser : public VSTGUI::CControl author = ""; setDirty(true); } + virtual void draw(VSTGUI::CDrawContext* dc); VSTGUI::CMouseEventResult onMouseDown(VSTGUI::CPoint& where, const VSTGUI::CButtonState& button); void loadPatch(int id); diff --git a/src/common/gui/CStatusPanel.cpp b/src/common/gui/CStatusPanel.cpp new file mode 100644 index 00000000000..88e86f79628 --- /dev/null +++ b/src/common/gui/CStatusPanel.cpp @@ -0,0 +1,94 @@ +#include "CStatusPanel.h" +#include "RuntimeFont.h" +#include "SurgeGUIEditor.h" + +using namespace VSTGUI; + +void CStatusPanel::draw( VSTGUI::CDrawContext *dc ) +{ + auto size = getViewSize(); + + dc->setFont(displayFont); + auto sw = dc->getStringWidth("Status"); + dc->setFontColor(kBlackCColor); + dc->drawString("Status", CPoint( size.left + size.getWidth()/2 - sw/2, size.top + 8 ), true ); + + std::string labs[numDisplayFeatures]; + labs[mpeMode] = "mpe"; + labs[tuningMode] = "tun"; + int y0 = 13; + int boxSize = 13; + for( int i=0; isetFrameColor(bg);; + auto p = dc->createRoundRectGraphicsPath(CRect(xp,yp,xp+w,yp+h), 5 ); + dc->setFillColor(bg);; + dc->drawGraphicsPath(p, CDrawContext::kPathFilled); + dc->setFrameColor(ol); + dc->drawGraphicsPath(p, CDrawContext::kPathStroked); + p->forget(); + + if( hlbg ) + { + auto p = dc->createRoundRectGraphicsPath(CRect(xp+2,yp+2,xp+w-2,yp+h-2), 3 ); + dc->setFillColor(hl); + dc->drawGraphicsPath(p, CDrawContext::kPathFilled); + p->forget(); + } + dc->setFont(displayFont); + auto sw = dc->getStringWidth(labs[i].c_str()); + dc->setFontColor(fg); + dc->drawString(labs[i].c_str(), CPoint( xp + w/2 - sw/2, yp + h - 2 ), true ); + } +} + +VSTGUI::CMouseEventResult CStatusPanel::onMouseDown(VSTGUI::CPoint& where, const VSTGUI::CButtonState& button) +{ + if( mpeBox.pointInside(where) && editor ) + { + if( button & kLButton ) + { + editor->toggleMPE(); + } + else if( button & kRButton ) + { + editor->showMPEMenu(where); + } + return kMouseDownEventHandledButDontNeedMovedOrUpEvents; + } + + if( tuningBox.pointInside(where) && editor ) + { + if( button & kLButton ) + { + editor->toggleTuning(); + } + else if( button & kRButton ) + { + editor->showTuningMenu(where); + } + return kMouseDownEventHandledButDontNeedMovedOrUpEvents; + } + + return CControl::onMouseDown(where, button); +} + diff --git a/src/common/gui/CStatusPanel.h b/src/common/gui/CStatusPanel.h new file mode 100644 index 00000000000..a15473b888f --- /dev/null +++ b/src/common/gui/CStatusPanel.h @@ -0,0 +1,53 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright 2005 Claes Johanson & Vember Audio +//------------------------------------------------------------------------------------------------------- +#pragma once +#include "SurgeStorage.h" +#include "vstcontrols.h" + +class SurgeGUIEditor; + +class CStatusPanel : public VSTGUI::CControl +{ +public: + + typedef enum { + mpeMode, + tuningMode, + numDisplayFeatures + } DisplayFeatures; + + CStatusPanel(const VSTGUI::CRect& size, VSTGUI::IControlListener* listener, long tag, SurgeStorage* storage) + : VSTGUI::CControl(size, listener, tag, 0) + { + for( auto i=0; isel_id != synth->patchid; + } + if( statuspanel ) + { + CStatusPanel *pb = (CStatusPanel *)statuspanel; + pb->setDisplayFeature(CStatusPanel::mpeMode, synth->mpeEnabled); + pb->setDisplayFeature(CStatusPanel::tuningMode, ! synth->storage.isStandardTuning); + } + + if (queue_refresh || synth->refresh_editor || patchChanged) { queue_refresh = false; @@ -749,13 +763,23 @@ void SurgeGUIEditor::openOrRecreateEditor() // 150*b - 16 = 434 (b=3) patchname = - new CPatchBrowser(CRect(156, 11, 591, 11 + 28), this, tag_patchname, &synth->storage); + new CPatchBrowser(CRect(156, 11, 547, 11 + 28), this, tag_patchname, &synth->storage); ((CPatchBrowser*)patchname)->setLabel(synth->storage.getPatch().name); ((CPatchBrowser*)patchname)->setCategory(synth->storage.getPatch().category); ((CPatchBrowser*)patchname)->setIDs(synth->current_category_id, synth->patchid); ((CPatchBrowser*)patchname)->setAuthor(synth->storage.getPatch().author); frame->addView(patchname); + statuspanel = new CStatusPanel(CRect( 560, 1, 595, 54 ), this, tag_statuspanel, &synth->storage); + { + CStatusPanel *pb = (CStatusPanel *)statuspanel; + pb->setDisplayFeature(CStatusPanel::mpeMode, synth->mpeEnabled); + pb->setDisplayFeature(CStatusPanel::tuningMode, ! synth->storage.isStandardTuning); + pb->setEditor(this); + } + + frame->addView(statuspanel); + CHSwitch2* mp_cat = new CHSwitch2(CRect(157, 41, 157 + 37, 41 + 12), this, tag_mp_category, 2, 12, 1, 2, bitmapStore->getBitmap(IDB_BUTTON_MINUSPLUS), nopoint, false); @@ -768,7 +792,7 @@ void SurgeGUIEditor::openOrRecreateEditor() mp_patch->setUsesMouseWheel(false);// mousewheel on category and patch buttons is undesirable frame->addView(mp_patch); - CHSwitch2* b_store = new CHSwitch2(CRect(591 - 37, 41, 591, 41 + 12), this, tag_store, 1, 12, 1, + CHSwitch2* b_store = new CHSwitch2(CRect(547 - 37, 41, 591, 41 + 12), this, tag_store, 1, 12, 1, 1, bitmapStore->getBitmap(IDB_BUTTON_STORE), nopoint, false); frame->addView(b_store); @@ -1289,7 +1313,11 @@ void SurgeGUIEditor::openOrRecreateEditor() patchCategory = new CTextEdit(CRect(CPoint(96, 58), CPoint(340, 21)), this, tag_store_category); patchCreator = new CTextEdit(CRect(CPoint(96, 85), CPoint(340, 21)), this, tag_store_creator); patchComment = new CTextEdit(CRect(CPoint(96, 112), CPoint(340, 21)), this, tag_store_comments); - + patchTuning = new CCheckBox(CRect(CPoint(96, 112 + (112-85) ), CPoint( 21, 21 )), this, tag_store_tuning); + patchTuningLabel = new CTextLabel(CRect(CPoint(96 + 22, 112 + (112-85) ), CPoint( 200, 21 ))); + patchTuningLabel->setText( "Save Tuning in Patch" ); + patchTuningLabel->sizeToFit(); + // Mouse behavior if (CSurgeSlider::sliderMoveRateState == CSurgeSlider::kUnInitialized) CSurgeSlider::sliderMoveRateState = @@ -1314,7 +1342,7 @@ void SurgeGUIEditor::openOrRecreateEditor() patchCategory->setBackColor(kWhiteCColor); patchCreator->setBackColor(kWhiteCColor); patchComment->setBackColor(kWhiteCColor); - + patchName->setFontColor(kBlackCColor); patchCategory->setFontColor(kBlackCColor); patchCreator->setFontColor(kBlackCColor); @@ -1325,11 +1353,19 @@ void SurgeGUIEditor::openOrRecreateEditor() patchCreator->setFrameColor(kGreyCColor); patchComment->setFrameColor(kGreyCColor); + CColor bggr(205,206,212); + patchTuningLabel->setBackColor(bggr); + patchTuningLabel->setFrameColor(bggr); + patchTuningLabel->setFontColor(kBlackCColor); + saveDialog->addView(patchName); saveDialog->addView(patchCategory); saveDialog->addView(patchCreator); saveDialog->addView(patchComment); - + saveDialog->addView(patchTuning); + saveDialog->addView(patchTuningLabel); + + editor_open = true; queue_refresh = false; frame->setDirty(); @@ -2282,6 +2318,13 @@ void SurgeGUIEditor::valueChanged(CControl* control) synth->storage.getPatch().author = patchCreator->getText(); synth->storage.getPatch().category = patchCategory->getText(); synth->storage.getPatch().comment = patchComment->getText(); + + synth->storage.getPatch().patchTuning.tuningStoredInPatch = patchTuning->getValue() > 0.5; + if( synth->storage.getPatch().patchTuning.tuningStoredInPatch ) + synth->storage.getPatch().patchTuning.tuningContents = synth->storage.currentScale.rawText; + + synth->storage.getPatch().dawExtraState.isPopulated = false; // Ignore whatever comes from the DAW + synth->savePatch(); } } @@ -2552,6 +2595,21 @@ bool SurgeGUIEditor::showPatchStoreDialog(patchdata* p, std::vector* patch_category, int startcategory) { + if( synth->storage.isStandardTuning ) + { + patchTuningLabel->setFontColor(kGreyCColor); + patchTuning->setMouseEnabled(false); + patchTuning->setBoxFrameColor(kGreyCColor); + patchTuning->setValue(0); + } + else + { + patchTuningLabel->setFontColor(kBlackCColor); + patchTuning->setMouseEnabled(true); + patchTuning->setBoxFrameColor(kBlackCColor); + patchTuning->setValue(0); + } + saveDialog->setVisible(true); // frame->setModalView(saveDialog); @@ -2568,6 +2626,53 @@ long SurgeGUIEditor::unapplyParameterOffset(long id) return id + start_paramtags; } +// Status Panel Callbacks +void SurgeGUIEditor::toggleMPE() +{ + this->synth->mpeEnabled = ! this->synth->mpeEnabled; + if( statuspanel ) + ((CStatusPanel *)statuspanel)->setDisplayFeature(CStatusPanel::mpeMode, this->synth->mpeEnabled ); +} +void SurgeGUIEditor::showMPEMenu(VSTGUI::CPoint &where) +{ + CRect menuRect; + menuRect.offset(where.x, where.y); + auto m = makeMpeMenu(menuRect); + + frame->addView(m); + m->setDirty(); + m->popup(); + frame->removeView(m, true); +} + +void SurgeGUIEditor::toggleTuning() +{ + if( this->synth->storage.isStandardTuning && tuningCacheForToggle.size() > 0 ) + { + this->synth->storage.retuneToScale(Surge::Storage::parseSCLData(tuningCacheForToggle)); + } + else if( ! this->synth->storage.isStandardTuning ) + { + tuningCacheForToggle = this->synth->storage.currentScale.rawText; + this->synth->storage.init_tables(); + } + + if( statuspanel ) + ((CStatusPanel *)statuspanel)->setDisplayFeature(CStatusPanel::tuningMode, this->synth->storage.isStandardTuning ); +} +void SurgeGUIEditor::showTuningMenu(VSTGUI::CPoint &where) +{ + CRect menuRect; + menuRect.offset(where.x, where.y); + auto m = makeTuningMenu(menuRect); + + frame->addView(m); + m->setDirty(); + m->popup(); + frame->removeView(m, true); +} + + void SurgeGUIEditor::setZoomFactor(int zf) { if (!zoomEnabled) @@ -2725,26 +2830,7 @@ void SurgeGUIEditor::showSettingsMenu(CRect &menuRect) eid++; } - COptionMenu* mpeSubMenu = - new COptionMenu(menuRect, 0, 0, 0, 0, VSTGUI::COptionMenu::kNoDrawStyle); - std::string endis = "Enable MPE"; - if (synth->mpeEnabled) - endis = "Disable MPE"; - addCallbackMenu(mpeSubMenu, endis.c_str(), - [this]() { this->synth->mpeEnabled = !this->synth->mpeEnabled; }); - - std::ostringstream oss; - oss << "Change default pitch bend range (" << synth->mpePitchBendRange << ")"; - addCallbackMenu(mpeSubMenu, oss.str().c_str(), [this]() { - // FIXME! This won't work on linux - char c[256]; - snprintf(c, 256, "%d", synth->mpePitchBendRange); - spawn_miniedit_text(c, 16); - int newVal = ::atoi(c); - Surge::Storage::updateUserDefaultValue(&(this->synth->storage), "mpePitchBendRange", newVal); - this->synth->mpePitchBendRange = newVal; - }); - + auto mpeSubMenu = makeMpeMenu(menuRect); std::string mpeMenuName = "MPE (disabled)"; if (synth->mpeEnabled) mpeMenuName = "MPE (enabled)"; @@ -2809,67 +2895,7 @@ void SurgeGUIEditor::showSettingsMenu(CRect &menuRect) eid++; mouseSubMenu->forget(); - int tid=0; - COptionMenu *tuningSubMenu = new COptionMenu(menuRect, 0, 0, 0, 0, - VSTGUI::COptionMenu::kNoDrawStyle | - VSTGUI::COptionMenu::kMultipleCheckStyle); - - auto *st = addCallbackMenu(tuningSubMenu, "Set to Standard Tuning", - [this]() - { - this->synth->storage.init_tables(); - } - ); - st->setEnabled(! this->synth->storage.isStandardTuning); - tid++; - - addCallbackMenu(tuningSubMenu, "Apply .scl file tuning", - [this]() - { - auto cb = [this](std::string sf) - { - std::string sfx = ".scl"; - if( sf.length() >= sfx.length()) - { - if( sf.compare(sf.length() - sfx.length(), sfx.length(), sfx) != 0 ) - { - Surge::UserInteractions::promptError( "Please only select .scl files", "Invalid Choice" ); - std::cout << "FILE is [" << sf << "]" << std::endl; - return; - } - } - auto sc = Surge::Storage::readSCLFile(sf); - this->synth->storage.retuneToScale(sc); - }; - Surge::UserInteractions::promptFileOpenDialog(this->synth->storage.userDataPath, - ".scl", - cb); - } - ); - tid++; - - auto *sct = addCallbackMenu(tuningSubMenu, "Show current tuning", - [this]() - { - // Surge::UserInteractions::promptOKCancel( "Surge tuning is NONstandard tuning", "Tuning Info" ); - Surge::UserInteractions::showHTML( this->synth->storage.currentScale.toHtml() ); - } - ); - sct->setEnabled(! this->synth->storage.isStandardTuning ); - - /* - tuningSubMenu->addSeparator(tid++); - - addCallbackMenu(tuningSubMenu, "Apply .kbm file mapping", - [this]() - { - Surge::UserInteractions::promptError("KBM File Mappings are not yet supported in Surge", - "Unsupported", - this); - } - ); - */ - + auto tuningSubMenu = makeTuningMenu(menuRect); settingsMenu->addEntry(tuningSubMenu, "Tuning" ); eid++; tuningSubMenu->forget(); @@ -2952,6 +2978,97 @@ void SurgeGUIEditor::showSettingsMenu(CRect &menuRect) frame->removeView(settingsMenu, true); } + +VSTGUI::COptionMenu *SurgeGUIEditor::makeMpeMenu(VSTGUI::CRect &menuRect) +{ + COptionMenu* mpeSubMenu = + new COptionMenu(menuRect, 0, 0, 0, 0, VSTGUI::COptionMenu::kNoDrawStyle); + std::string endis = "Enable MPE"; + if (synth->mpeEnabled) + endis = "Disable MPE"; + addCallbackMenu(mpeSubMenu, endis.c_str(), + [this]() { this->synth->mpeEnabled = !this->synth->mpeEnabled; }); + + std::ostringstream oss; + oss << "Change default pitch bend range (" << synth->mpePitchBendRange << ")"; + addCallbackMenu(mpeSubMenu, oss.str().c_str(), [this]() { + // FIXME! This won't work on linux + char c[256]; + snprintf(c, 256, "%d", synth->mpePitchBendRange); + spawn_miniedit_text(c, 16); + int newVal = ::atoi(c); + Surge::Storage::updateUserDefaultValue(&(this->synth->storage), "mpePitchBendRange", newVal); + this->synth->mpePitchBendRange = newVal; + }); + return mpeSubMenu; + +} + +VSTGUI::COptionMenu *SurgeGUIEditor::makeTuningMenu(VSTGUI::CRect &menuRect) +{ + int tid=0; + COptionMenu *tuningSubMenu = new COptionMenu(menuRect, 0, 0, 0, 0, + VSTGUI::COptionMenu::kNoDrawStyle | + VSTGUI::COptionMenu::kMultipleCheckStyle); + + auto *st = addCallbackMenu(tuningSubMenu, "Set to Standard Tuning", + [this]() + { + this->synth->storage.init_tables(); + } + ); + st->setEnabled(! this->synth->storage.isStandardTuning); + tid++; + + addCallbackMenu(tuningSubMenu, "Apply .scl file tuning", + [this]() + { + auto cb = [this](std::string sf) + { + std::string sfx = ".scl"; + if( sf.length() >= sfx.length()) + { + if( sf.compare(sf.length() - sfx.length(), sfx.length(), sfx) != 0 ) + { + Surge::UserInteractions::promptError( "Please only select .scl files", "Invalid Choice" ); + std::cout << "FILE is [" << sf << "]" << std::endl; + return; + } + } + auto sc = Surge::Storage::readSCLFile(sf); + this->synth->storage.retuneToScale(sc); + }; + Surge::UserInteractions::promptFileOpenDialog(this->synth->storage.userDataPath, + ".scl", + cb); + } + ); + tid++; + + auto *sct = addCallbackMenu(tuningSubMenu, "Show current tuning", + [this]() + { + // Surge::UserInteractions::promptOKCancel( "Surge tuning is NONstandard tuning", "Tuning Info" ); + Surge::UserInteractions::showHTML( this->synth->storage.currentScale.toHtml() ); + } + ); + sct->setEnabled(! this->synth->storage.isStandardTuning ); + + /* + tuningSubMenu->addSeparator(tid++); + + addCallbackMenu(tuningSubMenu, "Apply .kbm file mapping", + [this]() + { + Surge::UserInteractions::promptError("KBM File Mappings are not yet supported in Surge", + "Unsupported", + this); + } + ); + */ + return tuningSubMenu; +} + int SurgeGUIEditor::findLargestFittingZoomBetween(int zoomLow, // bottom of range int zoomHigh, // top of range int zoomQuanta, // step size diff --git a/src/common/gui/SurgeGUIEditor.h b/src/common/gui/SurgeGUIEditor.h index c81a92614c0..01072b18f18 100644 --- a/src/common/gui/SurgeGUIEditor.h +++ b/src/common/gui/SurgeGUIEditor.h @@ -174,6 +174,15 @@ class SurgeGUIEditor : public EditorType, public VSTGUI::IControlListener, publi setZoomFactor(100); } + /* + ** Callbacks from the Status Panel. If this gets to be too many perhaps make these an interface? + */ + void toggleMPE(); + void showMPEMenu(VSTGUI::CPoint &where); + void toggleTuning(); + void showTuningMenu(VSTGUI::CPoint &where); + std::string tuningCacheForToggle = ""; + private: /** * findLargestFittingZoomBetween @@ -200,13 +209,15 @@ class SurgeGUIEditor : public EditorType, public VSTGUI::IControlListener, publi std::shared_ptr bitmapStore = nullptr; VSTGUI::CControl* vu[16]; - VSTGUI::CControl *infowindow, *patchname, *ccfxconf = nullptr; + VSTGUI::CControl *infowindow, *patchname, *ccfxconf = nullptr, *statuspanel = nullptr; VSTGUI::CControl* aboutbox = nullptr; VSTGUI::CViewContainer* saveDialog = nullptr; VSTGUI::CTextEdit* patchName = nullptr; VSTGUI::CTextEdit* patchCategory = nullptr; VSTGUI::CTextEdit* patchCreator = nullptr; VSTGUI::CTextEdit* patchComment = nullptr; + VSTGUI::CCheckBox* patchTuning = nullptr; + VSTGUI::CTextLabel* patchTuningLabel = nullptr; VSTGUI::CControl* polydisp = nullptr; VSTGUI::CControl* oscdisplay = nullptr; VSTGUI::CControl* param[1024] = {}; @@ -230,5 +241,7 @@ class SurgeGUIEditor : public EditorType, public VSTGUI::IControlListener, publi */ VSTGUI::CCommandMenuItem* addCallbackMenu(VSTGUI::COptionMenu* toThis, std::string label, std::function op); + VSTGUI::COptionMenu* makeMpeMenu(VSTGUI::CRect &rect); + VSTGUI::COptionMenu* makeTuningMenu(VSTGUI::CRect &rect); };