Update the VST plugin
This commit is contained in:
parent
ba0c68f5a1
commit
42bf66dd74
8 changed files with 541 additions and 28 deletions
|
|
@ -34,10 +34,22 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context)
|
|||
kParamPreloadSizeRange.createParameter(
|
||||
Steinberg::String("Preload size"), pid++, nullptr,
|
||||
0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId));
|
||||
parameters.addParameter(
|
||||
kParamScalaRootKey.createParameter(
|
||||
Steinberg::String("Scala root key"), pid++, nullptr,
|
||||
0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId));
|
||||
parameters.addParameter(
|
||||
kParamTuningFrequency.createParameter(
|
||||
Steinberg::String("Tuning frequency"), pid++, Steinberg::String("Hz"),
|
||||
0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId));
|
||||
parameters.addParameter(
|
||||
kParamStretchedTuning.createParameter(
|
||||
Steinberg::String("Stretched tuning"), pid++, nullptr,
|
||||
0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId));
|
||||
|
||||
// MIDI special controllers
|
||||
parameters.addParameter(Steinberg::String("Aftertouch"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId);
|
||||
parameters.addParameter(Steinberg::String("Pitch Bend"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId);
|
||||
parameters.addParameter(Steinberg::String("Pitch bend"), nullptr, 0, 0.5, 0, pid++, Vst::kRootUnitId);
|
||||
|
||||
// MIDI controllers
|
||||
for (unsigned i = 0; i < kNumControllerParams; ++i) {
|
||||
|
|
@ -161,6 +173,21 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst:
|
|||
value = kParamPreloadSizeRange.denormalize(normValue);
|
||||
break;
|
||||
}
|
||||
case kPidScalaRootKey: {
|
||||
slotI32 = &_state.scalaRootKey;
|
||||
value = kParamScalaRootKey.denormalize(normValue);
|
||||
break;
|
||||
}
|
||||
case kPidTuningFrequency: {
|
||||
slotF32 = &_state.tuningFrequency;
|
||||
value = kParamTuningFrequency.denormalize(normValue);
|
||||
break;
|
||||
}
|
||||
case kPidStretchedTuning: {
|
||||
slotF32 = &_state.stretchedTuning;
|
||||
value = kParamStretchedTuning.denormalize(normValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool update = false;
|
||||
|
|
@ -217,6 +244,9 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state)
|
|||
setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices));
|
||||
setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversamplingLog2));
|
||||
setParamNormalized(kPidPreloadSize, kParamPreloadSizeRange.normalize(s.preloadSize));
|
||||
setParamNormalized(kPidScalaRootKey, kParamScalaRootKey.normalize(s.scalaRootKey));
|
||||
setParamNormalized(kPidTuningFrequency, kParamTuningFrequency.normalize(s.tuningFrequency));
|
||||
setParamNormalized(kPidStretchedTuning, kParamStretchedTuning.normalize(s.stretchedTuning));
|
||||
|
||||
for (StateListener* listener : _stateListeners)
|
||||
listener->onStateChanged();
|
||||
|
|
@ -224,6 +254,34 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state)
|
|||
return kResultTrue;
|
||||
}
|
||||
|
||||
tresult SfizzVstController::notify(Vst::IMessage* message)
|
||||
{
|
||||
tresult result = SfizzVstControllerNoUi::notify(message);
|
||||
if (result != kResultFalse)
|
||||
return result;
|
||||
|
||||
const char* id = message->getMessageID();
|
||||
Vst::IAttributeList* attr = message->getAttributes();
|
||||
|
||||
if (!strcmp(id, "LoadedSfz")) {
|
||||
const void* data = nullptr;
|
||||
uint32 size = 0;
|
||||
result = attr->getBinary("File", data, size);
|
||||
_state.sfzFile.assign(static_cast<const char *>(data), size);
|
||||
}
|
||||
else if (!strcmp(id, "LoadedScala")) {
|
||||
const void* data = nullptr;
|
||||
uint32 size = 0;
|
||||
result = attr->getBinary("File", data, size);
|
||||
_state.scalaFile.assign(static_cast<const char *>(data), size);
|
||||
}
|
||||
|
||||
for (StateListener* listener : _stateListeners)
|
||||
listener->onStateChanged();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SfizzVstController::addSfizzStateListener(StateListener* listener)
|
||||
{
|
||||
_stateListeners.push_back(listener);
|
||||
|
|
|
|||
|
|
@ -44,12 +44,14 @@ public:
|
|||
tresult PLUGIN_API setState(IBStream* state) override;
|
||||
tresult PLUGIN_API getState(IBStream* state) override;
|
||||
tresult PLUGIN_API setComponentState(IBStream* state) override;
|
||||
tresult PLUGIN_API notify(Vst::IMessage* message) override;
|
||||
|
||||
struct StateListener {
|
||||
virtual void onStateChanged() = 0;
|
||||
};
|
||||
|
||||
const SfizzVstState& getSfizzState() const { return _state; }
|
||||
SfizzVstState& getSfizzState() { return _state; }
|
||||
|
||||
const SfizzUiState& getSfizzUiState() const { return _uiState; }
|
||||
SfizzUiState& getSfizzUiState() { return _uiState; }
|
||||
|
|
|
|||
|
|
@ -86,24 +86,53 @@ void SfizzVstEditor::valueChanged(CControl* ctl)
|
|||
Call::later([this]() { chooseSfzFile(); });
|
||||
break;
|
||||
|
||||
case kTagLoadScalaFile:
|
||||
if (value != 1)
|
||||
break;
|
||||
|
||||
Call::later([this]() { chooseScalaFile(); });
|
||||
break;
|
||||
|
||||
case kTagSetVolume:
|
||||
controller->setParamNormalized(kPidVolume, valueNorm);
|
||||
controller->performEdit(kPidVolume, valueNorm);
|
||||
updateVolumeLabel(value);
|
||||
break;
|
||||
|
||||
case kTagSetNumVoices:
|
||||
controller->setParamNormalized(kPidNumVoices, valueNorm);
|
||||
controller->performEdit(kPidNumVoices, valueNorm);
|
||||
updateNumVoicesLabel(static_cast<int>(value));
|
||||
break;
|
||||
|
||||
case kTagSetOversampling:
|
||||
controller->setParamNormalized(kPidOversampling, valueNorm);
|
||||
controller->performEdit(kPidOversampling, valueNorm);
|
||||
updateOversamplingLabel(static_cast<int>(value));
|
||||
break;
|
||||
|
||||
case kTagSetPreloadSize:
|
||||
controller->setParamNormalized(kPidPreloadSize, valueNorm);
|
||||
controller->performEdit(kPidPreloadSize, valueNorm);
|
||||
updatePreloadSizeLabel(static_cast<int>(value));
|
||||
break;
|
||||
|
||||
case kTagSetScalaRootKey:
|
||||
controller->setParamNormalized(kPidScalaRootKey, valueNorm);
|
||||
controller->performEdit(kPidScalaRootKey, valueNorm);
|
||||
updateScalaRootKeyLabel(value);
|
||||
break;
|
||||
|
||||
case kTagSetTuningFrequency:
|
||||
controller->setParamNormalized(kPidTuningFrequency, valueNorm);
|
||||
controller->performEdit(kPidTuningFrequency, valueNorm);
|
||||
updateTuningFrequencyLabel(value);
|
||||
break;
|
||||
|
||||
case kTagSetStretchedTuning:
|
||||
controller->setParamNormalized(kPidStretchedTuning, valueNorm);
|
||||
controller->performEdit(kPidStretchedTuning, valueNorm);
|
||||
updateStretchedTuningLabel(value);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -123,6 +152,9 @@ void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter)
|
|||
case kTagSetNumVoices: id = kPidNumVoices; break;
|
||||
case kTagSetOversampling: id = kPidOversampling; break;
|
||||
case kTagSetPreloadSize: id = kPidPreloadSize; break;
|
||||
case kTagSetScalaRootKey: id = kPidScalaRootKey; break;
|
||||
case kTagSetTuningFrequency: id = kPidTuningFrequency; break;
|
||||
case kTagSetStretchedTuning: id = kPidStretchedTuning; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +223,7 @@ void SfizzVstEditor::loadSfzFile(const std::string& filePath)
|
|||
{
|
||||
SfizzVstController* ctl = getController();
|
||||
|
||||
Vst::IMessage *msg = ctl->allocateMessage();
|
||||
Steinberg::OPtr<Vst::IMessage> msg { ctl->allocateMessage() };
|
||||
if (!msg) {
|
||||
fprintf(stderr, "[Sfizz] UI could not allocate message\n");
|
||||
return;
|
||||
|
|
@ -201,9 +233,40 @@ void SfizzVstEditor::loadSfzFile(const std::string& filePath)
|
|||
Vst::IAttributeList* attr = msg->getAttributes();
|
||||
attr->setBinary("File", filePath.data(), filePath.size());
|
||||
ctl->sendMessage(msg);
|
||||
msg->release();
|
||||
|
||||
updateFileLabel(filePath);
|
||||
updateSfzFileLabel(filePath);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::chooseScalaFile()
|
||||
{
|
||||
SharedPointer<CNewFileSelector> fs(CNewFileSelector::create(frame));
|
||||
|
||||
fs->setTitle("Load Scala file");
|
||||
fs->setDefaultExtension(CFileExtension("SCL", "scl"));
|
||||
|
||||
if (fs->runModal()) {
|
||||
UTF8StringPtr file = fs->getSelectedFile(0);
|
||||
if (file)
|
||||
loadScalaFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
void SfizzVstEditor::loadScalaFile(const std::string& filePath)
|
||||
{
|
||||
SfizzVstController* ctl = getController();
|
||||
|
||||
Steinberg::OPtr<Vst::IMessage> msg { ctl->allocateMessage() };
|
||||
if (!msg) {
|
||||
fprintf(stderr, "[Sfizz] UI could not allocate message\n");
|
||||
return;
|
||||
}
|
||||
|
||||
msg->setMessageID("LoadScala");
|
||||
Vst::IAttributeList* attr = msg->getAttributes();
|
||||
attr->setBinary("File", filePath.data(), filePath.size());
|
||||
ctl->sendMessage(msg);
|
||||
|
||||
updateScalaFileLabel(filePath);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::createFrameContents()
|
||||
|
|
@ -241,7 +304,7 @@ void SfizzVstEditor::createFrameContents()
|
|||
topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00));
|
||||
topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
|
||||
panel->addView(topLeftLabel);
|
||||
_fileLabel = topLeftLabel;
|
||||
_sfzFileLabel = topLeftLabel;
|
||||
|
||||
_subPanels[kPanelGeneral] = panel;
|
||||
}
|
||||
|
|
@ -277,6 +340,13 @@ void SfizzVstEditor::createFrameContents()
|
|||
return div;
|
||||
};
|
||||
|
||||
auto labelArea = [&topRow, &row]() -> CRect {
|
||||
CRect div = row;
|
||||
div.right = topRow.right - 10.0;
|
||||
div.left = div.right - 100.0 + 20.0;
|
||||
return div;
|
||||
};
|
||||
|
||||
CTextLabel* label;
|
||||
SimpleSlider* slider;
|
||||
|
||||
|
|
@ -290,6 +360,9 @@ void SfizzVstEditor::createFrameContents()
|
|||
panel->addView(slider);
|
||||
adjustMinMaxToRangeParam(slider, kPidVolume);
|
||||
_volumeSlider = slider;
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_volumeLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
row.top += interRow;
|
||||
row.bottom += interRow;
|
||||
|
|
@ -304,6 +377,9 @@ void SfizzVstEditor::createFrameContents()
|
|||
panel->addView(slider);
|
||||
adjustMinMaxToRangeParam(slider, kPidNumVoices);
|
||||
_numVoicesSlider = slider;
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_numVoicesLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
row.top += interRow;
|
||||
row.bottom += interRow;
|
||||
|
|
@ -318,6 +394,9 @@ void SfizzVstEditor::createFrameContents()
|
|||
panel->addView(slider);
|
||||
adjustMinMaxToRangeParam(slider, kPidOversampling);
|
||||
_oversamplingSlider = slider;
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_oversamplingLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
row.top += interRow;
|
||||
row.bottom += interRow;
|
||||
|
|
@ -332,6 +411,9 @@ void SfizzVstEditor::createFrameContents()
|
|||
panel->addView(slider);
|
||||
adjustMinMaxToRangeParam(slider, kPidPreloadSize);
|
||||
_preloadSizeSlider = slider;
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_preloadSizeLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
// row.top += interRow;
|
||||
// row.bottom += interRow;
|
||||
|
|
@ -350,6 +432,114 @@ void SfizzVstEditor::createFrameContents()
|
|||
_subPanels[kPanelSettings] = panel;
|
||||
}
|
||||
|
||||
// tuning panel
|
||||
{
|
||||
panel = new CViewContainer(bounds);
|
||||
frame->addView(panel);
|
||||
panel->setTransparency(true);
|
||||
|
||||
CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Tuning");
|
||||
topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00));
|
||||
topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00));
|
||||
panel->addView(topLeftLabel);
|
||||
|
||||
CRect row = topRow;
|
||||
row.top += 45.0;
|
||||
row.bottom += 45.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;
|
||||
};
|
||||
|
||||
auto labelArea = [&topRow, &row]() -> CRect {
|
||||
CRect div = row;
|
||||
div.right = topRow.right - 10.0;
|
||||
div.left = div.right - 100.0 + 20.0;
|
||||
return div;
|
||||
};
|
||||
|
||||
CTextLabel* label;
|
||||
SimpleSlider* slider;
|
||||
CTextButton* textbutton;
|
||||
|
||||
label = new CTextLabel(leftSide(), "Scala file");
|
||||
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);
|
||||
textbutton = new CTextButton(rightSide(), this, kTagLoadScalaFile, "Choose");
|
||||
panel->addView(textbutton);
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_scalaFileLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
row.top += interRow;
|
||||
row.bottom += interRow;
|
||||
|
||||
label = new CTextLabel(leftSide(), "Scala root key");
|
||||
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, kTagSetScalaRootKey);
|
||||
panel->addView(slider);
|
||||
adjustMinMaxToRangeParam(slider, kPidScalaRootKey);
|
||||
_scalaRootKeySlider = slider;
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_scalaRootKeyLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
row.top += interRow;
|
||||
row.bottom += interRow;
|
||||
|
||||
label = new CTextLabel(leftSide(), "Tuning frequency");
|
||||
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, kTagSetTuningFrequency);
|
||||
panel->addView(slider);
|
||||
adjustMinMaxToRangeParam(slider, kPidTuningFrequency);
|
||||
_tuningFrequencySlider = slider;
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_tuningFrequencyLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
row.top += interRow;
|
||||
row.bottom += interRow;
|
||||
|
||||
label = new CTextLabel(leftSide(), "Stretched tuning");
|
||||
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, kTagSetStretchedTuning);
|
||||
panel->addView(slider);
|
||||
adjustMinMaxToRangeParam(slider, kPidStretchedTuning);
|
||||
_stretchedTuningSlider = slider;
|
||||
label = new CTextLabel(labelArea(), "");
|
||||
_stretchedTuningLabel = label;
|
||||
panel->addView(label);
|
||||
|
||||
_subPanels[kPanelTuning] = panel;
|
||||
}
|
||||
|
||||
// all panels
|
||||
for (unsigned currentPanel = 0; currentPanel < kNumPanels; ++currentPanel) {
|
||||
panel = _subPanels[currentPanel];
|
||||
|
|
@ -369,6 +559,7 @@ void SfizzVstEditor::createFrameContents()
|
|||
switch (i) {
|
||||
case kPanelGeneral: text = "File"; break;
|
||||
case kPanelSettings: text = "Setup"; break;
|
||||
case kPanelTuning: text = "Tuning"; break;
|
||||
default: text = "?"; break;
|
||||
}
|
||||
|
||||
|
|
@ -391,38 +582,164 @@ void SfizzVstEditor::updateStateDisplay()
|
|||
const SfizzVstState& state = controller->getSfizzState();
|
||||
const SfizzUiState& uiState = controller->getSfizzUiState();
|
||||
|
||||
updateFileLabel(state.sfzFile);
|
||||
updateSfzFileLabel(state.sfzFile);
|
||||
if (_volumeSlider)
|
||||
_volumeSlider->setValue(state.volume);
|
||||
updateVolumeLabel(state.volume);
|
||||
if (_numVoicesSlider)
|
||||
_numVoicesSlider->setValue(state.numVoices);
|
||||
updateNumVoicesLabel(state.numVoices);
|
||||
if (_oversamplingSlider)
|
||||
_oversamplingSlider->setValue(state.oversamplingLog2);
|
||||
updateOversamplingLabel(state.oversamplingLog2);
|
||||
if (_preloadSizeSlider)
|
||||
_preloadSizeSlider->setValue(state.preloadSize);
|
||||
updatePreloadSizeLabel(state.preloadSize);
|
||||
updateScalaFileLabel(state.scalaFile);
|
||||
if (_scalaRootKeySlider)
|
||||
_scalaRootKeySlider->setValue(state.scalaRootKey);
|
||||
updateScalaRootKeyLabel(state.scalaRootKey);
|
||||
if (_tuningFrequencySlider)
|
||||
_tuningFrequencySlider->setValue(state.tuningFrequency);
|
||||
updateTuningFrequencyLabel(state.tuningFrequency);
|
||||
if (_stretchedTuningSlider)
|
||||
_stretchedTuningSlider->setValue(state.stretchedTuning);
|
||||
updateStretchedTuningLabel(state.stretchedTuning);
|
||||
|
||||
setActivePanel(uiState.activePanel);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateFileLabel(const std::string& filePath)
|
||||
void SfizzVstEditor::updateSfzFileLabel(const std::string& filePath)
|
||||
{
|
||||
if (_fileLabel) {
|
||||
std::string fileName;
|
||||
if (filePath.empty())
|
||||
fileName = "<No file>";
|
||||
else {
|
||||
#if defined (_WIN32)
|
||||
size_t pos = filePath.find_last_of("/\\");
|
||||
#else
|
||||
size_t pos = filePath.rfind('/');
|
||||
#endif
|
||||
fileName = (pos != filePath.npos) ?
|
||||
filePath.substr(pos + 1) : filePath;
|
||||
}
|
||||
_fileLabel->setText(fileName.c_str());
|
||||
}
|
||||
updateLabelWithFileName(_sfzFileLabel, filePath);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateScalaFileLabel(const std::string& filePath)
|
||||
{
|
||||
updateLabelWithFileName(_scalaFileLabel, filePath);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateLabelWithFileName(CTextLabel* label, const std::string& filePath)
|
||||
{
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
std::string fileName;
|
||||
if (filePath.empty())
|
||||
fileName = "<No file>";
|
||||
else {
|
||||
#if defined (_WIN32)
|
||||
size_t pos = filePath.find_last_of("/\\");
|
||||
#else
|
||||
size_t pos = filePath.rfind('/');
|
||||
#endif
|
||||
fileName = (pos != filePath.npos) ?
|
||||
filePath.substr(pos + 1) : filePath;
|
||||
}
|
||||
label->setText(fileName.c_str());
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateVolumeLabel(float volume)
|
||||
{
|
||||
CTextLabel* label = _volumeLabel;
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
char text[64];
|
||||
sprintf(text, "%.1f dB", volume);
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
label->setText(text);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateNumVoicesLabel(int numVoices)
|
||||
{
|
||||
CTextLabel* label = _numVoicesLabel;
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
char text[64];
|
||||
sprintf(text, "%d", numVoices);
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
label->setText(text);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateOversamplingLabel(int oversamplingLog2)
|
||||
{
|
||||
CTextLabel* label = _oversamplingLabel;
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
char text[64];
|
||||
sprintf(text, "%dx", 1 << oversamplingLog2);
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
label->setText(text);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updatePreloadSizeLabel(int preloadSize)
|
||||
{
|
||||
CTextLabel* label = _preloadSizeLabel;
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
char text[64];
|
||||
sprintf(text, "%.1f kB", preloadSize * (1.0 / 1024));
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
label->setText(text);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateScalaRootKeyLabel(int rootKey)
|
||||
{
|
||||
CTextLabel* label = _scalaRootKeyLabel;
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
static const char *octNoteNames[12] = {
|
||||
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
|
||||
};
|
||||
|
||||
auto noteName = [](int key) -> std::string
|
||||
{
|
||||
int octNum;
|
||||
int octNoteNum;
|
||||
if (key >= 0) {
|
||||
octNum = key / 12 - 1;
|
||||
octNoteNum = key % 12;
|
||||
}
|
||||
else {
|
||||
octNum = -2 - (key + 1) / -12;
|
||||
octNoteNum = (key % 12 + 12) % 12;
|
||||
}
|
||||
return std::string(octNoteNames[octNoteNum]) + std::to_string(octNum);
|
||||
};
|
||||
|
||||
label->setText(noteName(rootKey));
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateTuningFrequencyLabel(float tuningFrequency)
|
||||
{
|
||||
CTextLabel* label = _tuningFrequencyLabel;
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
char text[64];
|
||||
sprintf(text, "%.1f", tuningFrequency);
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
label->setText(text);
|
||||
}
|
||||
|
||||
void SfizzVstEditor::updateStretchedTuningLabel(float stretchedTuning)
|
||||
{
|
||||
CTextLabel* label = _stretchedTuningLabel;
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
char text[64];
|
||||
sprintf(text, "%.3f", stretchedTuning);
|
||||
text[sizeof(text) - 1] = '\0';
|
||||
label->setText(text);
|
||||
}
|
||||
|
||||
|
||||
void SfizzVstEditor::setActivePanel(unsigned panelId)
|
||||
{
|
||||
panelId = std::max(0, std::min(kNumPanels - 1, static_cast<int>(panelId)));
|
||||
|
|
|
|||
|
|
@ -43,9 +43,21 @@ private:
|
|||
void chooseSfzFile();
|
||||
void loadSfzFile(const std::string& filePath);
|
||||
|
||||
void chooseScalaFile();
|
||||
void loadScalaFile(const std::string& filePath);
|
||||
|
||||
void createFrameContents();
|
||||
void updateStateDisplay();
|
||||
void updateFileLabel(const std::string& filePath);
|
||||
void updateSfzFileLabel(const std::string& filePath);
|
||||
void updateScalaFileLabel(const std::string& filePath);
|
||||
static void updateLabelWithFileName(CTextLabel* label, const std::string& filePath);
|
||||
void updateVolumeLabel(float volume);
|
||||
void updateNumVoicesLabel(int numVoices);
|
||||
void updateOversamplingLabel(int oversamplingLog2);
|
||||
void updatePreloadSizeLabel(int preloadSize);
|
||||
void updateScalaRootKeyLabel(int rootKey);
|
||||
void updateTuningFrequencyLabel(float tuningFrequency);
|
||||
void updateStretchedTuningLabel(float stretchedTuning);
|
||||
void setActivePanel(unsigned panelId);
|
||||
|
||||
template <class Control>
|
||||
|
|
@ -60,6 +72,7 @@ private:
|
|||
kPanelGeneral,
|
||||
// kPanelControls,
|
||||
kPanelSettings,
|
||||
kPanelTuning,
|
||||
kNumPanels,
|
||||
};
|
||||
|
||||
|
|
@ -72,16 +85,31 @@ private:
|
|||
kTagSetNumVoices,
|
||||
kTagSetOversampling,
|
||||
kTagSetPreloadSize,
|
||||
kTagLoadScalaFile,
|
||||
kTagSetScalaRootKey,
|
||||
kTagSetTuningFrequency,
|
||||
kTagSetStretchedTuning,
|
||||
kTagFirstChangePanel,
|
||||
kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1,
|
||||
};
|
||||
|
||||
CBitmap _logo;
|
||||
CTextLabel* _fileLabel = nullptr;
|
||||
CTextLabel* _sfzFileLabel = nullptr;
|
||||
CTextLabel* _scalaFileLabel = nullptr;
|
||||
CSliderBase *_volumeSlider = nullptr;
|
||||
CTextLabel* _volumeLabel = nullptr;
|
||||
CSliderBase *_numVoicesSlider = nullptr;
|
||||
CTextLabel* _numVoicesLabel = nullptr;
|
||||
CSliderBase *_oversamplingSlider = nullptr;
|
||||
CTextLabel* _oversamplingLabel = nullptr;
|
||||
CSliderBase *_preloadSizeSlider = nullptr;
|
||||
CTextLabel* _preloadSizeLabel = nullptr;
|
||||
CSliderBase *_scalaRootKeySlider = nullptr;
|
||||
CTextLabel* _scalaRootKeyLabel = nullptr;
|
||||
CSliderBase *_tuningFrequencySlider = nullptr;
|
||||
CTextLabel* _tuningFrequencyLabel = nullptr;
|
||||
CSliderBase *_stretchedTuningSlider = nullptr;
|
||||
CTextLabel* _stretchedTuningLabel = nullptr;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
SharedPointer<RunLoop> _runLoop;
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ tresult PLUGIN_API SfizzVstProcessor::initialize(FUnknown* context)
|
|||
|
||||
fprintf(stderr, "[sfizz] new synth\n");
|
||||
_synth.reset(new sfz::Sfizz);
|
||||
_currentStretchedTuning = 0.0;
|
||||
loadSfzFileOrDefault(*_synth, {});
|
||||
|
||||
return result;
|
||||
|
|
@ -101,6 +102,10 @@ void SfizzVstProcessor::syncStateToSynth()
|
|||
synth->setNumVoices(_state.numVoices);
|
||||
synth->setOversamplingFactor(1 << _state.oversamplingLog2);
|
||||
synth->setPreloadSize(_state.preloadSize);
|
||||
synth->loadScalaFile(_state.scalaFile);
|
||||
synth->setScalaRootKey(_state.scalaRootKey);
|
||||
synth->setTuningFrequency(_state.tuningFrequency);
|
||||
synth->loadStretchTuningByRatio(_state.stretchedTuning);
|
||||
}
|
||||
|
||||
tresult PLUGIN_API SfizzVstProcessor::canProcessSampleSize(int32 symbolicSampleSize)
|
||||
|
|
@ -174,6 +179,12 @@ tresult PLUGIN_API SfizzVstProcessor::process(Vst::ProcessData& data)
|
|||
processEvents(*events);
|
||||
|
||||
synth.setVolume(_state.volume);
|
||||
synth.setScalaRootKey(_state.scalaRootKey);
|
||||
synth.setTuningFrequency(_state.tuningFrequency);
|
||||
if (_currentStretchedTuning != _state.stretchedTuning) {
|
||||
synth.loadStretchTuningByRatio(_state.stretchedTuning);
|
||||
_currentStretchedTuning = _state.stretchedTuning;
|
||||
}
|
||||
|
||||
synth.renderBlock(outputs, numFrames, numChannels);
|
||||
|
||||
|
|
@ -230,6 +241,18 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc)
|
|||
_semaToWorker.post();
|
||||
}
|
||||
break;
|
||||
case kPidScalaRootKey:
|
||||
if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue)
|
||||
_state.scalaRootKey = static_cast<int32>(kParamScalaRootKey.denormalize(value));
|
||||
break;
|
||||
case kPidTuningFrequency:
|
||||
if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue)
|
||||
_state.tuningFrequency = kParamTuningFrequency.denormalize(value);
|
||||
break;
|
||||
case kPidStretchedTuning:
|
||||
if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue)
|
||||
_state.stretchedTuning = kParamStretchedTuning.denormalize(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -328,9 +351,33 @@ tresult PLUGIN_API SfizzVstProcessor::notify(Vst::IMessage* message)
|
|||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
std::lock_guard<std::mutex> lock(_processMutex);
|
||||
std::unique_lock<std::mutex> lock(_processMutex);
|
||||
_state.sfzFile.assign(static_cast<const char *>(data), size);
|
||||
loadSfzFileOrDefault(*_synth, _state.sfzFile);
|
||||
lock.unlock();
|
||||
|
||||
Steinberg::OPtr<Vst::IMessage> reply { allocateMessage() };
|
||||
reply->setMessageID("LoadedSfz");
|
||||
reply->getAttributes()->setBinary("File", _state.sfzFile.data(), _state.sfzFile.size());
|
||||
sendMessage(reply);
|
||||
}
|
||||
else if (!std::strcmp(id, "LoadScala")) {
|
||||
const void* data = nullptr;
|
||||
uint32 size = 0;
|
||||
result = attr->getBinary("File", data, size);
|
||||
|
||||
if (result != kResultTrue)
|
||||
return result;
|
||||
|
||||
std::unique_lock<std::mutex> lock(_processMutex);
|
||||
_state.scalaFile.assign(static_cast<const char *>(data), size);
|
||||
_synth->loadScalaFile(_state.scalaFile);
|
||||
lock.unlock();
|
||||
|
||||
Steinberg::OPtr<Vst::IMessage> reply { allocateMessage() };
|
||||
reply->setMessageID("LoadedScala");
|
||||
reply->getAttributes()->setBinary("File", _state.scalaFile.data(), _state.scalaFile.size());
|
||||
sendMessage(reply);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -379,9 +426,13 @@ void SfizzVstProcessor::doBackgroundWork()
|
|||
}
|
||||
else if (!std::strcmp(id, "CheckShouldReload")) {
|
||||
if (_synth->shouldReloadFile()) {
|
||||
fprintf(stderr, "[Sfizz] file has changed, reloading\n");
|
||||
fprintf(stderr, "[Sfizz] sfz file has changed, reloading\n");
|
||||
loadSfzFileOrDefault(*_synth, _state.sfzFile);
|
||||
}
|
||||
else if (_synth->shouldReloadScala()) {
|
||||
fprintf(stderr, "[Sfizz] scala file has changed, reloading\n");
|
||||
_synth->loadScalaFile(_state.scalaFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ private:
|
|||
// synth state. acquire processMutex before accessing
|
||||
std::unique_ptr<sfz::Sfizz> _synth;
|
||||
SfizzVstState _state;
|
||||
float _currentStretchedTuning = 0;
|
||||
|
||||
// misc
|
||||
static void loadSfzFileOrDefault(sfz::Sfizz& synth, const std::string& filePath);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,33 @@ tresult SfizzVstState::load(IBStream* state)
|
|||
if (!s.readInt32(preloadSize))
|
||||
return kResultFalse;
|
||||
|
||||
const SfizzVstState defaults;
|
||||
|
||||
if (version >= 1) {
|
||||
if (const char* str = s.readStr8())
|
||||
scalaFile = str;
|
||||
else
|
||||
return kResultFalse;
|
||||
|
||||
if (!s.readInt32(scalaRootKey))
|
||||
return kResultFalse;
|
||||
|
||||
if (!s.readFloat(tuningFrequency))
|
||||
return kResultFalse;
|
||||
|
||||
if (!s.readFloat(stretchedTuning))
|
||||
return kResultFalse;
|
||||
}
|
||||
else {
|
||||
scalaFile = defaults.scalaFile;
|
||||
scalaRootKey = defaults.scalaRootKey;
|
||||
tuningFrequency = defaults.tuningFrequency;
|
||||
stretchedTuning = defaults.stretchedTuning;
|
||||
}
|
||||
|
||||
if (version > 1)
|
||||
return kResultFalse;
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
|
|
@ -59,9 +86,23 @@ tresult SfizzVstState::store(IBStream* state) const
|
|||
if (!s.writeInt32(preloadSize))
|
||||
return kResultFalse;
|
||||
|
||||
if (!s.writeStr8(scalaFile.c_str()))
|
||||
return kResultFalse;
|
||||
|
||||
if (!s.writeInt32(scalaRootKey))
|
||||
return kResultFalse;
|
||||
|
||||
if (!s.writeFloat(tuningFrequency))
|
||||
return kResultFalse;
|
||||
|
||||
if (!s.writeFloat(stretchedTuning))
|
||||
return kResultFalse;
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
constexpr uint64 SfizzVstState::currentStateVersion;
|
||||
|
||||
tresult SfizzUiState::load(IBStream* state)
|
||||
{
|
||||
IBStreamer s(state, kLittleEndian);
|
||||
|
|
@ -73,6 +114,9 @@ tresult SfizzUiState::load(IBStream* state)
|
|||
if (!s.readInt32u(activePanel))
|
||||
return kResultFalse;
|
||||
|
||||
if (version > 0)
|
||||
return kResultFalse;
|
||||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
|
|
@ -88,3 +132,5 @@ tresult SfizzUiState::store(IBStream* state) const
|
|||
|
||||
return kResultTrue;
|
||||
}
|
||||
|
||||
constexpr uint64 SfizzUiState::currentStateVersion;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ enum {
|
|||
kPidNumVoices,
|
||||
kPidOversampling,
|
||||
kPidPreloadSize,
|
||||
kPidScalaRootKey,
|
||||
kPidTuningFrequency,
|
||||
kPidStretchedTuning,
|
||||
kPidMidiAftertouch,
|
||||
kPidMidiPitchBend,
|
||||
kPidMidiCC0,
|
||||
|
|
@ -31,15 +34,19 @@ enum {
|
|||
|
||||
class SfizzVstState {
|
||||
public:
|
||||
SfizzVstState() { sfzFile.reserve(8192); }
|
||||
SfizzVstState() { sfzFile.reserve(8192); scalaFile.reserve(8192); }
|
||||
|
||||
std::string sfzFile;
|
||||
float volume = 0;
|
||||
int32 numVoices = 64;
|
||||
int32 oversamplingLog2 = 0;
|
||||
int32 preloadSize = 8192;
|
||||
std::string scalaFile;
|
||||
int32 scalaRootKey = 60;
|
||||
float tuningFrequency = 440.0;
|
||||
float stretchedTuning = 0.0;
|
||||
|
||||
static constexpr uint64 currentStateVersion = 0;
|
||||
static constexpr uint64 currentStateVersion = 1;
|
||||
|
||||
tresult load(IBStream* state);
|
||||
tresult store(IBStream* state) const;
|
||||
|
|
@ -83,3 +90,6 @@ static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0);
|
|||
static constexpr SfizzParameterRange kParamNumVoicesRange(256.0, 1.0, 512.0);
|
||||
static constexpr SfizzParameterRange kParamOversamplingRange(0.0, 0.0, 3.0);
|
||||
static constexpr SfizzParameterRange kParamPreloadSizeRange(8192.0, 1024.0, 65536.0);
|
||||
static constexpr SfizzParameterRange kParamScalaRootKey(60.0, 0.0, 127.0);
|
||||
static constexpr SfizzParameterRange kParamTuningFrequency(440.0, 300.0, 500.0);
|
||||
static constexpr SfizzParameterRange kParamStretchedTuning(0.0, 0.0, 1.0);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue