sfizz/vst/SfizzVstEditor.cpp

425 lines
12 KiB
C++
Raw Normal View History

2020-03-05 11:16:47 +01:00
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "SfizzVstEditor.h"
#include "SfizzVstState.h"
2020-03-05 18:21:46 +01:00
#include "GUIComponents.h"
2020-03-05 11:16:47 +01:00
#if !defined(__APPLE__) && !defined(_WIN32)
2020-03-12 00:41:35 +01:00
#include "X11RunLoop.h"
2020-03-05 11:16:47 +01:00
#endif
using namespace VSTGUI;
static ViewRect sfizzUiViewRect {0, 0, 684, 684};
2020-03-05 11:16:47 +01:00
SfizzVstEditor::SfizzVstEditor(void *controller)
: VSTGUIEditor(controller, &sfizzUiViewRect),
2020-03-05 15:53:01 +01:00
_logo("logo.png")
2020-03-05 11:16:47 +01:00
{
2020-03-05 18:21:46 +01:00
getController()->addSfizzStateListener(this);
2020-03-05 11:16:47 +01:00
}
SfizzVstEditor::~SfizzVstEditor()
{
2020-03-05 18:21:46 +01:00
getController()->removeSfizzStateListener(this);
2020-03-05 11:16:47 +01:00
}
bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& platformType)
{
fprintf(stderr, "[sfizz] about to open view with parent %p\n", parent);
CRect wsize(0, 0, sfizzUiViewRect.getWidth(), sfizzUiViewRect.getHeight());
2020-03-05 11:16:47 +01:00
CFrame *frame = new CFrame(wsize, this);
this->frame = frame;
IPlatformFrameConfig* config = nullptr;
#if !defined(__APPLE__) && !defined(_WIN32)
X11::FrameConfig x11config;
2020-03-12 00:41:35 +01:00
if (!_runLoop)
_runLoop = new RunLoop(plugFrame);
x11config.runLoop = _runLoop;
2020-03-05 11:16:47 +01:00
config = &x11config;
#endif
createFrameContents();
updateStateDisplay();
if (!frame->open(parent, platformType, config)) {
fprintf(stderr, "[sfizz] error opening frame\n");
return false;
}
2020-03-05 11:16:47 +01:00
return true;
}
void PLUGIN_API SfizzVstEditor::close()
{
CFrame *frame = this->frame;
if (frame) {
2020-03-12 00:41:35 +01:00
frame->removeAll();
if (frame->getNbReference() != 1)
frame->forget ();
else {
frame->close();
this->frame = nullptr;
}
2020-03-05 11:16:47 +01:00
}
}
///
void SfizzVstEditor::valueChanged(CControl* ctl)
{
int32_t tag = ctl->getTag();
float value = ctl->getValue();
2020-03-05 18:21:46 +01:00
float valueNorm = ctl->getValueNormalized();
SfizzVstController* controller = getController();
2020-03-05 11:16:47 +01:00
switch (tag) {
case kTagLoadSfzFile:
if (value != 1)
break;
2020-03-05 15:53:01 +01:00
Call::later([this]() { chooseSfzFile(); });
2020-03-05 11:16:47 +01:00
break;
2020-03-05 16:41:59 +01:00
2020-03-05 18:21:46 +01:00
case kTagSetVolume:
controller->setParamNormalized(kPidVolume, valueNorm);
controller->performEdit(kPidVolume, valueNorm);
break;
2020-03-06 11:46:49 +01:00
case kTagSetNumVoices:
controller->setParamNormalized(kPidNumVoices, valueNorm);
controller->performEdit(kPidNumVoices, valueNorm);
break;
2020-03-06 11:55:52 +01:00
case kTagSetOversampling:
controller->setParamNormalized(kPidOversampling, valueNorm);
controller->performEdit(kPidOversampling, valueNorm);
break;
2020-03-06 13:15:32 +01:00
case kTagSetPreloadSize:
controller->setParamNormalized(kPidPreloadSize, valueNorm);
controller->performEdit(kPidPreloadSize, valueNorm);
break;
2020-03-05 16:41:59 +01:00
default:
if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel)
setActivePanel(tag - kTagFirstChangePanel);
break;
2020-03-05 11:16:47 +01:00
}
}
2020-03-05 18:21:46 +01:00
void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter)
{
int32_t tag = ctl->getTag();
Vst::ParamID id;
switch (tag) {
case kTagSetVolume: id = kPidVolume; break;
2020-03-06 11:46:49 +01:00
case kTagSetNumVoices: id = kPidNumVoices; break;
2020-03-06 11:55:52 +01:00
case kTagSetOversampling: id = kPidOversampling; break;
2020-03-06 13:15:32 +01:00
case kTagSetPreloadSize: id = kPidPreloadSize; break;
2020-03-05 18:21:46 +01:00
default: return;
}
SfizzVstController* controller = getController();
if (enter)
controller->beginEdit(id);
else
controller->endEdit(id);
}
void SfizzVstEditor::controlBeginEdit(CControl* ctl)
{
enterOrLeaveEdit(ctl, true);
}
void SfizzVstEditor::controlEndEdit(CControl* ctl)
{
enterOrLeaveEdit(ctl, false);
}
2020-03-12 00:41:35 +01:00
CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message)
{
CMessageResult result = VSTGUIEditor::notify(sender, message);
if (result != kMessageNotified)
return result;
#if !defined(__APPLE__) && !defined(_WIN32)
if (message == CVSTGUITimer::kMsgTimer) {
SharedPointer<VSTGUI::RunLoop> runLoop = RunLoop::get();
if (runLoop) {
// note(jpc) I don't find a reliable way to check if the host
// notifier of X11 events is working. If there is, remove this and
// avoid polluting Linux hosts which implement the loop correctly.
runLoop->processSomeEvents();
runLoop->cleanupDeadHandlers();
}
}
#endif
return result;
}
2020-03-05 11:16:47 +01:00
void SfizzVstEditor::onStateChanged()
{
updateStateDisplay();
}
///
void SfizzVstEditor::chooseSfzFile()
{
SharedPointer<CNewFileSelector> fs(CNewFileSelector::create(frame));
fs->setTitle("Load SFZ file");
fs->setDefaultExtension(CFileExtension("SFZ", "sfz"));
if (fs->runModal()) {
UTF8StringPtr file = fs->getSelectedFile(0);
if (file)
loadSfzFile(file);
}
}
void SfizzVstEditor::loadSfzFile(const std::string& filePath)
{
2020-03-05 18:21:46 +01:00
SfizzVstController* ctl = getController();
2020-03-05 15:53:01 +01:00
2020-03-05 11:16:47 +01:00
Vst::IMessage *msg = ctl->allocateMessage();
2020-03-05 15:53:01 +01:00
if (!msg) {
fprintf(stderr, "[Sfizz] UI could not allocate message\n");
return;
2020-03-05 11:16:47 +01:00
}
2020-03-05 15:53:01 +01:00
msg->setMessageID("LoadSfz");
Vst::IAttributeList* attr = msg->getAttributes();
attr->setString("File", Steinberg::String(filePath.c_str()).text());
ctl->sendMessage(msg);
msg->release();
if (_fileLabel)
_fileLabel->setText(("File: " + filePath).c_str());
2020-03-05 11:16:47 +01:00
}
2020-03-05 16:41:59 +01:00
void SfizzVstEditor::createFrameContents()
{
2020-03-05 18:21:46 +01:00
SfizzVstController* controller = getController();
const SfizzUiState& uiState = controller->getSfizzUiState();
2020-03-05 16:41:59 +01:00
CFrame* frame = this->frame;
CRect bounds = frame->getViewSize();
frame->setBackgroundColor(CColor(0xff, 0xff, 0xff));
2020-03-05 11:16:47 +01:00
2020-03-05 16:41:59 +01:00
CRect bottomRow = bounds;
bottomRow.top = bottomRow.bottom - 30;
CRect topRow = bounds;
topRow.bottom = topRow.top + 30;
CViewContainer* panel;
2020-03-05 18:21:46 +01:00
_activePanel = std::max(0, std::min(kNumPanels - 1, static_cast<int>(uiState.activePanel)));
2020-03-05 16:41:59 +01:00
CRect topLeftLabelBox = topRow;
topLeftLabelBox.right -= 20 * kNumPanels;
// general panel
2020-03-05 11:16:47 +01:00
{
2020-03-05 16:41:59 +01:00
panel = new CViewContainer(bounds);
frame->addView(panel);
panel->setTransparency(true);
CKickButton* sfizzButton = new CKickButton(bounds, this, kTagLoadSfzFile, &_logo);
panel->addView(sfizzButton);
CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "No file loaded");
topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00));
topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
panel->addView(topLeftLabel);
_fileLabel = topLeftLabel;
_subPanels[kPanelGeneral] = panel;
2020-03-05 11:16:47 +01:00
}
2020-03-05 16:41:59 +01:00
// settings panel
2020-03-05 11:16:47 +01:00
{
2020-03-05 16:41:59 +01:00
panel = new CViewContainer(bounds);
frame->addView(panel);
panel->setTransparency(true);
2020-03-05 11:16:47 +01:00
2020-03-05 16:41:59 +01:00
CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Settings");
topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00));
topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
panel->addView(topLeftLabel);
2020-03-05 11:16:47 +01:00
2020-03-05 18:21:46 +01:00
CRect row = topRow;
row.top += 200.0;
row.bottom += 200.0;
row.left += 100.0;
row.right -= 100.0;
CCoord interRow = 35.0;
auto leftSide = [&row]() -> CRect {
CRect div = row;
div.right = 0.5 * (div.left + div.right);
return div;
};
auto rightSide = [&row]() -> CRect {
CRect div = row;
div.left = 0.5 * (div.left + div.right);
return div;
};
CTextLabel* label;
SimpleSlider* slider;
label = new CTextLabel(leftSide(), "Volume");
label->setFontColor(CColor(0x00, 0x00, 0x00));
label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setHoriAlign(kLeftText);
panel->addView(label);
slider = new SimpleSlider(rightSide(), this, kTagSetVolume);
panel->addView(slider);
2020-03-06 11:46:49 +01:00
adjustMinMaxToRangeParam(slider, kPidVolume);
2020-03-05 18:21:46 +01:00
_volumeSlider = slider;
2020-03-06 11:46:49 +01:00
row.top += interRow;
row.bottom += interRow;
2020-03-05 18:21:46 +01:00
2020-03-06 11:46:49 +01:00
label = new CTextLabel(leftSide(), "Polyphony");
label->setFontColor(CColor(0x00, 0x00, 0x00));
label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setHoriAlign(kLeftText);
panel->addView(label);
slider = new SimpleSlider(rightSide(), this, kTagSetNumVoices);
panel->addView(slider);
adjustMinMaxToRangeParam(slider, kPidNumVoices);
_numVoicesSlider = slider;
2020-03-05 18:21:46 +01:00
2020-03-06 11:55:52 +01:00
row.top += interRow;
row.bottom += interRow;
2020-03-05 18:21:46 +01:00
2020-03-06 11:55:52 +01:00
label = new CTextLabel(leftSide(), "Oversampling");
label->setFontColor(CColor(0x00, 0x00, 0x00));
label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setHoriAlign(kLeftText);
panel->addView(label);
slider = new SimpleSlider(rightSide(), this, kTagSetOversampling);
panel->addView(slider);
adjustMinMaxToRangeParam(slider, kPidOversampling);
_oversamplingSlider = slider;
2020-03-05 18:21:46 +01:00
2020-03-06 13:15:32 +01:00
row.top += interRow;
row.bottom += interRow;
2020-03-05 18:21:46 +01:00
2020-03-06 13:15:32 +01:00
label = new CTextLabel(leftSide(), "Preload size");
label->setFontColor(CColor(0x00, 0x00, 0x00));
label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
label->setHoriAlign(kLeftText);
panel->addView(label);
slider = new SimpleSlider(rightSide(), this, kTagSetPreloadSize);
panel->addView(slider);
adjustMinMaxToRangeParam(slider, kPidPreloadSize);
_preloadSizeSlider = slider;
2020-03-05 18:21:46 +01:00
// row.top += interRow;
// row.bottom += interRow;
// label = new CTextLabel(leftSide(), "Freewheel");
// label->setFontColor(CColor(0x00, 0x00, 0x00));
// label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00));
// label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
// label->setHoriAlign(kLeftText);
// panel->addView(label);
2020-03-06 11:55:52 +01:00
// slider = new SimpleSlider(rightSide(), this, kTag);
2020-03-05 18:21:46 +01:00
// panel->addView(slider);
2020-03-06 11:55:52 +01:00
// adjustMinMaxToRangeParam(slider, kPid);
// _aSlider = slider;
2020-03-05 18:21:46 +01:00
2020-03-05 16:41:59 +01:00
_subPanels[kPanelSettings] = panel;
2020-03-05 11:16:47 +01:00
}
2020-03-05 16:41:59 +01:00
// all panels
for (unsigned currentPanel = 0; currentPanel < kNumPanels; ++currentPanel) {
panel = _subPanels[currentPanel];
2020-03-05 11:16:47 +01:00
2020-03-05 16:41:59 +01:00
CTextLabel* descLabel = new CTextLabel(
bottomRow, "Paul Ferrand and the SFZ Tools work group");
descLabel->setFontColor(CColor(0x00, 0x00, 0x00));
descLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
panel->addView(descLabel);
2020-03-05 11:16:47 +01:00
2020-03-05 16:41:59 +01:00
for (unsigned i = 0; i < kNumPanels; ++i) {
CRect btnRect = topRow;
btnRect.left = topRow.right - (kNumPanels - i) * 20;
btnRect.right = btnRect.left + 20;
2020-03-05 15:53:01 +01:00
2020-03-05 16:41:59 +01:00
const char *text;
switch (i) {
case kPanelGeneral: text = "G"; break;
case kPanelSettings: text = "S"; break;
default: text = "?"; break;
}
2020-03-05 15:53:01 +01:00
2020-03-05 16:41:59 +01:00
CTextButton* changePanelButton = new CTextButton(btnRect, this, kTagFirstChangePanel + i, text);
panel->addView(changePanelButton);
2020-03-05 15:53:01 +01:00
2020-03-05 16:41:59 +01:00
changePanelButton->setRoundRadius(0.0);
}
2020-03-05 15:53:01 +01:00
2020-03-05 16:41:59 +01:00
panel->setVisible(currentPanel == _activePanel);
}
2020-03-05 11:16:47 +01:00
}
void SfizzVstEditor::updateStateDisplay()
{
if (!frame)
return;
2020-03-05 18:21:46 +01:00
SfizzVstController* controller = getController();
const SfizzVstState& state = controller->getSfizzState();
const SfizzUiState& uiState = controller->getSfizzUiState();
2020-03-05 11:16:47 +01:00
2020-03-05 15:53:01 +01:00
if (_fileLabel)
_fileLabel->setText(("File: " + state.sfzFile).c_str());
2020-03-05 18:21:46 +01:00
if (_volumeSlider)
_volumeSlider->setValue(state.volume);
2020-03-06 11:46:49 +01:00
if (_numVoicesSlider)
_numVoicesSlider->setValue(state.numVoices);
2020-03-06 11:55:52 +01:00
if (_oversamplingSlider)
2020-03-06 13:15:32 +01:00
_oversamplingSlider->setValue(state.oversamplingLog2);
if (_preloadSizeSlider)
_preloadSizeSlider->setValue(state.preloadSize);
2020-03-05 18:21:46 +01:00
setActivePanel(uiState.activePanel);
2020-03-05 11:16:47 +01:00
}
2020-03-05 16:41:59 +01:00
void SfizzVstEditor::setActivePanel(unsigned panelId)
{
2020-03-05 18:21:46 +01:00
panelId = std::max(0, std::min(kNumPanels - 1, static_cast<int>(panelId)));
getController()->getSfizzUiState().activePanel = panelId;
2020-03-05 16:41:59 +01:00
if (_activePanel != panelId) {
2020-03-05 18:21:46 +01:00
if (frame)
_subPanels[_activePanel]->setVisible(false);
2020-03-05 16:41:59 +01:00
_activePanel = panelId;
2020-03-05 18:21:46 +01:00
if (frame)
_subPanels[panelId]->setVisible(true);
2020-03-05 16:41:59 +01:00
}
}